Enable lock for Vector to protect wasm-c-api read/write/extend operations (#1010)

This commit is contained in:
liang.he 2022-03-23 11:42:57 +08:00 committed by GitHub
parent e7079eeb17
commit 86b79cfb93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 198 additions and 121 deletions

View File

@ -3025,7 +3025,8 @@ aot_dump_call_stack(WASMExecEnv *exec_env)
/* release previous stack frames and create new ones */ /* release previous stack frames and create new ones */
if (!bh_vector_destroy(module_inst->frames.ptr) if (!bh_vector_destroy(module_inst->frames.ptr)
|| !bh_vector_init(module_inst->frames.ptr, n, sizeof(WASMCApiFrame))) { || !bh_vector_init(module_inst->frames.ptr, n, sizeof(WASMCApiFrame),
false)) {
return; return;
} }

View File

@ -109,113 +109,115 @@ failed: \
} }
/* vectors with no ownership management of elements */ /* vectors with no ownership management of elements */
#define WASM_DEFINE_VEC_PLAIN(name) \ #define WASM_DEFINE_VEC_PLAIN(name) \
WASM_DEFINE_VEC(name) \ WASM_DEFINE_VEC(name) \
void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \
own wasm_##name##_t const data[]) \ own wasm_##name##_t const data[]) \
{ \ { \
if (!out) { \ if (!out) { \
return; \ return; \
} \ } \
\ \
memset(out, 0, sizeof(wasm_##name##_vec_t)); \ memset(out, 0, sizeof(wasm_##name##_vec_t)); \
\ \
if (!size) { \ if (!size) { \
return; \ return; \
} \ } \
\ \
if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t))) { \ if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t), \
LOG_DEBUG("bh_vector_init failed"); \ true)) { \
goto failed; \ LOG_DEBUG("bh_vector_init failed"); \
} \ goto failed; \
\ } \
if (data) { \ \
uint32 size_in_bytes = 0; \ if (data) { \
size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t)); \ uint32 size_in_bytes = 0; \
bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t)); \
out->num_elems = size; \ bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \
} \ out->num_elems = size; \
\ } \
RETURN_VOID(out, wasm_##name##_vec_delete) \ \
} \ RETURN_VOID(out, wasm_##name##_vec_delete) \
void wasm_##name##_vec_copy(wasm_##name##_vec_t *out, \ } \
const wasm_##name##_vec_t *src) \ void wasm_##name##_vec_copy(wasm_##name##_vec_t *out, \
{ \ const wasm_##name##_vec_t *src) \
wasm_##name##_vec_new(out, src->size, src->data); \ { \
} \ wasm_##name##_vec_new(out, src->size, src->data); \
void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ } \
{ \ void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \
if (v) { \ { \
bh_vector_destroy((Vector *)v); \ if (v) { \
} \ bh_vector_destroy((Vector *)v); \
} \
} }
/* vectors that own their elements */ /* vectors that own their elements */
#define WASM_DEFINE_VEC_OWN(name, elem_destroy_func) \ #define WASM_DEFINE_VEC_OWN(name, elem_destroy_func) \
WASM_DEFINE_VEC(name) \ WASM_DEFINE_VEC(name) \
void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \ void wasm_##name##_vec_new(own wasm_##name##_vec_t *out, size_t size, \
own wasm_##name##_t *const data[]) \ own wasm_##name##_t *const data[]) \
{ \ { \
if (!out) { \ if (!out) { \
return; \ return; \
} \ } \
\ \
memset(out, 0, sizeof(wasm_##name##_vec_t)); \ memset(out, 0, sizeof(wasm_##name##_vec_t)); \
\ \
if (!size) { \ if (!size) { \
return; \ return; \
} \ } \
\ \
if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t *))) { \ if (!bh_vector_init((Vector *)out, size, sizeof(wasm_##name##_t *), \
LOG_DEBUG("bh_vector_init failed"); \ true)) { \
goto failed; \ LOG_DEBUG("bh_vector_init failed"); \
} \ goto failed; \
\ } \
if (data) { \ \
uint32 size_in_bytes = 0; \ if (data) { \
size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t *)); \ uint32 size_in_bytes = 0; \
bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \ size_in_bytes = (uint32)(size * sizeof(wasm_##name##_t *)); \
out->num_elems = size; \ bh_memcpy_s(out->data, size_in_bytes, data, size_in_bytes); \
} \ out->num_elems = size; \
\ } \
RETURN_VOID(out, wasm_##name##_vec_delete) \ \
} \ RETURN_VOID(out, wasm_##name##_vec_delete) \
void wasm_##name##_vec_copy(own wasm_##name##_vec_t *out, \ } \
const wasm_##name##_vec_t *src) \ void wasm_##name##_vec_copy(own wasm_##name##_vec_t *out, \
{ \ const wasm_##name##_vec_t *src) \
size_t i = 0; \ { \
memset(out, 0, sizeof(Vector)); \ size_t i = 0; \
\ memset(out, 0, sizeof(Vector)); \
if (!src || !src->size) { \ \
return; \ if (!src || !src->size) { \
} \ return; \
\ } \
if (!bh_vector_init((Vector *)out, src->size, \ \
sizeof(wasm_##name##_t *))) { \ if (!bh_vector_init((Vector *)out, src->size, \
LOG_DEBUG("bh_vector_init failed"); \ sizeof(wasm_##name##_t *), true)) { \
goto failed; \ LOG_DEBUG("bh_vector_init failed"); \
} \ goto failed; \
\ } \
for (i = 0; i != src->num_elems; ++i) { \ \
if (!(out->data[i] = wasm_##name##_copy(src->data[i]))) { \ for (i = 0; i != src->num_elems; ++i) { \
LOG_DEBUG("wasm_%s_copy failed", #name); \ if (!(out->data[i] = wasm_##name##_copy(src->data[i]))) { \
goto failed; \ LOG_DEBUG("wasm_%s_copy failed", #name); \
} \ goto failed; \
} \ } \
out->num_elems = src->num_elems; \ } \
\ out->num_elems = src->num_elems; \
RETURN_VOID(out, wasm_##name##_vec_delete) \ \
} \ RETURN_VOID(out, wasm_##name##_vec_delete) \
void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \ } \
{ \ void wasm_##name##_vec_delete(wasm_##name##_vec_t *v) \
size_t i = 0; \ { \
if (!v) { \ size_t i = 0; \
return; \ if (!v) { \
} \ return; \
for (i = 0; i != v->num_elems; ++i) { \ } \
elem_destroy_func(*(v->data + i)); \ for (i = 0; i != v->num_elems; ++i) { \
} \ elem_destroy_func(*(v->data + i)); \
bh_vector_destroy((Vector *)v); \ } \
bh_vector_destroy((Vector *)v); \
} }
WASM_DEFINE_VEC_PLAIN(byte) WASM_DEFINE_VEC_PLAIN(byte)
@ -377,7 +379,7 @@ wasm_store_new(wasm_engine_t *engine)
DEFAULT_VECTOR_INIT_LENGTH); DEFAULT_VECTOR_INIT_LENGTH);
if (!(store->foreigns = malloc_internal(sizeof(Vector))) if (!(store->foreigns = malloc_internal(sizeof(Vector)))
|| !(bh_vector_init(store->foreigns, 24, sizeof(Vector *)))) { || !(bh_vector_init(store->foreigns, 24, sizeof(Vector *), true))) {
goto failed; goto failed;
} }

View File

@ -88,6 +88,7 @@ typedef double float64_t;
wasm_##name##_t ptr_or_none* data; \ wasm_##name##_t ptr_or_none* data; \
size_t num_elems; \ size_t num_elems; \
size_t size_of_elem; \ size_t size_of_elem; \
void *lock; \
} wasm_##name##_vec_t; \ } wasm_##name##_vec_t; \
\ \
WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \ WASM_API_EXTERN void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out); \
@ -589,8 +590,8 @@ WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_exte
// Vectors // Vectors
#define WASM_EMPTY_VEC {0, NULL, 0, 0} #define WASM_EMPTY_VEC {0, NULL, 0, 0, NULL}
#define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array, sizeof(array)/sizeof(*(array)), sizeof(*(array))} #define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array, sizeof(array)/sizeof(*(array)), sizeof(*(array)), NULL}
// Value Type construction short-hands // Value Type construction short-hands

View File

@ -2504,7 +2504,8 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
/* release previous stack frames and create new ones */ /* release previous stack frames and create new ones */
if (!bh_vector_destroy(module_inst->frames) if (!bh_vector_destroy(module_inst->frames)
|| !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame))) { || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame),
false)) {
return; return;
} }

