| |
| |
| |
| |
| |
|
|
| assert(SHARED_MEMORY); |
|
|
| addToLibrary({ |
| |
| |
| |
| |
| |
| |
| |
| #if MIN_CHROME_VERSION < 91 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED || MIN_FIREFOX_VERSION != TARGET_NOT_SUPPORTED || ENVIRONMENT_MAY_BE_NODE |
| |
| |
| |
| |
| |
| |
| |
| $waitAsyncPolyfilled: '=(!Atomics.waitAsync || (globalThis.navigator?.userAgent && Number((navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./)||[])[2]) < 91));', |
| $polyfillWaitAsync__deps: ['$waitAsyncPolyfilled'], |
| $polyfillWaitAsync__postset: `if (waitAsyncPolyfilled) { |
| let __Atomics_waitAsyncAddresses = [/*[i32a, index, value, maxWaitMilliseconds, promiseResolve]*/]; |
| function __Atomics_pollWaitAsyncAddresses() { |
| let now = performance.now(); |
| let l = __Atomics_waitAsyncAddresses.length; |
| for (let i = 0; i < l; ++i) { |
| let a = __Atomics_waitAsyncAddresses[i]; |
| let expired = (now > a[3]); |
| let awoken = (Atomics.load(a[0], a[1]) != a[2]); |
| if (expired || awoken) { |
| __Atomics_waitAsyncAddresses[i--] = __Atomics_waitAsyncAddresses[--l]; |
| __Atomics_waitAsyncAddresses.length = l; |
| a[4](awoken ? 'ok': 'timed-out'); |
| } |
| } |
| if (l) { |
| // If we still have addresses to wait, loop the timeout handler to continue polling. |
| setTimeout(__Atomics_pollWaitAsyncAddresses, 10); |
| } |
| } |
| #if ASSERTIONS && WASM_WORKERS |
| if (!ENVIRONMENT_IS_WASM_WORKER) err('Current environment does not support Atomics.waitAsync(): polyfilling it, but this is going to be suboptimal.'); |
| #endif |
| /** |
| * @param {number=} maxWaitMilliseconds |
| */ |
| Atomics.waitAsync = (i32a, index, value, maxWaitMilliseconds) => { |
| let val = Atomics.load(i32a, index); |
| if (val != value) return { async: false, value: 'not-equal' }; |
| if (maxWaitMilliseconds <= 0) return { async: false, value: 'timed-out' }; |
| maxWaitMilliseconds = performance.now() + (maxWaitMilliseconds || Infinity); |
| let promiseResolve; |
| let promise = new Promise((resolve) => { promiseResolve = resolve; }); |
| if (!__Atomics_waitAsyncAddresses[0]) setTimeout(__Atomics_pollWaitAsyncAddresses, 10); |
| __Atomics_waitAsyncAddresses.push([i32a, index, value, maxWaitMilliseconds, promiseResolve]); |
| return { async: true, value: promise }; |
| }; |
| }`, |
| #else |
| $waitAsyncPolyfilled: false, |
| #endif |
|
|
| $polyfillWaitAsync__internal: true, |
| $polyfillWaitAsync: () => { |
| |
| |
| |
| }, |
|
|
| $atomicWaitStates__internal: true, |
| $atomicWaitStates: ['ok', 'not-equal', 'timed-out'], |
| $liveAtomicWaitAsyncs: {}, |
| $liveAtomicWaitAsyncs__internal: true, |
| $liveAtomicWaitAsyncCounter: 0, |
| $liveAtomicWaitAsyncCounter__internal: true, |
|
|
| emscripten_atomic_wait_async__deps: ['$atomicWaitStates', '$liveAtomicWaitAsyncs', '$liveAtomicWaitAsyncCounter', '$polyfillWaitAsync', '$callUserCallback'], |
| emscripten_atomic_wait_async: (addr, val, asyncWaitFinished, userData, maxWaitMilliseconds) => { |
| let wait = Atomics.waitAsync(HEAP32, {{{ getHeapOffset('addr', 'i32') }}}, val, maxWaitMilliseconds); |
| if (!wait.async) return atomicWaitStates.indexOf(wait.value); |
| |
| |
| |
| |
| let counter = liveAtomicWaitAsyncCounter; |
| liveAtomicWaitAsyncCounter = Math.max(0, (liveAtomicWaitAsyncCounter+1)|0); |
| liveAtomicWaitAsyncs[counter] = addr; |
| {{{ runtimeKeepalivePush() }}} |
| wait.value.then((value) => { |
| if (liveAtomicWaitAsyncs[counter]) { |
| {{{ runtimeKeepalivePop() }}} |
| delete liveAtomicWaitAsyncs[counter]; |
| callUserCallback(() => {{{ makeDynCall('vpiip', 'asyncWaitFinished') }}}(addr, val, atomicWaitStates.indexOf(value), userData)); |
| } |
| }); |
| return -counter; |
| }, |
|
|
| emscripten_atomic_cancel_wait_async__deps: ['$liveAtomicWaitAsyncs'], |
| emscripten_atomic_cancel_wait_async: (waitToken) => { |
| #if ASSERTIONS |
| if (waitToken == {{{ cDefs.ATOMICS_WAIT_NOT_EQUAL }}}) { |
| warnOnce('Attempted to call emscripten_atomic_cancel_wait_async() with a value ATOMICS_WAIT_NOT_EQUAL (1) that is not a valid wait token! Check success in return value from call to emscripten_atomic_wait_async()'); |
| } else if (waitToken == {{{ cDefs.ATOMICS_WAIT_TIMED_OUT }}}) { |
| warnOnce('Attempted to call emscripten_atomic_cancel_wait_async() with a value ATOMICS_WAIT_TIMED_OUT (2) that is not a valid wait token! Check success in return value from call to emscripten_atomic_wait_async()'); |
| } else if (waitToken > 0) { |
| warnOnce(`Attempted to call emscripten_atomic_cancel_wait_async() with an invalid wait token value ${waitToken}`); |
| } |
| #endif |
| var address = liveAtomicWaitAsyncs[waitToken]; |
| if (address) { |
| |
| |
| |
| |
| |
| Atomics.notify(HEAP32, {{{ getHeapOffset('address', 'i32') }}}); |
| delete liveAtomicWaitAsyncs[waitToken]; |
| {{{ runtimeKeepalivePop() }}} |
| return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; |
| } |
| |
| return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; |
| }, |
|
|
| emscripten_atomic_cancel_all_wait_asyncs__deps: ['$liveAtomicWaitAsyncs'], |
| emscripten_atomic_cancel_all_wait_asyncs: () => { |
| let waitAsyncs = Object.values(liveAtomicWaitAsyncs); |
| for (var address of waitAsyncs) { |
| Atomics.notify(HEAP32, {{{ getHeapOffset('address', 'i32') }}}); |
| } |
| liveAtomicWaitAsyncs = {}; |
| return waitAsyncs.length; |
| }, |
|
|
| emscripten_atomic_cancel_all_wait_asyncs_at_address__deps: ['$liveAtomicWaitAsyncs'], |
| emscripten_atomic_cancel_all_wait_asyncs_at_address: (address) => { |
| let numCancelled = 0; |
| for (var [waitToken, waitAddress] of Object.entries(liveAtomicWaitAsyncs)) { |
| if (waitAddress == address) { |
| Atomics.notify(HEAP32, {{{ getHeapOffset('address', 'i32') }}}); |
| delete liveAtomicWaitAsyncs[waitToken]; |
| numCancelled++; |
| } |
| } |
| return numCancelled; |
| }, |
|
|
| emscripten_has_threading_support: () => !!globalThis.SharedArrayBuffer, |
|
|
| emscripten_num_logical_cores: () => |
| #if ENVIRONMENT_MAY_BE_NODE |
| ENVIRONMENT_IS_NODE ? require('node:os').cpus().length : |
| #endif |
| navigator['hardwareConcurrency'], |
|
|
| emscripten_atomics_is_lock_free: (width) => Atomics.isLockFree(width), |
| }); |
|
|