Skip to content

Commit 4e5529f

Browse files
authored
Reserve TID values for WASI threads (#1862)
According to the [WASI thread specification](WebAssembly/wasi-threads#16), some thread identifiers are reserved and should not be used. In fact, only IDs between `1` and `0x1FFFFFFF` are valid. The thread ID allocator has been moved to a separate class to avoid polluting the `lib_wasi_threads_wrapper` logic.
1 parent 3403f0a commit 4e5529f

File tree

4 files changed

+125
-58
lines changed

4 files changed

+125
-58
lines changed

core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ add_definitions (-DWASM_ENABLE_LIB_WASI_THREADS=1 -DWASM_ENABLE_HEAP_AUX_STACK_A
88
include_directories(${LIB_WASI_THREADS_DIR})
99

1010
set (LIB_WASI_THREADS_SOURCE
11-
${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c)
11+
${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c
12+
${LIB_WASI_THREADS_DIR}/tid_allocator.c)

core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c

Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include "bh_log.h"
77
#include "thread_manager.h"
8+
#include "tid_allocator.h"
89

910
#if WASM_ENABLE_INTERP != 0
1011
#include "wasm_runtime.h"
@@ -15,16 +16,8 @@
1516
#endif
1617

1718
static const char *THREAD_START_FUNCTION = "wasi_thread_start";
18-
1919
static korp_mutex thread_id_lock;
20-
21-
// Stack data structure to track available thread identifiers
22-
#define AVAIL_TIDS_INIT_SIZE CLUSTER_MAX_THREAD_NUM
23-
typedef struct {
24-
int32 *ids;
25-
uint32 pos, size;
26-
} AvailableThreadIds;
27-
static AvailableThreadIds avail_tids;
20+
static TidAllocator tid_allocator;
2821

2922
typedef struct {
3023
/* app's entry function */
@@ -38,53 +31,18 @@ typedef struct {
3831
static int32
3932
allocate_thread_id()
4033
{
41-
int32 id = -1;
42-
4334
os_mutex_lock(&thread_id_lock);
44-
if (avail_tids.pos == 0) { // Resize stack and push new thread ids
45-
uint32 old_size = avail_tids.size;
46-
uint32 new_size = avail_tids.size * 2;
47-
if (new_size / 2 != avail_tids.size) {
48-
LOG_ERROR("Overflow detected during new size calculation");
49-
goto return_id;
50-
}
51-
52-
size_t realloc_size = new_size * sizeof(int32);
53-
if (realloc_size / sizeof(int32) != new_size) {
54-
LOG_ERROR("Overflow detected during realloc");
55-
goto return_id;
56-
}
57-
int32 *tmp =
58-
(int32 *)wasm_runtime_realloc(avail_tids.ids, realloc_size);
59-
if (tmp == NULL) {
60-
LOG_ERROR("Thread ID allocator realloc failed");
61-
goto return_id;
62-
}
63-
64-
avail_tids.size = new_size;
65-
avail_tids.pos = old_size;
66-
avail_tids.ids = tmp;
67-
for (uint32 i = 0; i < old_size; i++)
68-
avail_tids.ids[i] = new_size - i;
69-
}
70-
71-
// Pop available thread identifier from `avail_tids` stack
72-
id = avail_tids.ids[--avail_tids.pos];
73-
74-
return_id:
35+
int32 id = tid_allocator_get_tid(&tid_allocator);
7536
os_mutex_unlock(&thread_id_lock);
37+
7638
return id;
7739
}
7840

7941
void
8042
deallocate_thread_id(int32 thread_id)
8143
{
8244
os_mutex_lock(&thread_id_lock);
83-
84-
// Release thread identifier by pushing it into `avail_tids` stack
85-
bh_assert(avail_tids.pos < avail_tids.size);
86-
avail_tids.ids[avail_tids.pos++] = thread_id;
87-
45+
tid_allocator_release_tid(&tid_allocator, thread_id);
8846
os_mutex_unlock(&thread_id_lock);
8947
}
9048

@@ -212,25 +170,17 @@ lib_wasi_threads_init(void)
212170
if (0 != os_mutex_init(&thread_id_lock))
213171
return false;
214172

215-
// Initialize stack to store thread identifiers
216-
avail_tids.size = AVAIL_TIDS_INIT_SIZE;
217-
avail_tids.pos = avail_tids.size;
218-
avail_tids.ids =
219-
(int32 *)wasm_runtime_malloc(avail_tids.size * sizeof(int32));
220-
if (avail_tids.ids == NULL) {
173+
if (!tid_allocator_init(&tid_allocator)) {
221174
os_mutex_destroy(&thread_id_lock);
222175
return false;
223176
}
224-
for (uint32 i = 0; i < avail_tids.size; i++)
225-
avail_tids.ids[i] = avail_tids.size - i;
226177

227178
return true;
228179
}
229180

230181
void
231182
lib_wasi_threads_destroy(void)
232183
{
233-
wasm_runtime_free(avail_tids.ids);
234-
avail_tids.ids = NULL;
184+
tid_allocator_deinit(&tid_allocator);
235185
os_mutex_destroy(&thread_id_lock);
236186
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include "tid_allocator.h"
7+
#include "wasm_export.h"
8+
#include "bh_log.h"
9+
10+
bh_static_assert(TID_MIN <= TID_MAX);
11+
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
12+
13+
bool
14+
tid_allocator_init(TidAllocator *tid_allocator)
15+
{
16+
tid_allocator->size = MIN(TID_ALLOCATOR_INIT_SIZE, TID_MAX - TID_MIN + 1);
17+
tid_allocator->pos = tid_allocator->size;
18+
tid_allocator->ids =
19+
wasm_runtime_malloc(tid_allocator->size * sizeof(int32));
20+
if (tid_allocator->ids == NULL)
21+
return false;
22+
23+
for (int64 i = tid_allocator->pos - 1; i >= 0; i--)
24+
tid_allocator->ids[i] = TID_MIN + (tid_allocator->pos - 1 - i);
25+
26+
return true;
27+
}
28+
29+
void
30+
tid_allocator_deinit(TidAllocator *tid_allocator)
31+
{
32+
wasm_runtime_free(tid_allocator->ids);
33+
}
34+
35+
int32
36+
tid_allocator_get_tid(TidAllocator *tid_allocator)
37+
{
38+
if (tid_allocator->pos == 0) { // Resize stack and push new thread ids
39+
if (tid_allocator->size == TID_MAX - TID_MIN + 1) {
40+
LOG_ERROR("Maximum thread identifier reached");
41+
return -1;
42+
}
43+
44+
uint32 old_size = tid_allocator->size;
45+
uint32 new_size = MIN(tid_allocator->size * 2, TID_MAX - TID_MIN + 1);
46+
if (new_size != TID_MAX - TID_MIN + 1
47+
&& new_size / 2 != tid_allocator->size) {
48+
LOG_ERROR("Overflow detected during new size calculation");
49+
return -1;
50+
}
51+
52+
size_t realloc_size = new_size * sizeof(int32);
53+
if (realloc_size / sizeof(int32) != new_size) {
54+
LOG_ERROR("Overflow detected during realloc");
55+
return -1;
56+
}
57+
int32 *tmp = wasm_runtime_realloc(tid_allocator->ids, realloc_size);
58+
if (tmp == NULL) {
59+
LOG_ERROR("Thread ID allocator realloc failed");
60+
return -1;
61+
}
62+
63+
tid_allocator->size = new_size;
64+
tid_allocator->pos = new_size - old_size;
65+
tid_allocator->ids = tmp;
66+
for (int64 i = tid_allocator->pos - 1; i >= 0; i--)
67+
tid_allocator->ids[i] = TID_MIN + (tid_allocator->size - 1 - i);
68+
}
69+
70+
// Pop available thread identifier from the stack
71+
return tid_allocator->ids[--tid_allocator->pos];
72+
}
73+
74+
void
75+
tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id)
76+
{
77+
// Release thread identifier by pushing it into the stack
78+
bh_assert(tid_allocator->pos < tid_allocator->size);
79+
tid_allocator->ids[tid_allocator->pos++] = thread_id;
80+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#ifndef _TID_ALLOCATOR_H
7+
#define _TID_ALLOCATOR_H
8+
9+
#include "platform_common.h"
10+
11+
#define TID_ALLOCATOR_INIT_SIZE CLUSTER_MAX_THREAD_NUM
12+
enum {
13+
TID_MIN = 1,
14+
TID_MAX = 0x1FFFFFFF
15+
}; // Reserved TIDs (WASI specification)
16+
17+
/* Stack data structure to track available thread identifiers */
18+
typedef struct {
19+
int32 *ids; // Array used to store the stack
20+
uint32 size; // Stack capacity
21+
uint32 pos; // Index of the element after the stack top
22+
} TidAllocator;
23+
24+
bool
25+
tid_allocator_init(TidAllocator *tid_allocator);
26+
27+
void
28+
tid_allocator_deinit(TidAllocator *tid_allocator);
29+
30+
int32
31+
tid_allocator_get_tid(TidAllocator *tid_allocator);
32+
33+
void
34+
tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id);
35+
36+
#endif /* _TID_ALLOCATOR_H */

0 commit comments

Comments
 (0)