View File

@ -38,15 +38,21 @@ extend_vector(Vector *vector, size_t length)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(data, vector->data, vector->size_elem * vector->max_elems); memcpy(data, vector->data, vector->size_elem * vector->max_elems);
BH_FREE(vector->data); BH_FREE(vector->data);
vector->data = data; vector->data = data;
vector->max_elems = length; vector->max_elems = length;
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
bool bool
bh_vector_init(Vector *vector, size_t init_length, size_t size_elem) bh_vector_init(Vector *vector, size_t init_length, size_t size_elem,
bool use_lock)
{ {
if (!vector) { if (!vector) {
LOG_ERROR("Init vector failed: vector is NULL.\n"); LOG_ERROR("Init vector failed: vector is NULL.\n");
@ -65,6 +71,26 @@ bh_vector_init(Vector *vector, size_t init_length, size_t size_elem)
vector->size_elem = size_elem; vector->size_elem = size_elem;
vector->max_elems = init_length; vector->max_elems = init_length;
vector->num_elems = 0; vector->num_elems = 0;
vector->lock = NULL;
if (use_lock) {
if (!(vector->lock = wasm_runtime_malloc(sizeof(korp_mutex)))) {
LOG_ERROR("Init vector failed: alloc locker failed.\n");
bh_vector_destroy(vector);
return false;
}
if (BHT_OK != os_mutex_init(vector->lock)) {
LOG_ERROR("Init vector failed: init locker failed.\n");
wasm_runtime_free(vector->lock);
vector->lock = NULL;
bh_vector_destroy(vector);
return false;
}
}
return true; return true;
} }
@ -81,13 +107,17 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(vector->data + vector->size_elem * index, elem_buf, memcpy(vector->data + vector->size_elem * index, elem_buf,
vector->size_elem); vector->size_elem);
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
bool bool
bh_vector_get(const Vector *vector, uint32 index, void *elem_buf) bh_vector_get(Vector *vector, uint32 index, void *elem_buf)
{ {
if (!vector || !elem_buf) { if (!vector || !elem_buf) {
LOG_ERROR("Get vector elem failed: vector or elem buf is NULL.\n"); LOG_ERROR("Get vector elem failed: vector or elem buf is NULL.\n");
@ -99,8 +129,12 @@ bh_vector_get(const Vector *vector, uint32 index, void *elem_buf)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(elem_buf, vector->data + vector->size_elem * index, memcpy(elem_buf, vector->data + vector->size_elem * index,
vector->size_elem); vector->size_elem);
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
@ -125,6 +159,8 @@ bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
p = vector->data + vector->size_elem * vector->num_elems; p = vector->data + vector->size_elem * vector->num_elems;
for (i = vector->num_elems - 1; i > index; i--) { for (i = vector->num_elems - 1; i > index; i--) {
memcpy(p, p - vector->size_elem, vector->size_elem); memcpy(p, p - vector->size_elem, vector->size_elem);
@ -133,6 +169,8 @@ bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
memcpy(p, elem_buf, vector->size_elem); memcpy(p, elem_buf, vector->size_elem);
vector->num_elems++; vector->num_elems++;
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
@ -149,9 +187,13 @@ bh_vector_append(Vector *vector, const void *elem_buf)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf, memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf,
vector->size_elem); vector->size_elem);
vector->num_elems++; vector->num_elems++;
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
@ -171,6 +213,8 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
return false; return false;
} }
if (vector->lock)
os_mutex_lock(vector->lock);
p = vector->data + vector->size_elem * index; p = vector->data + vector->size_elem * index;
if (old_elem_buf) { if (old_elem_buf) {
@ -183,6 +227,8 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
} }
vector->num_elems--; vector->num_elems--;
if (vector->lock)
os_mutex_unlock(vector->lock);
return true; return true;
} }
@ -202,6 +248,12 @@ bh_vector_destroy(Vector *vector)
if (vector->data) if (vector->data)
BH_FREE(vector->data); BH_FREE(vector->data);
if (vector->lock) {
os_mutex_destroy(vector->lock);
wasm_runtime_free(vector->lock);
}
memset(vector, 0, sizeof(Vector)); memset(vector, 0, sizeof(Vector));
return true; return true;
} }

