From 9444113e1089847819dcc04cbc3aab8396a1bc60 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 11 Apr 2026 10:41:18 -0700 Subject: [PATCH] Unify thread ID allocation between Wasm Workers and pthreads. NFC Followup to #26660 and #26472 --- src/lib/libsigs.js | 4 +- src/lib/libwasm_worker.js | 28 +- src/lib/libwebaudio.js | 17 +- system/lib/libc/emscripten_internal.h | 5 +- system/lib/pthread/emscripten_get_next_tid.c | 31 ++ system/lib/pthread/pthread_create.c | 17 +- system/lib/pthread/threading_internal.h | 2 + system/lib/wasm_worker/audio_worklet.c | 17 + system/lib/wasm_worker/library_wasm_worker.c | 6 +- test/codesize/audio_worklet_wasm.expected.js | 294 +++++++++--------- .../hello_wasm_worker_wasm.expected.js | 36 +-- .../test_codesize_minimal_pthreads.json | 8 +- ...t_codesize_minimal_pthreads_memgrowth.json | 8 +- ...nimal_runtime_code_size_audio_worklet.json | 12 +- ...l_runtime_code_size_hello_wasm_worker.json | 12 +- test/wasm_worker/test_wasm_worker_dbg.out | 2 +- tools/system_libs.py | 3 +- 17 files changed, 268 insertions(+), 234 deletions(-) create mode 100644 system/lib/pthread/emscripten_get_next_tid.c create mode 100644 system/lib/wasm_worker/audio_worklet.c diff --git a/src/lib/libsigs.js b/src/lib/libsigs.js index bb990b3f9c142..6ead52530d407 100644 --- a/src/lib/libsigs.js +++ b/src/lib/libsigs.js @@ -313,7 +313,8 @@ sigs = { _embind_register_value_object__sig: 'vpppppp', _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_void__sig: 'vpp', - _emscripten_create_wasm_worker__sig: 'ipi', + _emscripten_create_audio_worklet__sig: 'viipipp', + _emscripten_create_wasm_worker__sig: 'iipi', _emscripten_dlopen_js__sig: 'vpppp', _emscripten_dlsync_threads__sig: 'v', _emscripten_fetch_get_response_headers__sig: 'pipp', @@ -808,7 +809,6 @@ sigs = { emscripten_stack_snapshot__sig: 'p', emscripten_stack_unwind_buffer__sig: 'ippi', emscripten_start_fetch__sig: 'vp', - emscripten_start_wasm_audio_worklet_thread_async__sig: 'vipipp', emscripten_supports_offscreencanvas__sig: 'i', emscripten_terminate_all_wasm_workers__sig: 'v', emscripten_terminate_wasm_worker__sig: 'vi', diff --git a/src/lib/libwasm_worker.js b/src/lib/libwasm_worker.js index af8b8930104d5..1542573fb715c 100644 --- a/src/lib/libwasm_worker.js +++ b/src/lib/libwasm_worker.js @@ -50,7 +50,7 @@ // This is the way that we signal to the Web Worker that it is hosting // a Wasm Worker. #if ASSERTIONS - 'name': 'em-ww-' + _wasmWorkersID, + 'name': 'em-ww-' + wwID, #else 'name': 'em-ww', #endif @@ -62,16 +62,6 @@ addToLibrary({ $_wasmWorkers: {}, -#if PTHREADS - // When the build contains both pthreads and Wasm Workers, offset the - // Wasm Worker ID space to avoid collisions with pthread TIDs (which start - // at 42). We use `1 << 21` since it's ~1/2 way through `pid_t` space, - // essentially giving pthreads the first 1/2 of the range and wasm workers the - // second half. - $_wasmWorkersID: {{{ 1 << 21 }}}, -#else - $_wasmWorkersID: 1, -#endif // Starting up a Wasm Worker is an asynchronous operation, hence if the parent // thread performs any postMessage()-based wasm function calls to the @@ -175,7 +165,7 @@ addToLibrary({ }, _emscripten_create_wasm_worker__deps: [ - '$_wasmWorkers', '$_wasmWorkersID', + '$_wasmWorkers', '$_wasmWorkerAppendToQueue', '$_wasmWorkerRunPostMessage', #if ASSERTIONS 'emscripten_has_threading_support', @@ -191,11 +181,11 @@ if (ENVIRONMENT_IS_WASM_WORKER _wasmWorkers[0] = globalThis; addEventListener("message", _wasmWorkerAppendToQueue); }`, - _emscripten_create_wasm_worker: (stackLowestAddress, stackSize) => { + _emscripten_create_wasm_worker: (wwID, stackLowestAddress, stackSize) => { #if ASSERTIONS if (!_emscripten_has_threading_support()) { err('create_wasm_worker: environment does not support SharedArrayBuffer, wasm workers are not available'); - return 0; + return false; } #endif let worker; @@ -205,15 +195,15 @@ if (ENVIRONMENT_IS_WASM_WORKER var p = trustedTypes.createPolicy( 'emscripten#workerPolicy1', { createScriptURL: (ignored) => {{{ wasmWorkerJs }}}} ); - worker = _wasmWorkers[_wasmWorkersID] = new Worker(p.createScriptURL('ignored'), {{{ wasmWorkerOptions }}}); + worker = _wasmWorkers[wwID] = new Worker(p.createScriptURL('ignored'), {{{ wasmWorkerOptions }}}); } else #endif - worker = _wasmWorkers[_wasmWorkersID] = new Worker({{{ wasmWorkerJs }}}, {{{ wasmWorkerOptions }}}); + worker = _wasmWorkers[wwID] = new Worker({{{ wasmWorkerJs }}}, {{{ wasmWorkerOptions }}}); // Craft the Module object for the Wasm Worker scope: worker.postMessage({ // Signal with a non-zero value that this Worker will be a Wasm Worker, // and not the main browser thread. - wwID: _wasmWorkersID, + wwID, wasm: wasmModule, wasmMemory, stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full) @@ -237,9 +227,9 @@ if (ENVIRONMENT_IS_WASM_WORKER } #endif #if RUNTIME_DEBUG - dbg("done _emscripten_create_wasm_worker", _wasmWorkersID) + dbg("done _emscripten_create_wasm_worker", wwID) #endif - return _wasmWorkersID++; + return true; }, emscripten_terminate_wasm_worker: (id) => { diff --git a/src/lib/libwebaudio.js b/src/lib/libwebaudio.js index 421852d367e67..29e84909cc970 100644 --- a/src/lib/libwebaudio.js +++ b/src/lib/libwebaudio.js @@ -165,16 +165,15 @@ var LibraryWebAudio = { }, #if AUDIO_WORKLET - // emscripten_start_wasm_audio_worklet_thread_async() doesn't use stackAlloc, + // _emscripten_create_audio_worklet() doesn't use stackAlloc, // etc., but the created worklet does. - emscripten_start_wasm_audio_worklet_thread_async__deps: [ - '$_wasmWorkersID', + _emscripten_create_audio_worklet__deps: [ '$_emAudioDispatchProcessorCallback', '$stackAlloc', '$stackRestore', '$stackSave'], - emscripten_start_wasm_audio_worklet_thread_async: (contextHandle, stackLowestAddress, stackSize, callback, userData) => { + _emscripten_create_audio_worklet: (wwID, contextHandle, stackLowestAddress, stackSize, callback, userData) => { #if ASSERTIONS || WEBAUDIO_DEBUG - emAudioExpectContext(contextHandle, 'emscripten_start_wasm_audio_worklet_thread_async'); + emAudioExpectContext(contextHandle, '_emscripten_create_audio_worklet'); #endif var audioContext = emAudio[contextHandle]; @@ -190,12 +189,12 @@ var LibraryWebAudio = { #endif #if WEBAUDIO_DEBUG - dbg(`emscripten_start_wasm_audio_worklet_thread_async() adding audioworklet.js...`); + dbg(`_emscripten_create_audio_worklet() adding audioworklet.js...`); #endif var audioWorkletCreationFailed = () => { #if ASSERTIONS || WEBAUDIO_DEBUG - dbg(`emscripten_start_wasm_audio_worklet_thread_async() addModule() failed!`); + dbg(`_emscripten_create_audio_worklet() addModule() failed!`); #endif {{{ makeDynCall('viip', 'callback') }}}(contextHandle, 0/*EM_FALSE*/, userData); }; @@ -214,7 +213,7 @@ var LibraryWebAudio = { audioWorklet.addModule({{{ wasmWorkerJs }}}).then(() => { #if WEBAUDIO_DEBUG - dbg(`emscripten_start_wasm_audio_worklet_thread_async() addModule() completed`); + dbg(`_emscripten_create_audio_worklet() addModule() completed`); #endif #if MIN_FIREFOX_VERSION < 138 || MIN_CHROME_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED @@ -248,7 +247,7 @@ var LibraryWebAudio = { // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that // it can utilized its own TLS slots, and it is recognized to not be // the main browser thread. - wwID: _wasmWorkersID++, + wwID, #if MINIMAL_RUNTIME wasm: Module['wasm'], #else diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 15465864c4d7a..7f0ffccea5116 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -129,7 +130,9 @@ void emscripten_fetch_free(unsigned int); // Internal implementation function in JavaScript side that emscripten_create_wasm_worker() calls to // to perform the wasm worker creation. -emscripten_wasm_worker_t _emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize); +bool _emscripten_create_wasm_worker(emscripten_wasm_worker_t wwID, void *stackLowestAddress, uint32_t stackSize); + +void _emscripten_create_audio_worklet(emscripten_wasm_worker_t wwID, EMSCRIPTEN_WEBAUDIO_T audioContext, void *stackLowestAddress, uint32_t stackSize, EmscriptenStartWebAudioWorkletCallback callback, void *userData2); void __resumeException(void* exn); void __cxa_call_unexpected(void* exn); diff --git a/system/lib/pthread/emscripten_get_next_tid.c b/system/lib/pthread/emscripten_get_next_tid.c new file mode 100644 index 0000000000000..de870f019718d --- /dev/null +++ b/system/lib/pthread/emscripten_get_next_tid.c @@ -0,0 +1,31 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include + +#include "emscripten_internal.h" + +// In case the stub syscall is not linked it +static int dummy_getpid(void) { + return 42; +} +weak_alias(dummy_getpid, __syscall_getpid); + +static _Atomic pid_t next_tid = 0; + +pid_t _emscripten_get_next_tid() { + // Create threads with monotonically increasing TID starting with the main + // thread which has TID == PID. + if (next_tid == 0) { + // Use CAS to initialize next_tid so that one thread will end up + // initializing it. + pid_t expected = 0; + atomic_compare_exchange_strong(&next_tid, &expected, getpid() + 1); + } + return next_tid++; +} diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 570306a907a42..00df6ad4b8854 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -14,6 +14,7 @@ #include #include #include + #include #include @@ -62,14 +63,6 @@ static void init_file_lock(FILE *f) { if (f && f->lock<0) f->lock = 0; } -static pid_t next_tid = 0; - -// In case the stub syscall is not linked it -static int dummy_getpid(void) { - return 42; -} -weak_alias(dummy_getpid, __syscall_getpid); - static int tl_lock_count; static int tl_lock_waiters; @@ -121,12 +114,6 @@ int __pthread_create(pthread_t* restrict res, return EINVAL; } - // Create threads with monotonically increasing TID starting with the main - // thread which has TID == PID. - if (!next_tid) { - next_tid = getpid() + 1; - } - if (!libc.threaded) { for (FILE *f=*__ofl_lock(); f; f=f->next) init_file_lock(f); @@ -177,7 +164,7 @@ int __pthread_create(pthread_t* restrict res, // The pthread struct has a field that points to itself - this is used as a // magic ID to detect whether the pthread_t structure is 'alive'. new->self = new; - new->tid = next_tid++; + new->tid = _emscripten_get_next_tid(); // pthread struct robust_list head should point to itself. new->robust_list.head = &new->robust_list.head; diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index abc6cbff7f22c..22ad1ae433674 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -104,3 +104,5 @@ void _emscripten_run_js_on_main_thread_done(void* ctx, void* arg, double result) // if called from the main browser thread, this function will return zero // since blocking is not allowed there). int _emscripten_thread_supports_atomics_wait(void); + +pid_t _emscripten_get_next_tid(); diff --git a/system/lib/wasm_worker/audio_worklet.c b/system/lib/wasm_worker/audio_worklet.c new file mode 100644 index 0000000000000..a921fcdea7da7 --- /dev/null +++ b/system/lib/wasm_worker/audio_worklet.c @@ -0,0 +1,17 @@ +/* + * Copyright 2026 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include + +#include "emscripten_internal.h" +#include "threading_internal.h" + +// Simple wrapper function around the JS _emscripten_create_audio_worklet +// function that adds the _emscripten_get_next_tid() as arg0 +void emscripten_start_wasm_audio_worklet_thread_async(EMSCRIPTEN_WEBAUDIO_T audioContext, void *stackLowestAddress, uint32_t stackSize, EmscriptenStartWebAudioWorkletCallback callback, void *userData2) { + _emscripten_create_audio_worklet(_emscripten_get_next_tid(), audioContext, stackLowestAddress, stackSize, callback, userData2); +} diff --git a/system/lib/wasm_worker/library_wasm_worker.c b/system/lib/wasm_worker/library_wasm_worker.c index 15484acaa29de..e4ecf0b112788 100644 --- a/system/lib/wasm_worker/library_wasm_worker.c +++ b/system/lib/wasm_worker/library_wasm_worker.c @@ -14,6 +14,7 @@ #include "libc.h" #include "stdio_impl.h" #include "emscripten_internal.h" +#include "threading_internal.h" #include #include @@ -101,7 +102,10 @@ emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress // only going one way here. if (!libc.threads_minus_1++) libc.need_locks = 1; - return _emscripten_create_wasm_worker(stackPlusTLSAddress, stackPlusTLSSize); + emscripten_wasm_worker_t wwID = _emscripten_get_next_tid(); + if (!_emscripten_create_wasm_worker(wwID, stackPlusTLSAddress, stackPlusTLSSize)) + return 0; + return wwID; } emscripten_wasm_worker_t emscripten_malloc_wasm_worker(size_t stackSize) { diff --git a/test/codesize/audio_worklet_wasm.expected.js b/test/codesize/audio_worklet_wasm.expected.js index 33b2b8c2790ac..d1b4ebcacb533 100644 --- a/test/codesize/audio_worklet_wasm.expected.js +++ b/test/codesize/audio_worklet_wasm.expected.js @@ -1,8 +1,8 @@ -var m = globalThis.Module || "undefined" != typeof Module ? Module : {}, p = !!globalThis.AudioWorkletGlobalScope, t = "em-ww" == globalThis.name || p, u, z, J, E, G, I, w, X, F, D, C, Y, A, Z; +var m = globalThis.Module || "undefined" != typeof Module ? Module : {}, q = !!globalThis.AudioWorkletGlobalScope, r = "em-ww" == globalThis.name || q, t, z, J, E, G, I, v, X, F, D, C, Y, A, Z; -function v(a) { - u = a; - w = a.H; +function u(a) { + t = a; + v = a.H; x(); m ||= {}; m.wasm = a.G; @@ -10,14 +10,14 @@ function v(a) { a.G = a.H = 0; } -t && !p && (onmessage = a => { +r && !q && (onmessage = a => { onmessage = null; - v(a.data); + u(a.data); }); -if (p) { - function a(b) { - class h extends AudioWorkletProcessor { +if (q) { + function a(c) { + class l extends AudioWorkletProcessor { constructor(d) { super(); d = d.processorOptions; @@ -25,25 +25,25 @@ if (p) { this.A = d.A; this.u = d.u; this.s = 4 * this.u; - this.B = Array(Math.min((u.F - 16) / this.s | 0, 64)); + this.B = Array(Math.min((t.F - 16) / this.s | 0, 64)); this.L(); } L() { - for (var d = C(), g = D(this.B.length * this.s) >> 2, e = this.B.length - 1; 0 <= e; e--) this.B[e] = E.subarray(g, g += this.u); + for (var d = C(), h = D(this.B.length * this.s) >> 2, g = this.B.length - 1; 0 <= g; g--) this.B[g] = E.subarray(h, h += this.u); F(d); } static get parameterDescriptors() { - return b; + return c; } - process(d, g, e) { - var l = d.length, q = g.length, f, r, k = 12 * (l + q), n = 0; + process(d, h, g) { + var e = d.length, w = h.length, f, p, k = 12 * (e + w), n = 0; for (f of d) n += f.length; n *= this.s; var H = 0; - for (f of g) H += f.length; + for (f of h) H += f.length; n += H * this.s; var O = 0; - for (f in e) ++O, k += 8, n += e[f].byteLength; + for (f in g) ++O, k += 8, n += g[f].byteLength; var V = C(), B = k + n + 15 & -16; k = D(B); n = k + (B - n); @@ -53,50 +53,50 @@ if (p) { G[k + 4 >> 2] = this.u; G[k + 8 >> 2] = n; k += 12; - for (r of f) E.set(r, n >> 2), n += this.s; + for (p of f) E.set(p, n >> 2), n += this.s; } d = k; - for (f = 0; r = e[f++]; ) G[k >> 2] = r.length, G[k + 4 >> 2] = n, k += 8, E.set(r, n >> 2), - n += 4 * r.length; - e = k; - for (f of g) G[k >> 2] = f.length, G[k + 4 >> 2] = this.u, G[k + 8 >> 2] = n, k += 12, + for (f = 0; p = g[f++]; ) G[k >> 2] = p.length, G[k + 4 >> 2] = n, k += 8, E.set(p, n >> 2), + n += 4 * p.length; + g = k; + for (f of h) G[k >> 2] = f.length, G[k + 4 >> 2] = this.u, G[k + 8 >> 2] = n, k += 12, n += this.s * f.length; - if (l = this.v(l, B, q, e, O, d, this.A)) for (f of g) for (r of f) r.set(this.B[--H]); + if (e = this.v(e, B, w, g, O, d, this.A)) for (f of h) for (p of f) p.set(this.B[--H]); F(V); - return !!l; + return !!e; } } - return h; + return l; } var port = globalThis.port || {}; - class c extends AudioWorkletProcessor { - constructor(b) { + class b extends AudioWorkletProcessor { + constructor(c) { super(); - v(b.processorOptions); + u(c.processorOptions); port instanceof MessagePort || (this.port.onmessage = port.onmessage, port = this.port); } process() {} } - registerProcessor("em-bootstrap", c); - port.onmessage = async b => { + registerProcessor("em-bootstrap", b); + port.onmessage = async c => { await z; - b = b.data; - b._boot ? v(b) : b._wpn ? (registerProcessor(b._wpn, a(b.I)), port.postMessage({ - _wsc: b.v, - C: [ b.J, 1, b.A ] - })) : b._wsc && A.get(b._wsc)(...b.C); + c = c.data; + c._boot ? u(c) : c._wpn ? (registerProcessor(c._wpn, a(c.I)), port.postMessage({ + _wsc: c.v, + C: [ c.J, 1, c.A ] + })) : c._wsc && A.get(c._wsc)(...c.C); }; } function x() { - var a = w.buffer; + var a = v.buffer; I = new Uint8Array(a); J = new Int32Array(a); G = new Uint32Array(a); E = new Float32Array(a); } -t || (w = m.mem || new WebAssembly.Memory({ +r || (v = m.mem || new WebAssembly.Memory({ initial: 256, maximum: 256, shared: !0 @@ -104,139 +104,139 @@ t || (w = m.mem || new WebAssembly.Memory({ var K = [], L = a => { a = a.data; - let c = a._wsc; - c && A.get(c)(...a.x); + let b = a._wsc; + b && A.get(b)(...a.x); }, M = a => { K.push(a); -}, P = (a, c, b, h) => { - c = N[c]; - N[a].connect(c.destination || c, b, h); -}, N = {}, Q = 0, R = globalThis.TextDecoder && new TextDecoder, S = (a = 0) => { - for (var c = I, b = a, h = b + void 0; c[b] && !(b >= h); ) ++b; - if (16 < b - a && c.buffer && R) return R.decode(c.slice(a, b)); - for (h = ""; a < b; ) { - var d = c[a++]; +}, N = a => { + a = a.data; + var b = a._wsc; + b && A.get(b)(...a.C); +}, Q = (a, b, c, l, d, h) => { + var g = P[b], e = g.audioWorklet, w = () => { + A.get(d)(b, 0, h); + }; + if (!e) return w(); + e.addModule(m.js).then((() => { + e.port || (e.port = { + postMessage: f => { + f._boot ? (e.D = new AudioWorkletNode(g, "em-bootstrap", { + processorOptions: f + }), e.D.port.onmessage = p => { + e.port.onmessage(p); + }) : e.D.port.postMessage(f); + } + }); + e.port.postMessage({ + _boot: 1, + M: a, + G: m.wasm, + H: v, + K: c, + F: l + }); + e.port.onmessage = N; + A.get(d)(b, 1, h); + })).catch(w); +}, R = (a, b, c, l) => { + b = P[b]; + P[a].connect(b.destination || b, c, l); +}, P = {}, S = 0, T = globalThis.TextDecoder && new TextDecoder, U = (a = 0) => { + for (var b = I, c = a, l = c + void 0; b[c] && !(c >= l); ) ++c; + if (16 < c - a && b.buffer && T) return T.decode(b.slice(a, c)); + for (l = ""; a < c; ) { + var d = b[a++]; if (d & 128) { - var g = c[a++] & 63; - if (192 == (d & 224)) h += String.fromCharCode((d & 31) << 6 | g); else { - var e = c[a++] & 63; - d = 224 == (d & 240) ? (d & 15) << 12 | g << 6 | e : (d & 7) << 18 | g << 12 | e << 6 | c[a++] & 63; - 65536 > d ? h += String.fromCharCode(d) : (d -= 65536, h += String.fromCharCode(55296 | d >> 10, 56320 | d & 1023)); + var h = b[a++] & 63; + if (192 == (d & 224)) l += String.fromCharCode((d & 31) << 6 | h); else { + var g = b[a++] & 63; + d = 224 == (d & 240) ? (d & 15) << 12 | h << 6 | g : (d & 7) << 18 | h << 12 | g << 6 | b[a++] & 63; + 65536 > d ? l += String.fromCharCode(d) : (d -= 65536, l += String.fromCharCode(55296 | d >> 10, 56320 | d & 1023)); } - } else h += String.fromCharCode(d); + } else l += String.fromCharCode(d); } - return h; -}, T = a => { + return l; +}, aa = a => { if (a) { - var c = G[a >> 2]; - c = (c ? S(c) : "") || void 0; - var b = J[a + 8 >> 2]; + var b = G[a >> 2]; + b = (b ? U(b) : "") || void 0; + var c = J[a + 8 >> 2]; a = { - latencyHint: c, + latencyHint: b, sampleRate: G[a + 4 >> 2] || void 0, - N: 0 > b ? "hardware" : b || "default" + N: 0 > c ? "hardware" : c || "default" }; } else a = void 0; a = new AudioContext(a); - N[++Q] = a; - return Q; -}, U = (a, c, b, h, d) => { - var g = b ? J[b + 4 >> 2] : 0; - if (b) { - var e = J[b >> 2], l = G[b + 8 >> 2], q = g; - if (l) { - l >>= 2; - for (var f = []; q--; ) f.push(G[l++]); - l = f; - } else l = void 0; - b = { - numberOfInputs: e, - numberOfOutputs: g, - outputChannelCount: l, - channelCount: G[b + 12 >> 2] || void 0, - channelCountMode: [ , "clamped-max", "explicit" ][J[b + 16 >> 2]], - channelInterpretation: [ , "discrete" ][J[b + 20 >> 2]], + P[++S] = a; + return S; +}, ba = (a, b, c, l, d) => { + var h = c ? J[c + 4 >> 2] : 0; + if (c) { + var g = J[c >> 2], e = G[c + 8 >> 2], w = h; + if (e) { + e >>= 2; + for (var f = []; w--; ) f.push(G[e++]); + e = f; + } else e = void 0; + c = { + numberOfInputs: g, + numberOfOutputs: h, + outputChannelCount: e, + channelCount: G[c + 12 >> 2] || void 0, + channelCountMode: [ , "clamped-max", "explicit" ][J[c + 16 >> 2]], + channelInterpretation: [ , "discrete" ][J[c + 20 >> 2]], processorOptions: { - v: h, + v: l, A: d, - u: N[a].renderQuantumSize || 128 + u: P[a].renderQuantumSize || 128 } }; - } else b = void 0; - a = new AudioWorkletNode(N[a], c ? S(c) : "", b); - N[++Q] = a; - return Q; -}, aa = (a, c, b, h) => { - var d = (d = G[c >> 2]) ? S(d) : "", g = J[c + 4 >> 2]; - c = G[c + 8 >> 2]; - for (var e = [], l = 0; g--; ) e.push({ - name: l++, - defaultValue: E[c >> 2], - minValue: E[c + 4 >> 2], - maxValue: E[c + 8 >> 2], - automationRate: (J[c + 12 >> 2] ? "k" : "a") + "-rate" - }), c += 16; - N[a].audioWorklet.port.postMessage({ + } else c = void 0; + a = new AudioWorkletNode(P[a], b ? U(b) : "", c); + P[++S] = a; + return S; +}, ca = (a, b, c, l) => { + var d = (d = G[b >> 2]) ? U(d) : "", h = J[b + 4 >> 2]; + b = G[b + 8 >> 2]; + for (var g = [], e = 0; h--; ) g.push({ + name: e++, + defaultValue: E[b >> 2], + minValue: E[b + 4 >> 2], + maxValue: E[b + 8 >> 2], + automationRate: (J[b + 12 >> 2] ? "k" : "a") + "-rate" + }), b += 16; + P[a].audioWorklet.port.postMessage({ _wpn: d, - I: e, + I: g, J: a, - v: b, - A: h + v: c, + A: l }); -}, ba = () => !1, ca = 1, da = a => { - a = a.data; - var c = a._wsc; - c && A.get(c)(...a.C); -}, ea = (a, c, b, h, d) => { - var g = N[a], e = g.audioWorklet, l = () => { - A.get(h)(a, 0, d); - }; - if (!e) return l(); - e.addModule(m.js).then((() => { - e.port || (e.port = { - postMessage: q => { - q._boot ? (e.D = new AudioWorkletNode(g, "em-bootstrap", { - processorOptions: q - }), e.D.port.onmessage = f => { - e.port.onmessage(f); - }) : e.D.port.postMessage(q); - } - }); - e.port.postMessage({ - _boot: 1, - M: ca++, - G: m.wasm, - H: w, - K: c, - F: b - }); - e.port.onmessage = da; - A.get(h)(a, 1, d); - })).catch(l); -}, fa = () => p ? () => 138 : a => (a.set(crypto.getRandomValues(new Uint8Array(a.byteLength))), -0), W = a => (W = fa())(a), ha = (a, c) => W(I.subarray(a, a + c)); +}, da = () => !1, ea = () => q ? () => 138 : a => (a.set(crypto.getRandomValues(new Uint8Array(a.byteLength))), +0), W = a => (W = ea())(a), fa = (a, b) => W(I.subarray(a, a + b)); -function ia(a) { - let c = document.createElement("button"); - c.innerHTML = "Toggle playback"; - document.body.appendChild(c); - a = N[a]; - c.onclick = () => { +function ha(a) { + let b = document.createElement("button"); + b.innerHTML = "Toggle playback"; + document.body.appendChild(b); + a = P[a]; + b.onclick = () => { "running" != a.state ? a.resume() : a.suspend(); }; } function y() { Z = { - g: ia, - h: P, - e: T, - i: U, - f: aa, - b: ba, - d: ea, - a: w, - c: ha + g: ha, + b: Q, + h: R, + e: aa, + i: ba, + f: ca, + c: da, + a: v, + d: fa }; z = WebAssembly.instantiate(m.wasm, { a: Z @@ -248,10 +248,10 @@ function y() { C = a.o; Y = a.p; A = a.l; - t ? (Y(u.M, u.K, u.F), p || (removeEventListener("message", M), K = K.forEach(L), + r ? (Y(t.M, t.K, t.F), q || (removeEventListener("message", M), K = K.forEach(L), addEventListener("message", L))) : a.j(); - t || X(); + r || X(); })); } -t || y(); \ No newline at end of file +r || y(); \ No newline at end of file diff --git a/test/codesize/hello_wasm_worker_wasm.expected.js b/test/codesize/hello_wasm_worker_wasm.expected.js index 8eaf110c41a4e..42ff06931d6c9 100644 --- a/test/codesize/hello_wasm_worker_wasm.expected.js +++ b/test/codesize/hello_wasm_worker_wasm.expected.js @@ -1,4 +1,4 @@ -var c = Module, d = !!globalThis.WorkerGlobalScope, e = "em-ww" == globalThis.name, f, g, C, r, D, n, E, w; +var c = Module, d = !!globalThis.WorkerGlobalScope, e = "em-ww" == globalThis.name, f, g, C, r, D, n, E, v; e && (onmessage = a => { onmessage = null; @@ -19,28 +19,28 @@ e || (g = c.mem || new WebAssembly.Memory({ shared: !0 }), h()); -var l = [], p = a => { +var m = [], p = a => { a = a.data; let b = a._wsc; b && n.get(b)(...a.x); }, q = a => { - l.push(a); + m.push(a); }, t = () => { r(0, !d, !e, d && 1); -}, u = {}, v = 1, x = (a, b) => { - let m = u[v] = new Worker(c.js, { +}, u = {}, w = (a, b, z) => { + let l = u[a] = new Worker(c.js, { name: "em-ww" }); - m.postMessage({ - v: v, - m: w, + l.postMessage({ + v: a, + m: v, o: g, - s: a, - u: b + s: b, + u: z }); - m.onmessage = p; - return v++; -}, y = () => performance.now(), z = () => !1, A = (a, b) => { + l.onmessage = p; + return !0; +}, x = () => performance.now(), y = () => !1, A = (a, b) => { u[a].postMessage({ _wsc: b, x: [] @@ -56,9 +56,9 @@ function B() { function k() { E = { e: t, - c: x, - b: y, - d: z, + c: w, + b: x, + d: y, f: A, g: B, a: g @@ -67,12 +67,12 @@ function k() { a: E }).then((a => { var b = (a.instance || a).exports; - w = a.module || c.wasm; + v = a.module || c.wasm; C = b.i; r = b.k; D = b.l; n = b.j; - e ? (D(f.v, f.s, f.u), removeEventListener("message", q), l = l.forEach(p), addEventListener("message", p)) : b.h(); + e ? (D(f.v, f.s, f.u), removeEventListener("message", q), m = m.forEach(p), addEventListener("message", p)) : b.h(); e || C(); })); } diff --git a/test/codesize/test_codesize_minimal_pthreads.json b/test/codesize/test_codesize_minimal_pthreads.json index 050cb6cd65f24..bb969ba950225 100644 --- a/test/codesize/test_codesize_minimal_pthreads.json +++ b/test/codesize/test_codesize_minimal_pthreads.json @@ -1,10 +1,10 @@ { "a.out.js": 7367, "a.out.js.gz": 3603, - "a.out.nodebug.wasm": 19003, - "a.out.nodebug.wasm.gz": 8786, - "total": 26370, - "total_gz": 12389, + "a.out.nodebug.wasm": 19002, + "a.out.nodebug.wasm.gz": 8787, + "total": 26369, + "total_gz": 12390, "sent": [ "a (memory)", "b (exit)", diff --git a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json index 3076a1322f4a5..9fd72a9e136cc 100644 --- a/test/codesize/test_codesize_minimal_pthreads_memgrowth.json +++ b/test/codesize/test_codesize_minimal_pthreads_memgrowth.json @@ -1,10 +1,10 @@ { "a.out.js": 7769, "a.out.js.gz": 3809, - "a.out.nodebug.wasm": 19004, - "a.out.nodebug.wasm.gz": 8787, - "total": 26773, - "total_gz": 12596, + "a.out.nodebug.wasm": 19003, + "a.out.nodebug.wasm.gz": 8788, + "total": 26772, + "total_gz": 12597, "sent": [ "a (memory)", "b (exit)", diff --git a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json index f1b1c4ce5a716..bf59dffa48ea4 100644 --- a/test/codesize/test_minimal_runtime_code_size_audio_worklet.json +++ b/test/codesize/test_minimal_runtime_code_size_audio_worklet.json @@ -1,10 +1,10 @@ { "a.html": 515, "a.html.gz": 355, - "a.js": 4452, - "a.js.gz": 2294, - "a.wasm": 1360, - "a.wasm.gz": 910, - "total": 6327, - "total_gz": 3559 + "a.js": 4446, + "a.js.gz": 2299, + "a.wasm": 1393, + "a.wasm.gz": 933, + "total": 6354, + "total_gz": 3587 } diff --git a/test/codesize/test_minimal_runtime_code_size_hello_wasm_worker.json b/test/codesize/test_minimal_runtime_code_size_hello_wasm_worker.json index 678af8ef670c3..3e9aa822d5125 100644 --- a/test/codesize/test_minimal_runtime_code_size_hello_wasm_worker.json +++ b/test/codesize/test_minimal_runtime_code_size_hello_wasm_worker.json @@ -1,10 +1,10 @@ { "a.html": 515, "a.html.gz": 355, - "a.js": 956, - "a.js.gz": 605, - "a.wasm": 2584, - "a.wasm.gz": 1438, - "total": 4055, - "total_gz": 2398 + "a.js": 952, + "a.js.gz": 601, + "a.wasm": 2630, + "a.wasm.gz": 1465, + "total": 4097, + "total_gz": 2421 } diff --git a/test/wasm_worker/test_wasm_worker_dbg.out b/test/wasm_worker/test_wasm_worker_dbg.out index da46278476ddd..9471725daebe1 100644 --- a/test/wasm_worker/test_wasm_worker_dbg.out +++ b/test/wasm_worker/test_wasm_worker_dbg.out @@ -2,5 +2,5 @@ err from main thread ww:0: dbg from main thread Hello from wasm worker! err from wasm worker -ww:1: dbg from wasm worker +ww:43: dbg from wasm worker do_exit diff --git a/tools/system_libs.py b/tools/system_libs.py index f2debcd9db20e..9373bf48ecf0d 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1305,6 +1305,7 @@ def get_files(self): libc_files += files_in_path( path='system/lib/pthread', filenames=[ + 'emscripten_get_next_tid.c', 'emscripten_thread_state.S', 'emscripten_thread_primitives.c', 'emscripten_futex_wait.c', @@ -1525,7 +1526,7 @@ class libwasm_workers(MuslInternalLibrary, DebugLibrary): name = 'libwasm_workers' includes = ['system/lib/libc'] src_dir = 'system/lib/wasm_worker' - src_files = ['library_wasm_worker.c', 'wasm_worker_initialize.S'] + src_files = ['library_wasm_worker.c', 'wasm_worker_initialize.S', 'audio_worklet.c'] def get_cflags(self): cflags = super().get_cflags() + ['-sWASM_WORKERS']