diff --git a/crates/extension_host/src/wasm_host.rs b/crates/extension_host/src/wasm_host.rs index a6e5768f16243ce6c6a4d250002e29d5db06a071..0d041c64f4c88735a2bcdf275f005c38aa37e49e 100644 --- a/crates/extension_host/src/wasm_host.rs +++ b/crates/extension_host/src/wasm_host.rs @@ -604,15 +604,28 @@ impl WasmHost { let this = self.clone(); let manifest = manifest.clone(); let executor = cx.background_executor().clone(); - let load_extension_task = async move { - let zed_api_version = parse_wasm_extension_version(&manifest.id, &wasm_bytes)?; - let component = Component::from_binary(&this.engine, &wasm_bytes) - .context("failed to compile wasm component")?; + // Parse version and compile component on gpui's background executor. + // These are cpu-bound operations that don't require a tokio runtime. + let compile_task = { + let manifest_id = manifest.id.clone(); + let engine = this.engine.clone(); + + executor.spawn(async move { + let zed_api_version = parse_wasm_extension_version(&manifest_id, &wasm_bytes)?; + let component = Component::from_binary(&engine, &wasm_bytes) + .context("failed to compile wasm component")?; + + anyhow::Ok((zed_api_version, component)) + }) + }; + + let load_extension = |zed_api_version: Version, component| async move { + let wasi_ctx = this.build_wasi_ctx(&manifest).await?; let mut store = wasmtime::Store::new( &this.engine, WasmState { - ctx: this.build_wasi_ctx(&manifest).await?, + ctx: wasi_ctx, manifest: manifest.clone(), table: ResourceTable::new(), host: this.clone(), @@ -661,11 +674,17 @@ impl WasmHost { zed_api_version, )) }; + cx.spawn(async move |cx| { + let (zed_api_version, component) = compile_task.await?; + + // Run wasi-dependent operations on tokio. + // wasmtime_wasi internally uses tokio for I/O operations. let (extension_task, manifest, work_dir, tx, zed_api_version) = - cx.background_executor().spawn(load_extension_task).await?; - // we need to run run the task in a tokio context as wasmtime_wasi may - // call into tokio, accessing its runtime handle when we trigger the `engine.increment_epoch()` above. + gpui_tokio::Tokio::spawn(cx, load_extension(zed_api_version, component))?.await??; + + // Run the extension message loop on tokio since extension + // calls may invoke wasi functions that require a tokio runtime. let task = Arc::new(gpui_tokio::Tokio::spawn(cx, extension_task)?); Ok(WasmExtension {