Open khalidabuhakmeh opened 2 years ago
Hi @khalidabuhakmeh, big fan 😅
I've discovered that the error message is misleading.
No one wants to use up a thread just to schedule completions of Task.Delay
or equivalent operations, duuh, and this only makes sense if the WASI host supports multiple threads to begin with, which is not true for browser tabs or their workers.
Therefore, you need full bi-directional chatter with the WASI host to pull off a Task.Delay
.
dotnet-wasi-sdk seems to expect the host to implement the so-called wasi-snapshot-preview1 standard, and by the looks of it, there's no "wake-me-up-in-X" in there.
I also think this is the way to solve the problem:
From what I gather, in his comment, Steve was answering a question about how one could emulate Blazor's JSExportAttribute
ability (where you write your own static method and you want to expose it) and possibly how one could call a "custom" function provided by the WASI host.
However, the exact same technique can be used to backfill .NET BCL methods marked extern
. So in a sense, instead of defining custom interop calls, you'd be "lighting up .NET capabilities" that were originally deactivated (with catastrophic and misleading errors).
Funny enough, in the very c file Steve points out, we see SetTimeout itself being declared:
mono_add_internal_call ("System.Threading.TimerQueue::SetTimeout", fake_settimeout);
You should probably import a function, let's call it "set_timeout", thus requiring the WASI host to provide it, by doing something like this:
__attribute__((import_name("start_http_server")))
void start_http_server (MonoObject* dotnet_http_server, int port);
and then fulfill the import in the WASI host.
That being said, running wasmtime from the command line, and passing it the KhalidConsoleApp.wasm won't work anymore, and neither will running the project in the Visual Studio, which I believe is doing the same thing.
That is because wasmtime implements wasi-snapshot-preview1, and even if it supports more than that, we probably didn't match some obscure 'set-timeout' it might be offering either in name or signature.
I think wasmer is in the same boat. All the while, browsers' WebAssembly hosts don't even offer wasi-snapshot-preview1, they're not WASI at all, but they can be taught to offer both this standard + our custom set-timeout. It's not straightforward but it's possible.
A pure For-.NET-By-.NET solution would be using the wasmtime Nuget package and building your own host:
part of the csproj
<ItemGroup> <PackageReference Include="Wasmtime" Version="2.0.2" /> </ItemGroup>
and then do something along the lines of (this is not the end of the story, but from here it should be clear what to look for and what to do):
Program.cs
using System.Reflection; using Wasmtime;
using Engine engine = new();
using Linker linker = new(engine); linker.DefineWasi(); linker.DefineFunction("The module name, gotta do research?", "set-timeout", (int cMillis) => { Task.Delay(TimeSpan.FromMilliseconds(cMillis)).ContinueWith( () => // ... now we need an Export from the Module and that export // should excite the BCL the same way the full blown CLR would do // apparently we don't have any correlation IDs in this whole story // so the CLR must be managing a table of sorts // and this is just a wake up call to check things ) });
using Store store = new(engine); store.SetWasiConfiguration( new WasiConfiguration() .WithInheritedStandardOutput());
const string name = "Runner.ConsoleApp1.wasm";
using var stream = Assembly .GetExecutingAssembly() .GetManifestResourceStream(name)!;
using var module = Wasmtime.Module.FromStream(engine, name, stream);
var instance = linker.Instantiate(store, module);
var _start = instance.GetAction("_start")!; _start();
Results in the following output.
I think the mention of
Mono
is a red-hearing since its likely talking about WASM runtime. Note that the code executes and fails at the call toTask.Delay
.Project Information