Skip to content

Problem when spawn new thread in wasix/wasm with import function #5508

@zhezzz

Description

@zhezzz

Project Info

Project A

As the main project, it is responsible for loading the .wasm file and running it.

  1. Rust:2021 rustc 1.84.1 (e71f9a9a9 2025-01-27)
  2. Wasmer: 5.0.4
  3. wasix is supported

Project B

Use the [cargo wasix build --release] command to compile into a .wasm file.

  1. Rust:2021 rustc 1.84.1 (e71f9a9a9 2025-01-27)
  2. Tokio:https://github.com/wasix-org/tokio.git branch = "wasix-1.35.1"

My Code

Project B

I performed two operations in project B, declared and used the import function [my_host_fn], and used std::thread::spawn to generate a new thread. The code is as follows:
########################################################
#[no_mangle]
extern "C" {
pub fn my_host_fn();
}

#[no_mangle]
pub extern "C" fn _start() {
println!("_start hello hello");
std::thread::spawn(move || println!("std::thread::spawn hello hello"));
unsafe { my_host_fn() };
}
########################################################

Project A

Next is Project A, where I refer to this example:
https://github.com/wasmerio/wasmer/blob/e36b898895922593cd3b9971e5fae5a915951146/examples/wasi_manual_setup.rs

The code is as follows:
########################################################
#[derive(Clone)]
struct Env {}
// Let's declare the Wasm module with the text representation.
let wasm_bytes = std::fs::read("./project_b.wasm")?;

// Create a Store.
let mut store = Store::default();

println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;

println!("Starting `tokio` runtime...");
let runtime = tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()
    .unwrap();
let _guard = runtime.enter();

let mut wasi_env = WasiEnv::builder("hello").finalize(&mut store)?;

let env = FunctionEnv::new(&mut store, Env {});

let mut import_object = wasi_env.import_object_for_all_wasi_versions(&mut store, &module)?;
let memory_type = module.imports().memories().next().map(|a| *a.ty()).unwrap();
let memory = Memory::new(&mut store, memory_type)?;
import_object.define("env", "memory", memory.clone());
import_object.extend(&imports! {
    "env" => {
        "my_host_fn" => Function::new_typed_with_env(&mut store, &env, |env: FunctionEnvMut<Env>|{
             println!("Calling `my_host_fn,my_host_fn`...");
        }),
    }
});

let instance = Instance::new(&mut store, &module, &import_object)?;

wasi_env.initialize_with_memory(&mut store, instance.clone(), Some(memory.clone()), true)?;

println!("Call WASI `xxx` function...");

// And we just call the `_start` function!
let start: TypedFunction<(), ()> =
    instance.exports.get_function("_start")?.typed(&mut store)?;
start.call(&mut store)?;
println!("End Call WASI `xxx` function...");

sleep(Duration::from_secs(100));

wasi_env.on_exit(&mut store, None);

########################################################

Error

i execute WASM using project A, and console error is as follows:
thread '<unnamed>' panicked at /Users/runner/work/rust/rust/wasix-rust/library/std/src/thread/mod.rs:734:29: failed to spawn thread: Os { code: 6, kind: WouldBlock, message: "Resource temporarily unavailable" } note: run with RUST_BACKTRACE=1 environment variable to display a backtrace Error: RuntimeError { source: Wasm { pc: 4443425784, backtrace: 0: <unknown> 1: <unknown> 2: <unknown> 3: <unknown> 4: <unknown> 5: <unknown> 6: <unknown> 7: <unknown> 8: <unknown> , signal_trap: None }, wasm_trace: [] }

and debug it,i found error source:

return Err(LinkError::Import(
import.module().to_string(),
import.name().to_string(),
ImportError::UnknownImport(import.ty().clone()),
));

this image is thread stack when error happened
Image

my conclusion

because [env.my_host_fn] is missing when wasmer execute
the root cause seems when spawn a new thread in wasm, wasmer will create a new instance with new imports ,but did not inherit original instance‘s imports
focus on new_with_store, create new import_object and new memory in new_with_store:

pub fn new_with_store(

my confuse

  1. why spawn a new thread must be auto create new instance by wasmer? and new instance did not inherit from original instance?
  2. If the existing wasmer code is correct, how should I use multithreading and host function calls in wasm at the same time?

Finally, thanks to everyone who helped

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions