[wasm-mt] Support async JS interop on threadpool threads (#84494)
This is the last part of #84489 - initial runtime support for async JS interop on threadpool threads in multi-threaded WebAssembly. Conceptually there are a few things here: * A mechanism for the native runtime to start some threads as "exitable" so that we don't clean up when they return from their thread start function. (we will clean up when the pthreads TLS dtor runs) * A change to make JSHostImplementation.s_csOwnedObjects a thread-static in multithreaded builds. This is because the map keys on a small integer handle that is allocated per-thread on the JS side as a handle for JS objects that are to be kept alive because managed code depends on them. (This is needed in general, but also makes the new smoke test work) * A version of the PortableThreadPool.WorkerThread that starts as an exitable thread and uses asynchronous callbacks to wait for available threadpool work items and returns to the JS event loop periodically in order to allow JS promises to settle. * A smoke test that does a background JS fetch and some async callbacks on it. --- * [wasm-mt] Enable JSInterop on threadpool workers Implement PortableThreadPool loop using semaphore callbacks manage emscripten event loop from PortableThreadPool.WorkerThread make sure to keep the thread alive after setting up the semaphore wait. Cleanup the thread when exiting minimal sample - fetch on a background thread works Add WebWorkerEventLoop internal class to managed event loop keepalive Start threadpool threads with keepalive checks Add a flag to mono's thread start wrappers to keep track of threads that may not want cleanup to run after the Start function returns. Use the flag when starting threadpool threads. make minimal FetchBackground sample more like a unit test Set WorkerThread.IsIOPending when the current thread has unsettled JS interop promises. When IsIOPending is true, the worker will not exit even if it has no more work to do. Instead it will repeatedly wait for more work to arrive or for all promises to settle. change minimal sample's fetch helper to artificially delay the delay is longer that the threadpool worker's semaphore timeout, in order to validate that the worker stays alive while there are unsettled promises * [wasm-mt] Add background interop to smoketest * update to use the LowLevelLifoAsyncWaitSemaphore * adjust to renamed PortableThreadPool helper methods * adjust to renamed WebWorkerEventLoop.HasJavaScriptInteropDependents * extend and rationalize the smoke test a bit Add a test that just starts a thread and asserts that it has a different thread ID than the main thread. This should allow us to rule out accidentally having the test pass on a single-threaded runtime * hide some debug output * smoke test: dispose of the ImportAsync result after the task is done * [wasm-mt] make JSHostImplementation.s_csOwnedObjects ThreadStatic The integer jsHandles are not global - they are essentially indices into a JS array. So the mapping from a jsHandle to a JSObject must be per-thread. This fixes the thread affinity assertions in the smoketest (which were false positives - we looked up a worker's jsHandle and got back the main thread's JSObject - and then asserted that it was accessed from the wrong thread) * remove locking on JSHostImplementation.CsOwnedObjects In single-threaded wasm, there is no need to lock since there is only one caller at a time. In multi-threaded wasm, the underlying dictionary is thread-static * [threads] make the "external eventloop" platform independent It only does something on WASM, but in principle if other platforms allow us to run some code after returning from a thread start function, we could do it there, too. * Add a Thread.HasExternalEventLoop managed property Set it from WebWorkerEventLoop.StartExitable. In native code, use it to set the `MONO_THREAD_CREATE_FLAGS_EXTERNAL_EVENTLOOP` flag when starting the thread. * rename JSHostImplementation.ThreadCsOwnedObjects (used to be CsOwnedObjects) Rename to make it clear that it's objects owned by the current thread, not the runtime globally * [checked] assert GC Safe mode, when returning to external eventloop
Showing
想要评论请 注册 或 登录