Skip to content

Commit ccc5dce

Browse files
Add blocking-based poll_oneoff to support clock_nanosleep
This commit adds a blocking-based `poll_oneoff` implementation to support `clock_nanosleep` in wasi-libc. This implementation is very simple and only supports a single subscription for now but is enough for `clock_nanosleep` to work.
1 parent c807dae commit ccc5dce

File tree

1 file changed

+53
-3
lines changed

1 file changed

+53
-3
lines changed

src/wasi.ts

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,59 @@ export default class WASI {
813813
return wasi.ERRNO_BADF;
814814
}
815815
},
816-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
817-
poll_oneoff(in_, out, nsubscriptions) {
818-
throw "async io not supported";
816+
async poll_oneoff(
817+
in_ptr: number,
818+
out_ptr: number,
819+
nsubscriptions: number,
820+
): Promise<number> {
821+
if (nsubscriptions === 0) {
822+
return wasi.ERRNO_INVAL;
823+
}
824+
// TODO: For now, we only support a single subscription just to be enough for wasi-libc's
825+
// clock_nanosleep.
826+
if (nsubscriptions > 1) {
827+
return wasi.ERRNO_NOTSUP;
828+
}
829+
830+
// Read a subscription from the in buffer
831+
const buffer = new DataView(self.inst.exports.memory.buffer);
832+
const userdata = buffer.getBigUint64(in_ptr, true);
833+
const eventtype = buffer.getUint8(in_ptr + 8);
834+
// TODO: For now, we only support clock subscriptions.
835+
if (eventtype !== wasi.EVENTTYPE_CLOCK) {
836+
return wasi.ERRNO_NOTSUP;
837+
}
838+
const clockid = buffer.getUint32(in_ptr + 16, true);
839+
const timeout = buffer.getBigUint64(in_ptr + 24, true);
840+
const flags = buffer.getUint16(in_ptr + 36, true);
841+
842+
// Select timer
843+
let getNow: (() => bigint) | undefined = undefined;
844+
let error: number = wasi.ERRNO_SUCCESS;
845+
if (clockid === wasi.CLOCKID_MONOTONIC) {
846+
getNow = () => BigInt(Math.round(performance.now() * 1_000_000));
847+
} else if (clockid === wasi.CLOCKID_REALTIME) {
848+
getNow = () => BigInt(new Date().getTime()) * 1_000_000n;
849+
} else {
850+
getNow = () => BigInt(0);
851+
error = wasi.ERRNO_INVAL;
852+
}
853+
854+
// Perform the wait
855+
const endTime =
856+
(flags & wasi.SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) !== 0
857+
? timeout
858+
: getNow() + timeout;
859+
while (endTime > getNow()) {
860+
// block until the timeout is reached
861+
}
862+
863+
// Write an event to the out buffer
864+
buffer.setBigUint64(out_ptr, userdata, true);
865+
buffer.setUint16(out_ptr + 8, error, true);
866+
buffer.setUint8(out_ptr + 10, wasi.EVENTTYPE_CLOCK);
867+
868+
return wasi.ERRNO_SUCCESS;
819869
},
820870
proc_exit(exit_code: number) {
821871
throw new WASIProcExit(exit_code);

0 commit comments

Comments
 (0)