[wasm][mt] Don't call Module.removeRunDependency in workers (#81311)
authorAleksey Kliger (λgeek) <alklig@microsoft.com>
Sat, 28 Jan 2023 13:22:52 +0000 (08:22 -0500)
committerGitHub <noreply@github.com>
Sat, 28 Jan 2023 13:22:52 +0000 (08:22 -0500)
commitb6cd3003c05d9be521d6d1ffff9207255d177116
tree27ad6b3857f747709a93641a5ae8dead0b54a665
parent7d4163fc6e4b5c634eef22d0fd8decfc2aaca763
[wasm][mt] Don't call Module.removeRunDependency in workers (#81311)

Fixes a sporadic hang that depends on the order in which webworkers get initialized.

The way `removeRunDependency` works is that it decrements a counter (incremented by `addRunDependency`) and when the counter hits 0 it runs a callback that runs `run`.

The problem is that on workers there are no other dependencies, so `removeRunDependency("wasm_pre_init_essential")` ticks the counter down to 0 and calls `run`.

The second problem is that `run` on a worker short-circuits most of the logic and just calls `readyPromiseResolve`, `initRuntime` and `postMessage` and returns.

So the worker posts a message back to the main thread that it is loaded.

Then the main body of dotnet.js in the worker calls `run` a second time. And we send a second `postMessage`.

So the main thread receives 2 "loaded" message for each worker in the pool.

That messes up the counter in `instantiateWasmPThreadWorkerPool` which is waiting for every fresh worker to send just 1 message before allowing the main thread to continue.

As a result, by the time the main thread runs some user code, only half the workers have loaded.

Depending on the timing, that could mean that if the main thread attempts to start a new pthread, that pthread might be in a worker that hasn't loaded the runtime yet.  In that case, the pthread start function doesn't get called, and the main thread hangs in Mono's `create_thread()` helper waiting for the `start_info->registered` semaphore that will never be posted.
src/mono/wasm/runtime/startup.ts