View File

@ -23,6 +23,7 @@ typedef struct Vector {
size_t num_elems; size_t num_elems;
/* size of each element */ /* size of each element */
size_t size_elem; size_t size_elem;
void *lock;
} Vector; } Vector;
/** /**
@ -35,7 +36,8 @@ typedef struct Vector {
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
bool bool
bh_vector_init(Vector *vector, size_t init_length, size_t size_elem); bh_vector_init(Vector *vector, size_t init_length, size_t size_elem,
bool use_lock);
/** /**
* Set element of vector * Set element of vector
@ -60,7 +62,7 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf);
* @return true if success, false otherwise * @return true if success, false otherwise
*/ */
bool bool
bh_vector_get(const Vector *vector, uint32 index, void *elem_buf); bh_vector_get(Vector *vector, uint32 index, void *elem_buf);
/** /**
* Insert element of vector * Insert element of vector

View File

@ -3,24 +3,42 @@
All samples come from the commit 340fd9528cc3b26d22fe30ee1628c8c3f2b8c53b All samples come from the commit 340fd9528cc3b26d22fe30ee1628c8c3f2b8c53b
of [wasm-c-api](https://github.com/WebAssembly/wasm-c-api). of [wasm-c-api](https://github.com/WebAssembly/wasm-c-api).
Developer can learn these *APIs* from Developer can learn these _APIs_ from
[wasm.h](https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.h). [wasm.h](https://github.com/WebAssembly/wasm-c-api/blob/master/include/wasm.h).
And here are [examples](https://github.com/WebAssembly/wasm-c-api/tree/master/example) which And here are [examples](https://github.com/WebAssembly/wasm-c-api/tree/master/example) which
are helpful. are helpful.
## FYI
- The thread model of _wasm_c_api_ is
- An `wasm_engine_t` instance may only be created once per process
- Every `wasm_store_t` and its objects may only be accessed in a single thread
- `wasm_engine_new`, `wasm_engine_new_with_config`, `wasm_engine_new_with_args`,
`wasm_engine_delete`should be called in a thread-safe environment. Such
behaviors are not recommended, and please make sure an appropriate calling
sequence if it has to be.
- call `wasm_engine_new` and `wasm_engine_delete` in different threads
- call `wasm_engine_new` or `wasm_engine_delete` multiple times in
different threads
## unspported list
Currently WAMR supports most of the APIs, the unsupported APIs are listed as below: Currently WAMR supports most of the APIs, the unsupported APIs are listed as below:
- References - References
``` c ```c
WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*);
WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*);
``` ```
- Several Module APIs - Several Module APIs
``` c ```c
WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out);
WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*);
``` ```
@ -30,12 +48,12 @@ by host-side function callings.
- Table Grow APIs - Table Grow APIs
``` c ```c
WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init);
``` ```
- Memory Grow APIs - Memory Grow APIs
``` c ```c
WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta);
``` ```

View File

@ -34,7 +34,7 @@ void check(bool success) {
void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) {
wasm_val_t r[] = {WASM_INIT_VAL}; wasm_val_t r[] = {WASM_INIT_VAL};
wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t), NULL};
wasm_val_vec_t results = WASM_ARRAY_VEC(r); wasm_val_vec_t results = WASM_ARRAY_VEC(r);
if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) { if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) {
printf("> Error on result\n"); printf("> Error on result\n");
@ -57,7 +57,7 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected
} }
void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) {
wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t), NULL};
wasm_val_vec_t results = WASM_EMPTY_VEC; wasm_val_vec_t results = WASM_EMPTY_VEC;
if (wasm_func_call(func, &args_, &results)) { if (wasm_func_call(func, &args_, &results)) {
printf("> Error on result, expected empty\n"); printf("> Error on result, expected empty\n");
@ -72,7 +72,7 @@ void check_ok2(wasm_func_t* func, int32_t arg1, int32_t arg2) {
void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) { void check_trap(wasm_func_t* func, int i, wasm_val_t args[]) {
wasm_val_t r[] = {WASM_INIT_VAL}; wasm_val_t r[] = {WASM_INIT_VAL};
wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t)}; wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t), NULL};
wasm_val_vec_t results = WASM_ARRAY_VEC(r); wasm_val_vec_t results = WASM_ARRAY_VEC(r);
own wasm_trap_t* trap = wasm_func_call(func, &args_, &results); own wasm_trap_t* trap = wasm_func_call(func, &args_, &results);
if (! trap) { if (! trap) {