Просмотр исходного кода

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

liang.he 3 лет назад
Родитель
Сommit
86b79cfb93

+ 2 - 1
core/iwasm/aot/aot_runtime.c

@@ -3025,7 +3025,8 @@ aot_dump_call_stack(WASMExecEnv *exec_env)
 
     /* release previous stack frames and create new ones */
     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;
     }
 

+ 107 - 105
core/iwasm/common/wasm_c_api.c

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

+ 3 - 2
core/iwasm/include/wasm_c_api.h

@@ -88,6 +88,7 @@ typedef double float64_t;
     wasm_##name##_t ptr_or_none* data; \
     size_t num_elems; \
     size_t size_of_elem; \
+    void *lock; \
   } wasm_##name##_vec_t; \
   \
   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
 
-#define WASM_EMPTY_VEC {0, NULL, 0, 0}
-#define WASM_ARRAY_VEC(array) {sizeof(array)/sizeof(*(array)), array, sizeof(array)/sizeof(*(array)), sizeof(*(array))}
+#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)), NULL}
 
 
 // Value Type construction short-hands

+ 2 - 1
core/iwasm/interpreter/wasm_runtime.c

@@ -2504,7 +2504,8 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
 
     /* release previous stack frames and create new ones */
     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;
     }
 

+ 54 - 2
core/shared/utils/bh_vector.c

@@ -38,15 +38,21 @@ extend_vector(Vector *vector, size_t length)
         return false;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     memcpy(data, vector->data, vector->size_elem * vector->max_elems);
     BH_FREE(vector->data);
+
     vector->data = data;
     vector->max_elems = length;
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
 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) {
         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->max_elems = init_length;
     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;
 }
 
@@ -81,13 +107,17 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf)
         return false;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     memcpy(vector->data + vector->size_elem * index, elem_buf,
            vector->size_elem);
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
 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) {
         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;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     memcpy(elem_buf, vector->data + vector->size_elem * index,
            vector->size_elem);
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
@@ -125,6 +159,8 @@ bh_vector_insert(Vector *vector, uint32 index, const void *elem_buf)
         return false;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     p = vector->data + vector->size_elem * vector->num_elems;
     for (i = vector->num_elems - 1; i > index; i--) {
         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);
     vector->num_elems++;
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
@@ -149,9 +187,13 @@ bh_vector_append(Vector *vector, const void *elem_buf)
         return false;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     memcpy(vector->data + vector->size_elem * vector->num_elems, elem_buf,
            vector->size_elem);
     vector->num_elems++;
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
@@ -171,6 +213,8 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
         return false;
     }
 
+    if (vector->lock)
+        os_mutex_lock(vector->lock);
     p = vector->data + vector->size_elem * index;
 
     if (old_elem_buf) {
@@ -183,6 +227,8 @@ bh_vector_remove(Vector *vector, uint32 index, void *old_elem_buf)
     }
 
     vector->num_elems--;
+    if (vector->lock)
+        os_mutex_unlock(vector->lock);
     return true;
 }
 
@@ -202,6 +248,12 @@ bh_vector_destroy(Vector *vector)
 
     if (vector->data)
         BH_FREE(vector->data);
+
+    if (vector->lock) {
+        os_mutex_destroy(vector->lock);
+        wasm_runtime_free(vector->lock);
+    }
+
     memset(vector, 0, sizeof(Vector));
     return true;
 }

+ 4 - 2
core/shared/utils/bh_vector.h

@@ -23,6 +23,7 @@ typedef struct Vector {
     size_t num_elems;
     /* size of each element */
     size_t size_elem;
+    void *lock;
 } Vector;
 
 /**
@@ -35,7 +36,8 @@ typedef struct Vector {
  * @return true if success, false otherwise
  */
 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
@@ -60,7 +62,7 @@ bh_vector_set(Vector *vector, uint32 index, const void *elem_buf);
  * @return true if success, false otherwise
  */
 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

+ 23 - 5
doc/wasm_c_api.md

@@ -3,24 +3,42 @@
 All samples come from the commit 340fd9528cc3b26d22fe30ee1628c8c3f2b8c53b
 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).
 
 And here are [examples](https://github.com/WebAssembly/wasm-c-api/tree/master/example) which
 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:
 
 - References
 
-``` c
+```c
 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*);
 ```
 
 - 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 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
 
-``` c
+```c
 WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init);
 ```
 
 - Memory Grow APIs
 
-``` c
+```c
 WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta);
 ```

+ 3 - 3
samples/wasm-c-api/src/memory.c

@@ -34,7 +34,7 @@ void check(bool success) {
 
 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_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);
   if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) {
     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[]) {
-  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;
   if (wasm_func_call(func, &args_, &results)) {
     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[]) {
   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);
   own wasm_trap_t* trap = wasm_func_call(func, &args_, &results);
   if (! trap) {