diff --git a/.github/workflows/web.yaml b/.github/workflows/web.yaml index 4b90760eaed..7f673590bd6 100644 --- a/.github/workflows/web.yaml +++ b/.github/workflows/web.yaml @@ -43,9 +43,6 @@ jobs: - name: Setup Chromedriver uses: nanasess/setup-chromedriver@v2 - # Temporary workaround for https://github.com/nanasess/setup-chromedriver/issues/190 - with: - chromedriver-version: '114.0.5735.90' - name: Show Rust version run: rustc --version --verbose diff --git a/lib/wasix/src/runtime/task_manager/mod.rs b/lib/wasix/src/runtime/task_manager/mod.rs index b866c4af659..e9902d07aa8 100644 --- a/lib/wasix/src/runtime/task_manager/mod.rs +++ b/lib/wasix/src/runtime/task_manager/mod.rs @@ -92,7 +92,21 @@ impl<'a, 'b> TaskWasm<'a, 'b> { } } -/// An implementation of task management +/// A task executor backed by a thread pool. +/// +/// ## Thread Safety +/// +/// Due to [#4158], it is possible to pass non-thread safe objects across +/// threads by capturing them in the task passed to +/// [`VirtualTaskManager::task_shared()`] or +/// [`VirtualTaskManager::task_dedicated()`]. +/// +/// If your task needs access to a [`wasmer::Module`], [`wasmer::Memory`], or +/// [`wasmer::Instance`], it should explicitly transfer the objects using +/// either [`VirtualTaskManager::task_wasm()`] when in syscall context or +/// [`VirtualTaskManager::spawn_with_module()`] for higher level code. +/// +/// [#4158]: https://github.com/wasmerio/wasmer/issues/4158 #[allow(unused_variables)] pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static { /// Build a new Webassembly memory. @@ -130,35 +144,70 @@ pub trait VirtualTaskManager: std::fmt::Debug + Send + Sync + 'static { } } - /// Invokes whenever a WASM thread goes idle. In some runtimes (like singlethreaded - /// execution environments) they will need to do asynchronous work whenever the main - /// thread goes idle and this is the place to hook for that. + /// Pause the current thread of execution. + /// + /// This is typically invoked whenever a WASM thread goes idle. Besides + /// acting as a platform-agnostic [`std::thread::sleep()`], this also gives + /// the runtime a chance to do asynchronous work like pumping an event + /// loop. fn sleep_now( &self, time: Duration, ) -> Pin + Send + Sync + 'static>>; - /// Starts an asynchronous task that will run on a shared worker pool - /// This task must not block the execution or it could cause a deadlock + /// Run an asynchronous operation on the thread pool. + /// + /// This task must not block execution or it could cause deadlocks. + /// + /// See the "Thread Safety" documentation on [`VirtualTaskManager`] for + /// limitations on what a `task` can and can't contain. fn task_shared( &self, task: Box BoxFuture<'static, ()> + Send + 'static>, ) -> Result<(), WasiThreadError>; - /// Starts an WebAssembly task will will run on a dedicated thread - /// pulled from the worker pool that has a stateful thread local variable + /// Run a blocking WebAssembly operation on the thread pool. + /// + /// This is primarily used inside the context of a syscall and allows + /// the transfer of things like [`wasmer::Module`] across threads. fn task_wasm(&self, task: TaskWasm) -> Result<(), WasiThreadError>; - /// Starts an asynchronous task will will run on a dedicated thread - /// pulled from the worker pool. It is ok for this task to block execution - /// and any async futures within its scope + /// Run a blocking operation on the thread pool. + /// + /// It is okay for this task to block execution and any async futures within + /// its scope. fn task_dedicated( &self, task: Box, ) -> Result<(), WasiThreadError>; - /// Returns the amount of parallelism that is possible on this platform + /// Returns the amount of parallelism that is possible on this platform. fn thread_parallelism(&self) -> Result; + + /// Schedule a blocking task to run on the threadpool, explicitly + /// transferring a [`Module`] to the task. + /// + /// This should be preferred over [`VirtualTaskManager::task_dedicated()`] + /// where possible because [`wasmer::Module`] is actually `!Send` in the + /// browser and can only be transferred to background threads via + /// an explicit `postMessage()`. See [#4158] for more details. + /// + /// This is very similar to [`VirtualTaskManager::task_wasm()`], but + /// intended for use outside of a syscall context. For example, when you are + /// running in the browser and want to run a WebAssembly module in the + /// background. + /// + /// [#4158]: https://github.com/wasmerio/wasmer/issues/4158 + fn spawn_with_module( + &self, + module: Module, + task: Box, + ) -> Result<(), WasiThreadError> { + // Note: Ideally, this function and task_wasm() would be superseded by + // a more general mechanism for transferring non-thread safe values + // to the thread pool. + self.task_dedicated(Box::new(move || task(module))) + } } impl VirtualTaskManager for D @@ -202,6 +251,14 @@ where fn thread_parallelism(&self) -> Result { (**self).thread_parallelism() } + + fn spawn_with_module( + &self, + module: Module, + task: Box, + ) -> Result<(), WasiThreadError> { + (**self).spawn_with_module(module, task) + } } impl dyn VirtualTaskManager {