Răsfoiți Sursa

Implement `wasm_externref_objdel` and `wasm_externref_set_cleanup` (#2455)

## Context

Some native libraries may want to explicitly delete an externref object without
waiting for the module instance to be deleted.
In addition, it may want to add a cleanup function.

## Proposed Changes

Implement:
* `wasm_externref_objdel` to explicitly delete an externeref'd object. 
* `wasm_externref_set_cleanup` to set a cleanup function that is called when
  the externref'd object is deleted.
tonibofarull 2 ani în urmă
părinte
comite
8d1cf46f02
2 a modificat fișierele cu 106 adăugiri și 4 ștergeri
  1. 80 4
      core/iwasm/common/wasm_runtime_common.c
  2. 26 0
      core/iwasm/include/wasm_export.h

+ 80 - 4
core/iwasm/common/wasm_runtime_common.c

@@ -4681,6 +4681,8 @@ typedef struct ExternRefMapNode {
     bool retained;
     /* Whether it is marked by runtime */
     bool marked;
+    /* cleanup function called when the externref is freed */
+    void (*cleanup)(void *);
 } ExternRefMapNode;
 
 static uint32
@@ -4743,6 +4745,81 @@ lookup_extobj_callback(void *key, void *value, void *user_data)
     }
 }
 
+static void
+delete_externref(void *key, ExternRefMapNode *node)
+{
+    bh_hash_map_remove(externref_map, key, NULL, NULL);
+    if (node->cleanup) {
+        (*node->cleanup)(node->extern_obj);
+    }
+    wasm_runtime_free(node);
+}
+
+static void
+delete_extobj_callback(void *key, void *value, void *user_data)
+{
+    ExternRefMapNode *node = (ExternRefMapNode *)value;
+    LookupExtObj_UserData *lookup_user_data =
+        (LookupExtObj_UserData *)user_data;
+
+    if (node->extern_obj == lookup_user_data->node.extern_obj
+        && node->module_inst == lookup_user_data->node.module_inst) {
+        lookup_user_data->found = true;
+        delete_externref(key, node);
+    }
+}
+
+bool
+wasm_externref_objdel(WASMModuleInstanceCommon *module_inst, void *extern_obj)
+{
+    LookupExtObj_UserData lookup_user_data = { 0 };
+    bool ok = false;
+
+    /* in a wrapper, extern_obj could be any value */
+    lookup_user_data.node.extern_obj = extern_obj;
+    lookup_user_data.node.module_inst = module_inst;
+    lookup_user_data.found = false;
+
+    os_mutex_lock(&externref_lock);
+    /* Lookup hashmap firstly */
+    bh_hash_map_traverse(externref_map, delete_extobj_callback,
+                         (void *)&lookup_user_data);
+    if (lookup_user_data.found) {
+        ok = true;
+    }
+    os_mutex_unlock(&externref_lock);
+
+    return ok;
+}
+
+bool
+wasm_externref_set_cleanup(WASMModuleInstanceCommon *module_inst,
+                           void *extern_obj, void (*extern_obj_cleanup)(void *))
+{
+
+    LookupExtObj_UserData lookup_user_data = { 0 };
+    bool ok = false;
+
+    /* in a wrapper, extern_obj could be any value */
+    lookup_user_data.node.extern_obj = extern_obj;
+    lookup_user_data.node.module_inst = module_inst;
+    lookup_user_data.found = false;
+
+    os_mutex_lock(&externref_lock);
+    /* Lookup hashmap firstly */
+    bh_hash_map_traverse(externref_map, lookup_extobj_callback,
+                         (void *)&lookup_user_data);
+    if (lookup_user_data.found) {
+        void *key = (void *)(uintptr_t)lookup_user_data.externref_idx;
+        ExternRefMapNode *node = bh_hash_map_find(externref_map, key);
+        node->cleanup = extern_obj_cleanup;
+        ok = true;
+    }
+    os_mutex_unlock(&externref_lock);
+
+    return ok;
+}
+
 bool
 wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
                        uint32 *p_externref_idx)
@@ -4792,6 +4869,7 @@ wasm_externref_obj2ref(WASMModuleInstanceCommon *module_inst, void *extern_obj,
     memset(node, 0, sizeof(ExternRefMapNode));
     node->extern_obj = extern_obj;
     node->module_inst = module_inst;
+    node->cleanup = NULL;
 
     externref_idx = externref_global_id;
 
@@ -4842,8 +4920,7 @@ reclaim_extobj_callback(void *key, void *value, void *user_data)
 
     if (node->module_inst == module_inst) {
         if (!node->marked && !node->retained) {
-            bh_hash_map_remove(externref_map, key, NULL, NULL);
-            wasm_runtime_free(value);
+            delete_externref(key, node);
         }
         else {
             node->marked = false;
@@ -4958,8 +5035,7 @@ cleanup_extobj_callback(void *key, void *value, void *user_data)
         (WASMModuleInstanceCommon *)user_data;
 
     if (node->module_inst == module_inst) {
-        bh_hash_map_remove(externref_map, key, NULL, NULL);
-        wasm_runtime_free(value);
+        delete_externref(key, node);
     }
 }
 

+ 26 - 0
core/iwasm/include/wasm_export.h

@@ -1292,6 +1292,32 @@ WASM_RUNTIME_API_EXTERN bool
 wasm_externref_obj2ref(wasm_module_inst_t module_inst,
                        void *extern_obj, uint32_t *p_externref_idx);
 
+/**
+ * Delete external object registered by `wasm_externref_obj2ref`.
+ *
+ * @param module_inst the WASM module instance that the extern object
+ *        belongs to
+ * @param extern_obj the external object to be deleted
+ *
+ * @return true if success, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_externref_objdel(wasm_module_inst_t module_inst, void *extern_obj);
+
+/**
+ * Set cleanup callback to release external object.
+ *
+ * @param module_inst the WASM module instance that the extern object
+ *        belongs to
+ * @param extern_obj the external object to which to set the `extern_obj_cleanup` cleanup callback.
+ * @param extern_obj_cleanup a callback to release `extern_obj`
+ *
+ * @return true if success, false otherwise
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_externref_set_cleanup(wasm_module_inst_t module_inst, void *extern_obj,
+                           void (*extern_obj_cleanup)(void *));
+
 /**
  * Retrieve the external object from an internal externref index
  *