Skip to content

Commit 0d76edc

Browse files
committed
Fix several bugs in the new pthread/Wasm Worker hybrid mode
1. Include pthread metadata size when calcualting total space needed in emscripten_malloc_wasm_worker 2. Add missing allocation of space for `pthread struct` in init_pthread_struct. The effect of this was the TSD data and the pthread struct were overlapping in memory! 3. Zero out pthread struct and TSD slots.
1 parent f24ee6f commit 0d76edc

3 files changed

Lines changed: 45 additions & 18 deletions

File tree

system/lib/wasm_worker/library_wasm_worker.c

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,38 +70,56 @@ static void init_file_lock(FILE *f) {
7070
if (f && f->lock<0) f->lock = 0;
7171
}
7272

73+
static size_t max_alignment() {
74+
return MAX(__builtin_wasm_tls_align(), STACK_ALIGN);
75+
}
76+
7377
#ifdef __EMSCRIPTEN_PTHREADS__
74-
/* pthread_key_create.c overrides this */
78+
_Static_assert(STACK_ALIGN >= _Alignof(struct pthread));
79+
80+
/*
81+
* pthread_key_create.c overrides this, meaning we only allocate space for TSD
82+
* if needed by the program.
83+
*/
7584
static volatile size_t dummy = 0;
7685
weak_alias(dummy, __pthread_tsd_size);
7786

78-
#define TSD_ALIGN (sizeof(void*))
79-
8087
/**
8188
* The layout of the wasm worker stack space in hybrid mode is as follow.
82-
* [ struct pthread ] [ pthread TSD slots ] [ TLS data ] [ ... stack ]
89+
* [ struct pthread ] [ pthread TSD slots ] [ ... stack ] [ TLS data ]
8390
*
8491
* As opposed to the layout for regular Wasm Workers which is just:
85-
* [ TLS data ] [ ... stack ]
92+
* [ ... stack ] [ TLS data ]
93+
*
94+
* In either case these sections are all aligned to `max_alignment()`
95+
* which is the max alignment of any of the given chunks.
8696
*/
8797
static void* init_pthread_struct(void *stackPlusTLSAddress, pid_t tid, size_t* stackPlusTLSSize) {
8898
// TODO: Remove duplication with pthread_create
89-
9099
pthread_t self = pthread_self();
91-
pthread_t new = (pthread_t)stackPlusTLSAddress;
92100

93101
uintptr_t base = (uintptr_t)stackPlusTLSAddress;
94102
uintptr_t offset = base;
95103

96-
// 3. tsd slots
104+
size_t alignment = max_alignment();
105+
assert(base % alignment == 0);
106+
107+
// 1. struct pthread comes first
108+
pthread_t new = (pthread_t)offset;
109+
memset(new, 0, sizeof(struct pthread));
110+
offset += ROUND_UP(sizeof(struct pthread), alignment);
111+
112+
// 2. tsd slots
97113
if (__pthread_tsd_size) {
98-
offset = ROUND_UP(offset, TSD_ALIGN);
99114
new->tsd = (void*)offset;
100-
offset += __pthread_tsd_size;
115+
memset(new->tsd, 0, __pthread_tsd_size);
116+
offset += ROUND_UP(__pthread_tsd_size, alignment);
101117
}
102118

119+
// 3. Remaining space is for TLS data + stack, which is handled by
120+
// the wasm worker startup code.
121+
103122
// Calculate updated stack size
104-
offset = ROUND_UP(offset, STACK_ALIGN);
105123
size_t new_stack_size = *stackPlusTLSSize - (offset - base);
106124
assert(new_stack_size % STACK_ALIGN == 0);
107125
assert(new_stack_size > 0);
@@ -192,11 +210,17 @@ emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress
192210
}
193211

194212
emscripten_wasm_worker_t emscripten_malloc_wasm_worker(size_t stackSize) {
195-
// Add the TLS size to the provided stackSize so that the allocation
196-
// will always be large enough to hold the worker TLS data.
197-
stackSize += ROUND_UP(__builtin_wasm_tls_size(), STACK_ALIGN);
198-
void* stackPlusTLSAddress = emscripten_builtin_memalign(MAX(__builtin_wasm_tls_align(), STACK_ALIGN), stackSize);
199-
return emscripten_create_wasm_worker(stackPlusTLSAddress, stackSize);
213+
// Add the TLS size (and pthread metadata size) to the provided stackSize so
214+
// that the allocation will always be large enough.
215+
size_t alignment = max_alignment();
216+
size_t totalSize = stackSize + ROUND_UP(__builtin_wasm_tls_size(), alignment);
217+
#ifdef __EMSCRIPTEN_PTHREADS__
218+
totalSize += ROUND_UP(sizeof(struct pthread), alignment);
219+
totalSize += ROUND_UP(__pthread_tsd_size, alignment);
220+
#endif
221+
222+
void* address = emscripten_builtin_memalign(alignment, totalSize);
223+
return emscripten_create_wasm_worker(address, totalSize);
200224
}
201225

202226
void emscripten_wasm_worker_sleep(int64_t nsecs) {

test/wasm_worker/wasm_worker_and_pthread.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ void *thread_main(void *arg) {
8484
return 0;
8585
}
8686

87+
#define WW_STACK_SIZE 2048
88+
8789
void worker_main() {
8890
// Test self ID
8991
worker_tid = gettid();
@@ -129,6 +131,7 @@ void worker_main() {
129131
emscripten_outf("worker stack: stack_high=%#lx, stack_low=%#lx, size=%zu, local=%p", stack_high, stack_low, stack_size, &local_data);
130132
assert(stack_size > 0);
131133
assert(stack_addr != NULL);
134+
assert(stack_size >= WW_STACK_SIZE);
132135
assert((intptr_t)&local_data <= stack_high);
133136
assert((intptr_t)&local_data >= stack_low);
134137

@@ -153,6 +156,6 @@ int main() {
153156
pthread_create(&thread, NULL, thread_main, NULL);
154157
pthread_join(thread, NULL);
155158

156-
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */2048);
159+
emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(WW_STACK_SIZE);
157160
emscripten_wasm_worker_post_function_v(worker, worker_main);
158161
}

tools/system_libs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,7 @@ def __init__(self, **kwargs):
15521552
super().__init__(**kwargs)
15531553

15541554
def get_cflags(self):
1555-
cflags = super().get_cflags() + ['-sWASM_WORKERS']
1555+
cflags = super().get_cflags() + ['-sWASM_WORKERS', '-Wno-c23-extensions']
15561556
if self.is_mt:
15571557
cflags += ['-pthread']
15581558
if self.is_debug:

0 commit comments

Comments
 (0)