Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/wasi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ export default class WASI {
in_ptr: number,
out_ptr: number,
nsubscriptions: number,
stored_events_count_ptr: number,
): number {
if (nsubscriptions === 0) {
return wasi.ERRNO_INVAL;
Expand Down Expand Up @@ -852,9 +853,9 @@ export default class WASI {

// Perform the wait
const endTime =
(s.flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0
((s.flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0
? timeout
: getNow() + timeout;
: getNow() + timeout) - s.precision;
while (endTime > getNow()) {
// block until the timeout is reached
}
Expand All @@ -863,6 +864,8 @@ export default class WASI {
const event = new wasi.Event(s.userdata, wasi.ERRNO_SUCCESS, eventtype);
event.write_bytes(buffer, out_ptr);

buffer.setUint32(stored_events_count_ptr, 1, true);

return wasi.ERRNO_SUCCESS;
},
proc_exit(exit_code: number) {
Expand Down
11 changes: 10 additions & 1 deletion src/wasi_defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export class Subscription {
public eventtype: number,
public clockid: number,
public timeout: bigint,
public precision: bigint,
public flags: number,
) {}

Expand All @@ -315,7 +316,8 @@ export class Subscription {
view.getUint8(ptr + 8),
view.getUint32(ptr + 16, true),
view.getBigUint64(ptr + 24, true),
view.getUint16(ptr + 36, true),
view.getBigUint64(ptr + 32, true),
view.getUint16(ptr + 40, true),
);
}
}
Expand All @@ -325,12 +327,19 @@ export class Event {
public userdata: bigint,
public error: number,
public eventtype: number,
// `eventtype::clock` events ignore this fields
public fd_readwrite_nbytes: bigint = 0n,
public fd_readwrite_flags: number = 0,
) {}

write_bytes(view: DataView, ptr: number) {
view.setBigUint64(ptr, this.userdata, true);
view.setUint16(ptr + 8, this.error, true);
view.setUint8(ptr + 10, this.eventtype);
if (this.eventtype !== EVENTTYPE_CLOCK) {
view.setBigUint64(ptr + 16, this.fd_readwrite_nbytes, true);
view.setUint16(ptr + 24, this.fd_readwrite_flags, true);
}
}
}

Expand Down
Binary file modified threads/bun.lockb
Binary file not shown.
Binary file modified threads/examples/bun.lockb
Binary file not shown.
Binary file added threads/examples/common_check/common.wasm
Binary file not shown.
10 changes: 10 additions & 0 deletions threads/examples/common_check/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">

<div id="terminal"></div>

<script type="module" src="./index.ts"></script>
</body>
</html>
60 changes: 60 additions & 0 deletions threads/examples/common_check/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Fd } from "@bjorn3/browser_wasi_shim";
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "xterm-addon-fit";
import { WASIFarm } from "../../src";
import { wait_async_polyfill } from "../../src";

import "@xterm/xterm/css/xterm.css";

wait_async_polyfill();

const term = new Terminal({
convertEol: true,
});
const terminalElement = document.getElementById("terminal");

if (!terminalElement) {
throw new Error("No terminal element found");
}

term.open(terminalElement);

const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
fitAddon.fit();

term.writeln("Initializing...");

class XtermStdio extends Fd {
term: Terminal;

constructor(term: Terminal) {
super();
this.term = term;
}
fd_write(data: Uint8Array) /*: {ret: number, nwritten: number}*/ {
const str = new TextDecoder().decode(data);
this.term.write(str);
console.log(str);
return { ret: 0, nwritten: data.byteLength };
}
}

const farm = new WASIFarm(
new XtermStdio(term),
new XtermStdio(term),
new XtermStdio(term),
[],
);

const worker = new Worker("./worker.ts", { type: "module" });

worker.postMessage({
wasi_ref: farm.get_ref(),
});

worker.onmessage = (e) => {
if (e.data.done) {
term.writeln("All Done!!");
}
};
51 changes: 51 additions & 0 deletions threads/examples/common_check/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// https://doc.rust-lang.org/book/ch16-02-message-passing.html
// rustc +nightly --target wasm32-wasip1-threads main.rs -o common.wasm -Cstrip=debuginfo -Clto=fat
// wasm-opt -Oz --enable-multivalue -o common_opt.wasm common.wasm

use std::thread;

fn main() {
let args = std::env::args().collect::<Vec<_>>();
match args[0].as_str() {
"unreachable" => {
unreachable!();
}
"unreachable_child" => {
thread::spawn(|| {
unreachable!();
});
loop {}
}
"exit" => {
println!("exit {}", args[1]);
std::process::exit(args[1].parse().unwrap());
}
"exit_child" => {
thread::spawn(move || {
println!("exit {}", args[1]);
std::process::exit(args[1].parse().unwrap());
});
loop {}
}
"panic" => {
panic!("panic!");
}
"panic_child" => {
thread::spawn(|| {
panic!("panic!");
});
loop {}
}
"ok" => {
println!("ok");
}
"ok_child" => {
thread::spawn(|| {
println!("ok");
})
.join()
.unwrap();
}
_ => unreachable!(),
}
}
5 changes: 5 additions & 0 deletions threads/examples/common_check/thread_spawn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { thread_spawn_on_worker } from "../../src";

self.onmessage = (event) => {
thread_spawn_on_worker(event.data);
};
78 changes: 78 additions & 0 deletions threads/examples/common_check/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { WASIFarmAnimal } from "../../src";

import { wait_async_polyfill } from "../../src/index.js";

wait_async_polyfill();

self.onmessage = async (e) => {
const { wasi_ref } = e.data;

const wasm = await WebAssembly.compileStreaming(fetch("./common.wasm"));

const run = async (args: string[]) => {
const wasi = new WASIFarmAnimal(
wasi_ref,
args, // args\
[], // env
{
can_thread_spawn: true,
thread_spawn_worker_url: new URL("./thread_spawn.ts", import.meta.url)
.href,
// thread_spawn_worker_url: "./thread_spawn.ts",
thread_spawn_wasm: wasm,
worker_background_worker_url: new URL(
"./worker_background.ts",
import.meta.url,
).href,
},
);

await wasi.wait_worker_background_worker();

try {
const code = await wasi.async_start_on_thread();
console.log(`"${args[0]}" exit code:`, code);
return code;
} catch (e) {
console.error(`"${args[0]}" error:`, e);
return "error";
}
};

const code = await run(["unreachable"]);
if (code !== "error") {
throw new Error("unreachable test failed");
}
const code2 = await run(["unreachable_child"]);
if (code2 !== "error") {
throw new Error("exit test failed");
}
const code3 = await run(["exit", "42"]);
if (code3 !== 42) {
throw new Error("exit test failed");
}
const code4 = await run(["exit_child", "43"]);
if (code4 !== 43) {
throw new Error("exit test failed");
}
const code5 = await run(["panic"]);
if (code5 !== "error") {
throw new Error("panic test failed");
}
const code6 = await run(["panic_child"]);
if (code6 !== "error") {
throw new Error("panic test failed");
}
const code7 = await run(["ok"]);
if (code7 !== 0) {
throw new Error("ok test failed");
}
const code8 = await run(["ok_child"]);
if (code8 !== 0) {
throw new Error("ok test failed");
}

console.log("All tests passed");

self.postMessage({ done: true });
};
8 changes: 8 additions & 0 deletions threads/examples/common_check/worker_background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @ts-ignore
import worker_background_worker from "../node_modules/@oligami/browser_wasi_shim-threads/dist/worker_background_worker.min.js";

import { wait_async_polyfill } from "../../src/index.js";

wait_async_polyfill();

worker_background_worker();
Loading
Loading