@ledsun blog

無味の味は佳境に入らざればすなわち知れず

ruby.wasmのKernel#sleepをどう実装したものか?

ruby.wasmを使ってブラウザ上でKernel#sleepを呼ぶとエラーが起きます。

<html>
<body>
  <script
    src="https://cdn.jsdelivr.net/npm/@ruby/head-wasm-wasi@2.4.1-2024-01-05-a/dist/browser.script.iife.js"></script>
  <script type="text/ruby">
    sleep 1
  </script>
</body>
</html>

エラーのスクリーンショット

とりあえずこんなパッチを当てれば動くことはわかっています。

module Kernel
  def sleep(time)
    JS.eval("return new Promise((resolve) => setTimeout(resolve, #{time * 1000}))").await
  end
end

現状Promise#newにコールバックをブロックで渡せないので、JS.evalを使っています。 これは直せると思います。

もう一つ悩みがあります。 JavaScriptsetTimeoutを使っています。 WASIのインターフェースを使ったほうがポータブルになりそうな気がします。

Add a sleep function to the Core · Issue #77 · WebAssembly/WASI · GitHub によると

I'm the current API, the way to implement sleep is to use poll_oneoff, polling for a single __WASI_EVENTTYPE_CLOCK event.

poll_oneoffという関数があるようです。

https://github.com/newpavlov/rust/blob/1e2b711d308be714e6211c125b1a33ac1247f866/src/libstd/sys/wasi/thread.rs#L30-L63をみると、rustではWASI用のThread.sleeppoll_oneoff関数を使って実装しているようです。

これらの情報をみても、ruyb.wasmにどうやって実装したらいいのか皆目見当もつきません。