bjorn3 / browser_wasi_shim

A WASI shim for in the browser
Apache License 2.0
298 stars 40 forks source link

poll_oneoff - is async io support possible? #14

Open TristanCacqueray opened 1 year ago

TristanCacqueray commented 1 year ago

Hello, thank you for this great library.

When using it for program built with https://gitlab.haskell.org/ghc/ghc-wasm-meta, it is failing early on because of the poll_oneoff "async io not supported" exception. Using return 0 instead makes the program go a bit further, but then it crash again when reading the stdin. Would it be possible to implement this api?

bjorn3 commented 1 year ago

Should be fine to implement. It can't be actual async io, but that isn't needed anyway as an in memory VFS is used, so every operation finishes pretty much instantly.

bjorn3 commented 1 year ago

Would you mind posting an example wasm binary that hits this error? That would help with testing the implementation.

TristanCacqueray commented 1 year ago

Good to hear! You can get a reproducer from https://tristancacqueray.github.io/tiny-game-haskell-wasm/ , where the shim is patched locally to remove the throw. The expected result is that pressing enter should clear and redraw the terminal. The client source is from https://github.com/TristanCacqueray/tiny-game-haskell-wasm/blob/main/client.js

hellwolf commented 1 year ago

Yes, please, I am having the same issue.

bjorn3 commented 1 year ago

I was busy for the past couple of week, but I can probably work on this tomorrow.

hellwolf commented 1 year ago

Appreciated!

bjorn3 commented 1 year ago

I just took a closer look and while

diff --git a/src/wasi.js b/src/wasi.js
index 3a1060f..1c341ae 100644
--- a/src/wasi.js
+++ b/src/wasi.js
@@ -426,6 +426,7 @@ export default class WASI {
                 }
             },
             poll_oneoff(in_, out, nsubscriptions) {
+                return 0;
                 throw "async io not supported";
             },
             proc_exit(exit_code/*: number*/) {

fixes the crash, it now gets stuck in an infinite loop waiting for input that will never come as fd_read returns 0. It isn't possible to block for input on the main thread in the browser.

It should be possible to run the wasm code in a web worker and then in this web worker do an Atomics.wait and Atomics.notify on the main thread when input arrives and use a SharedArrayBuffer for communicating the actual input, but I don't think browser_wasi_shim should do all this work at least right now. Maybe in the future browser_wasi_shim could have it as optional feature.

For now if you want to implement this yourself you can overwrite wasi.wasiImport.poll_oneoff before passing wasi.wasiImport to Webassembly.instantiate.

TristanCacqueray commented 1 year ago

I'm giving the SharedArrayBuffer approach a try with a web worker, and it doesn't seem to ever get to the fd_read call. I guess poll_oneoff needs to do something with its argument, but I can't tell what or how :)

bjorn3 commented 1 year ago

For me making poll_oneoff always return 0 caused the wasm module to call fd_read in an infinite loop. Can I take a look at what you have?

TristanCacqueray commented 1 year ago

@bjorn3 sure, I am using this branch: https://github.com/TristanCacqueray/browser_wasi_shim/tree/worker-example

Please note that I've never used web worker and atomics before. When browsing the dist, in the console I see an infinite loop between poll_oneoff and clock_time_get. I expected to see fd_read and Reading! where I would have hooked the waitForInput implementation.

bjorn3 commented 1 year ago

Looks like poll_oneoff needs to actually return which subscriptions are ready. I managed to hack the following thing together which may help you get further:

```diff diff --git a/examples/worker.html b/examples/worker.html index 10f2918..27a4d8c 100644 --- a/examples/worker.html +++ b/examples/worker.html @@ -4,8 +4,8 @@ - Githubissues.
  • Githubissues is a development platform for aggregating issues.