|
2 | 2 | //! |
3 | 3 | //! [`wasi-threads`]: https://github.com/WebAssembly/wasi-threads |
4 | 4 |
|
5 | | -use anyhow::{anyhow, Result}; |
| 5 | +use anyhow::{anyhow, bail, Result}; |
6 | 6 | use rand::Rng; |
| 7 | +use std::panic::{catch_unwind, AssertUnwindSafe}; |
7 | 8 | use std::sync::Arc; |
8 | | -use wasmtime::{Caller, Linker, Module, SharedMemory, Store}; |
| 9 | +use std::thread; |
| 10 | +use wasmtime::{Caller, Linker, Module, SharedMemory, Store, ValType}; |
9 | 11 | use wasmtime_wasi::maybe_exit_on_error; |
10 | 12 |
|
11 | 13 | // This name is a function export designated by the wasi-threads specification: |
@@ -36,46 +38,50 @@ impl<T: Clone + Send + 'static> WasiThreadsCtx<T> { |
36 | 38 | let wasi_thread_id = random_thread_id(); |
37 | 39 | let builder = thread::Builder::new().name(format!("wasi-thread-{}", wasi_thread_id)); |
38 | 40 | builder.spawn(move || { |
39 | | - // Convenience function for printing failures, since the `Thread` |
40 | | - // has no way to report a failure to the outer context. |
41 | | - let fail = |msg: String| { |
42 | | - format!( |
43 | | - "wasi-thread-{} exited unsuccessfully: {}", |
44 | | - wasi_thread_id, msg |
45 | | - ) |
46 | | - }; |
| 41 | + // Catch any panic failures in host code; e.g., if a WASI module |
| 42 | + // were to crash, we want all threads to exit, not just this one. |
| 43 | + let result = catch_unwind(AssertUnwindSafe(|| { |
| 44 | + // Each new instance is created in its own store. |
| 45 | + let mut store = Store::new(&module.engine(), host); |
47 | 46 |
|
48 | | - // Each new instance is created in its own store. |
49 | | - let mut store = Store::new(&module.engine(), host); |
50 | | - let instance = linker |
51 | | - .instantiate(&mut store, &module) |
52 | | - .expect(&fail("failed to instantiate".into())); |
53 | | - let thread_entry_point = instance |
54 | | - .get_typed_func::<(i32, i32), ()>(&mut store, WASI_ENTRY_POINT) |
55 | | - .expect(&fail(format!( |
56 | | - "failed to find wasi-threads entry point function: {}", |
57 | | - WASI_ENTRY_POINT |
58 | | - ))); |
| 47 | + // Ideally, we would have already checked much earlier (e.g., |
| 48 | + // `new`) whether the module can be instantiated. Because |
| 49 | + // `Linker::instantiate_pre` requires a `Store` and that is only |
| 50 | + // available now. TODO: |
| 51 | + // https://github.com/bytecodealliance/wasmtime/issues/5675. |
| 52 | + let instance = linker.instantiate(&mut store, &module).expect(&format!( |
| 53 | + "wasi-thread-{} exited unsuccessfully: failed to instantiate", |
| 54 | + wasi_thread_id |
| 55 | + )); |
| 56 | + let thread_entry_point = instance |
| 57 | + .get_typed_func::<(i32, i32), ()>(&mut store, WASI_ENTRY_POINT) |
| 58 | + .unwrap(); |
59 | 59 |
|
60 | | - // Start the thread's entry point. Any traps or calls to |
61 | | - // `proc_exit`, by specification, should end execution for all |
62 | | - // threads. This code uses `process::exit` to do so, which is what |
63 | | - // the user expects from the CLI but probably not in a Wasmtime |
64 | | - // embedding. |
65 | | - log::trace!( |
66 | | - "spawned thread id = {}; calling start function `{}` with: {}", |
67 | | - wasi_thread_id, |
68 | | - WASI_ENTRY_POINT, |
69 | | - thread_start_arg |
70 | | - ); |
71 | | - match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) { |
72 | | - Ok(_) => log::trace!("exiting thread id = {} normally", wasi_thread_id), |
73 | | - Err(e) => { |
74 | | - log::trace!("exiting thread id = {} due to error", wasi_thread_id); |
75 | | - let e = maybe_exit_on_error(e); |
76 | | - eprintln!("Error: {:?}", e); |
77 | | - std::process::exit(1); |
| 60 | + // Start the thread's entry point. Any traps or calls to |
| 61 | + // `proc_exit`, by specification, should end execution for all |
| 62 | + // threads. This code uses `process::exit` to do so, which is what |
| 63 | + // the user expects from the CLI but probably not in a Wasmtime |
| 64 | + // embedding. |
| 65 | + log::trace!( |
| 66 | + "spawned thread id = {}; calling start function `{}` with: {}", |
| 67 | + wasi_thread_id, |
| 68 | + WASI_ENTRY_POINT, |
| 69 | + thread_start_arg |
| 70 | + ); |
| 71 | + match thread_entry_point.call(&mut store, (wasi_thread_id, thread_start_arg)) { |
| 72 | + Ok(_) => log::trace!("exiting thread id = {} normally", wasi_thread_id), |
| 73 | + Err(e) => { |
| 74 | + log::trace!("exiting thread id = {} due to error", wasi_thread_id); |
| 75 | + let e = maybe_exit_on_error(e); |
| 76 | + eprintln!("Error: {:?}", e); |
| 77 | + std::process::exit(1); |
| 78 | + } |
78 | 79 | } |
| 80 | + })); |
| 81 | + |
| 82 | + if let Err(e) = result { |
| 83 | + eprintln!("Error: {:?}", e); |
| 84 | + std::process::exit(1); |
79 | 85 | } |
80 | 86 | })?; |
81 | 87 |
|
|
0 commit comments