Skip to content

Commit 70c39ba

Browse files
authored
wasi-nn: fix context lifetime issues (#4396)
* wasi-nn: fix context lifetime issues use the module instance context api instead of trying to roll our own with a hashmap. this fixes context lifetime problems mentioned in #4313. namely, * wasi-nn resources will be freed earlier now. before this change, they used to be kept until the runtime shutdown. (wasm_runtime_destroy) after this change, they will be freed together with the associated instances. * wasm_module_inst_t pointer uniqueness assumption (which is wrong after wasm_runtime_deinstantiate) was lifted. as a side effect, this change also makes a context shared among threads within a cluster. note that this is a user-visible api/abi breaking change. before this change, wasi-nn "handles" like wasi_ephemeral_nn_graph were thread-local. after this change, they are shared among threads within a cluster, similarly to wasi file descriptors. spec-wise, either behavior should be ok simply because wasi officially doesn't have threads yet. althogh i feel the latter semantics is more intuitive, if your application depends on the thread-local behavior, this change breaks your application. tested with wamr-wasi-extensions/samples/nn-cli, modified to call each wasi-nn operations on different threads. (if you are interested, you can find the modification at https://github.com/yamt/wasm-micro-runtime/tree/yamt-nn-wip-20250619.) cf. #4313 #2430 * runtime_lib.cmake: enable WAMR_BUILD_MODULE_INST_CONTEXT for wasi-nn as we do for wasi (WAMR_BUILD_LIBC_WASI)
1 parent 92e5f5f commit 70c39ba

File tree

2 files changed

+22
-57
lines changed

2 files changed

+22
-57
lines changed

build-scripts/runtime_lib.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ endif ()
106106

107107
if (WAMR_BUILD_WASI_NN EQUAL 1)
108108
include (${IWASM_DIR}/libraries/wasi-nn/cmake/wasi_nn.cmake)
109+
set (WAMR_BUILD_MODULE_INST_CONTEXT 1)
109110
endif ()
110111

111112
if (WAMR_BUILD_LIB_PTHREAD EQUAL 1)

core/iwasm/libraries/wasi-nn/src/wasi_nn.c

Lines changed: 21 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -55,49 +55,15 @@ struct backends_api_functions {
5555
NN_ERR_PRINTF("Error %s() -> %d", #func, wasi_error); \
5656
} while (0)
5757

58-
/* HashMap utils */
59-
static HashMap *hashmap;
60-
61-
static uint32
62-
hash_func(const void *key)
63-
{
64-
// fnv1a_hash
65-
const uint32 FNV_PRIME = 16777619;
66-
const uint32 FNV_OFFSET_BASIS = 2166136261U;
67-
68-
uint32 hash = FNV_OFFSET_BASIS;
69-
const unsigned char *bytes = (const unsigned char *)key;
70-
71-
for (size_t i = 0; i < sizeof(uintptr_t); ++i) {
72-
hash ^= bytes[i];
73-
hash *= FNV_PRIME;
74-
}
75-
76-
return hash;
77-
}
78-
79-
static bool
80-
key_equal_func(void *key1, void *key2)
81-
{
82-
return key1 == key2;
83-
}
84-
85-
static void
86-
key_destroy_func(void *key1)
87-
{
88-
/* key type is wasm_module_inst_t*. do nothing */
89-
}
58+
static void *wasi_nn_key;
9059

9160
static void
9261
wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx)
9362
{
94-
NN_DBG_PRINTF("[WASI NN] DEINIT...");
95-
9663
if (wasi_nn_ctx == NULL) {
97-
NN_ERR_PRINTF(
98-
"Error when deallocating memory. WASI-NN context is NULL");
9964
return;
10065
}
66+
NN_DBG_PRINTF("[WASI NN] DEINIT...");
10167
NN_DBG_PRINTF("Freeing wasi-nn");
10268
NN_DBG_PRINTF("-> is_model_loaded: %d", wasi_nn_ctx->is_model_loaded);
10369
NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->backend);
@@ -116,9 +82,9 @@ wasi_nn_ctx_destroy(WASINNContext *wasi_nn_ctx)
11682
}
11783

11884
static void
119-
value_destroy_func(void *value)
85+
dtor(wasm_module_inst_t inst, void *ctx)
12086
{
121-
wasi_nn_ctx_destroy((WASINNContext *)value);
87+
wasi_nn_ctx_destroy(ctx);
12288
}
12389

12490
bool
@@ -131,12 +97,9 @@ wasi_nn_initialize()
13197
return false;
13298
}
13399

134-
// hashmap { instance: wasi_nn_ctx }
135-
hashmap = bh_hash_map_create(HASHMAP_INITIAL_SIZE, true, hash_func,
136-
key_equal_func, key_destroy_func,
137-
value_destroy_func);
138-
if (hashmap == NULL) {
139-
NN_ERR_PRINTF("Error while initializing hashmap");
100+
wasi_nn_key = wasm_runtime_create_context_key(dtor);
101+
if (wasi_nn_key == NULL) {
102+
NN_ERR_PRINTF("Failed to create context key");
140103
os_mutex_destroy(&wasi_nn_lock);
141104
return false;
142105
}
@@ -170,21 +133,23 @@ static WASINNContext *
170133
wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance)
171134
{
172135
WASINNContext *wasi_nn_ctx =
173-
(WASINNContext *)bh_hash_map_find(hashmap, (void *)instance);
136+
wasm_runtime_get_context(instance, wasi_nn_key);
174137
if (wasi_nn_ctx == NULL) {
175-
wasi_nn_ctx = wasi_nn_initialize_context();
176-
if (wasi_nn_ctx == NULL)
177-
return NULL;
178-
179-
bool ok =
180-
bh_hash_map_insert(hashmap, (void *)instance, (void *)wasi_nn_ctx);
181-
if (!ok) {
182-
NN_ERR_PRINTF("Error while storing context");
183-
wasi_nn_ctx_destroy(wasi_nn_ctx);
138+
WASINNContext *newctx = wasi_nn_initialize_context();
139+
if (newctx == NULL)
184140
return NULL;
141+
os_mutex_lock(&wasi_nn_lock);
142+
wasi_nn_ctx = wasm_runtime_get_context(instance, wasi_nn_key);
143+
if (wasi_nn_ctx == NULL) {
144+
wasm_runtime_set_context_spread(instance, wasi_nn_key, newctx);
145+
wasi_nn_ctx = newctx;
146+
newctx = NULL;
147+
}
148+
os_mutex_unlock(&wasi_nn_lock);
149+
if (newctx != NULL) {
150+
wasi_nn_ctx_destroy(newctx);
185151
}
186152
}
187-
188153
return wasi_nn_ctx;
189154
}
190155

@@ -220,8 +185,7 @@ unlock_ctx(WASINNContext *wasi_nn_ctx)
220185
void
221186
wasi_nn_destroy()
222187
{
223-
// destroy hashmap will destroy keys and values
224-
bh_hash_map_destroy(hashmap);
188+
wasm_runtime_destroy_context_key(wasi_nn_key);
225189

226190
// close backends' libraries and registered functions
227191
for (unsigned i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++) {

0 commit comments

Comments
 (0)