Open williammortl opened 10 months ago
It looks like you need to enable WASI for this code to work.
@martindevans thank you so much - I closed this when I realized what a bonehead I was... that said, since you were kind enough to respond, I wonder if you could answer a followup...
I have this multi-threaded C code:
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#define NUM_THREADS 10
void *thread_entry_point(void *ctx) {
int id = (int) ctx;
printf(" in thread %d\n", id);
return 0;
}
extern void launch_threads() {
pthread_t threads[10];
for (int i = 0; i < NUM_THREADS; i++) {
int ret = pthread_create(&threads[i], NULL, &thread_entry_point, (void *) i);
if (ret) {
printf("failed to spawn thread: %s", strerror(ret));
}
}
for (int i = 0; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
}
int main(int argc, char **argv) {
launch_threads();
return 0;
}
I compile it thusly:
$WASI_SDK_DIR/bin/clang --sysroot $WASI_SDK_DIR/share/wasi-sysroot --target=wasm32-wasi-threads -pthread -Wl,--import-memory,--export-memory,--max-memory=67108864 src/threads.c -o bin/threads.wasm
I can then run it without issue:
wasmtime --wasm threads --wasi threads bin/threads.wasm
However, even after (I think) enabling threads in this C# code, it fails:
// See https://aka.ms/new-console-template for more information
using Wasmtime;
var wasi = new WasiConfiguration()
.WithInheritedStandardInput()
.WithInheritedStandardOutput()
.WithInheritedStandardError();
var config = new Config()
.WithWasmThreads(true)
.WithBulkMemory(true)
.WithMultiMemory(true);
using var engine = new Engine(config);
using var store = new Store(engine);
store.SetWasiConfiguration(wasi);
using var linker = new Linker(engine);
linker.DefineWasi();
using var module = Module.FromFile(engine, "threads.wasm");
var instance = linker.Instantiate(store, module);
var run = instance.GetFunction("_start").Invoke();
on the linker.Instantiate line, I get error:
Wasmtime.WasmtimeException: 'unknown import: "env::memory" has not been defined'
Any ideas or tips you could give me?
I really don't know a lot about WASI threads, the following is from some very quick research I just did right now and could definitely be wrong!
It looks like a WASI threads program imports a "shared memory" called env::memory
(ref). According to the error you're getting this has not been defined, so instantiating fails.
Wasmtime has a SharedMemory
struct, so I assume that's what you'd need to add to the Linker make your program work.
However looking through the Wasmtime C-API (which is what wasmtime-dotnet uses to interact with wasmtime) I don't see a mention of the word "shared" anywhere in memory.h or wasi.h. It's possible this can't be done through the C-API.
To follow up to that, there's this comment in Config.h:
Note that threads are largely unimplemented in Wasmtime at this time.
I have a similar issue. An unhandled exception occurred when I ran it from C#.
// zig build-exe main.zig -target wasm32-wasi -OReleaseSmall
const std = @import("std");
pub fn main() void {
std.debug.print("wasm: Hello, world!\n", .{});
}
Console.WriteLine("Hello, World!");
var resourceStream = await Assembly.GetExecutingAssembly().ReadResourceAsync("main.wasm");
var wasiConfig = new WasiConfiguration()
.WithInheritedStandardInput()
.WithInheritedStandardOutput()
.WithInheritedStandardError()
.WithInheritedArgs()
.WithInheritedEnvironment();
using var config = new Config()
.WithDebugInfo(true)
.WithCraneliftDebugVerifier(true)
.WithOptimizationLevel(OptimizationLevel.SpeedAndSize)
.WithWasmThreads(true)
.WithBulkMemory(true)
.WithMultiMemory(true);
using var engine = new Engine(config);
using var linker = new Linker(engine);
using var store = new Store(engine);
using var module = Wasmtime.Module.FromStream(engine, "main.wasm", resourceStream);
store.SetWasiConfiguration(wasiConfig);
linker.DefineWasi();
linker.DefineModule(store,module);
var instance = linker.Instantiate(store, module);
instance.GetAction("_start")?.Invoke(); // line 44 here
Output:
Hello, World!
wasm: Hello, world!
Unhandled exception. Wasmtime.WasmtimeException: error while executing at wasm backtrace:
0: 0xa9 - <unknown>!_start
Caused by:
Exited with i32 exit status 0
at Wasmtime.Function.Invoke(Span`1 argumentsAndResults, StoreContext storeContext)
at Wasmtime.Function.InvokeWithoutReturn(Span`1 arguments, StoreContext storeContext)
at Wasmtime.Function.<>c__DisplayClass171_0.<WrapAction>b__0()
at WasmtimeApp.Program.Main(String[] args) in Program.cs:line 44
at WasmtimeApp.Program.<Main>(String[] args)
Exit code -532,462,766.
The wat is:
(module
(type $t0 (func (param i32)))
(type $t1 (func (param i32 i32 i32 i32) (result i32)))
(type $t2 (func))
(import "wasi_snapshot_preview1" "proc_exit" (func $wasi_snapshot_preview1.proc_exit (type $t0)))
(import "wasi_snapshot_preview1" "fd_write" (func $wasi_snapshot_preview1.fd_write (type $t1)))
(func $_start (export "_start") (type $t2)
(call $f3)
(call $wasi_snapshot_preview1.proc_exit
(i32.const 0))
(unreachable))
(func $f3 (type $t2)
(local $l0 i32) (local $l1 i32)
(global.set $g0
(local.tee $l0
(i32.sub
(global.get $g0)
(i32.const 16))))
(local.set $l1
(i32.const 0))
(block $B0
(br_if $B0
(i32.load8_u offset=1048597
(i32.const 0)))
(i32.store8 offset=1048597
(i32.const 0)
(i32.const 1)))
(block $B1
(loop $L2
(br_if $B1
(i32.eq
(local.get $l1)
(i32.const 20)))
(i32.store offset=8
(local.get $l0)
(i32.sub
(i32.const 20)
(local.get $l1)))
(i32.store offset=4
(local.get $l0)
(i32.add
(local.get $l1)
(i32.const 1048576)))
(br_if $B1
(i32.and
(call $wasi_snapshot_preview1.fd_write
(i32.const 2)
(i32.add
(local.get $l0)
(i32.const 4))
(i32.const 1)
(i32.add
(local.get $l0)
(i32.const 12)))
(i32.const 65535)))
(local.set $l1
(i32.add
(i32.load offset=12
(local.get $l0))
(local.get $l1)))
(br $L2)))
(i32.store8 offset=1048597
(i32.const 0)
(i32.const 0))
(global.set $g0
(i32.add
(local.get $l0)
(i32.const 16))))
(memory $memory (export "memory") 17)
(global $g0 (mut i32) (i32.const 1048576))
(data $d0 (i32.const 1048576) "wasm: Hello, world!\0a\00"))
Hi @peaceshi. When running a WASI program with the .NET bindings, you'll want to catch WasmtimeException
where you invoke the start function and check if ExitCode
on the caught exception is 0, which indicates a successful exit.
ExitCode
will be null when the exception is not from calling proc_exit
. It will also be non-zero in the case of an unsuccessful exit via proc_exit
.
It's a little unfortunate that Zig is calling proc_exit(0)
after the user main as it can simply return from _start
; proc_exit
must be implemented via a trap that gets translated to a .NET exception as execution of the wasm guest must immediately abort.
Hello, I have a Rust hello world app:
I compile it:
and can run it in wasmtime
wasmtime run hello-world.wasm
without issue. However, when I run it in my C# app:and I get this error:
any thoughts?