Path: blob/main/core/kernel/src/wasm/io-using-atomics.ts
1067 views
/*1Synchronous blocking IO using Atomics and SharedArrayBuffers.23This requires cross-origin isolation, so the two headers have to be set by the4server as follows. This is VERY restrictive, but if you can do this, it's optimal:56"Cross-Origin-Opener-Policy": "same-origin"7"Cross-Origin-Embedder-Policy": "require-corp"8*/910import type { IOProvider } from "./types";11import { SIGINT } from "./constants";12import debug from "debug";13const log = debug("wasm:io-provider");1415interface Buffers {16stdinBuffer: SharedArrayBuffer;17stdinLengthBuffer: SharedArrayBuffer;18outputBuffer: SharedArrayBuffer;19outputLengthBuffer: SharedArrayBuffer;20signalBuffer: SharedArrayBuffer;21}2223export default class IOProviderUsingAtomics implements IOProvider {24private stdinLength: Int32Array;25private stdinUint8Array: Uint8Array;2627private outputLength: Int32Array;28private outputUint8Array: Uint8Array;2930private signalInt32Array: Int32Array;31private buffers: Buffers;3233constructor() {34log("IOProviderUsingAtomics");35const stdinLengthBuffer = new SharedArrayBuffer(4);36this.stdinLength = new Int32Array(stdinLengthBuffer);37// TODO: size?! -- implementation right now will start dropping data at this size, I think.38const stdinBuffer = new SharedArrayBuffer(10000);39this.stdinUint8Array = Buffer.from(stdinBuffer);4041const outputLengthBuffer = new SharedArrayBuffer(4);42this.outputLength = new Int32Array(outputLengthBuffer);43const outputBuffer = new SharedArrayBuffer(10000);44this.outputUint8Array = Buffer.from(outputBuffer);4546const signalBuffer = new SharedArrayBuffer(4);47this.signalInt32Array = new Int32Array(signalBuffer);48this.buffers = {49stdinBuffer,50stdinLengthBuffer,51outputBuffer,52outputLengthBuffer,53signalBuffer,54};55}5657writeToStdin(data: Buffer): void {58log("writeToStdin", data);59// place the new data in the stdinBuffer, so that the worker can receive60// it when it next checks for stdin.61data.copy(this.stdinUint8Array, this.stdinLength[0]);62log(63"setting writeToStdin input buffer size to ",64data.length + this.stdinLength[0]65);66Atomics.store(this.stdinLength, 0, data.length + this.stdinLength[0]);67Atomics.notify(this.stdinLength, 0);68}6970// not really async, but we do this for consistent api with service worker.71async readOutput(): Promise<Buffer> {72if (this.outputUint8Array[0] == 0) {73// locked -- in the process of modifying in the worker thread.74return Buffer.alloc(0);75}76const n = this.outputLength[0];77if (n == 0) {78return Buffer.alloc(0);79}80const data = Buffer.from(81this.outputUint8Array.subarray(0, this.outputLength[0])82);83Atomics.store(this.outputLength, 0, 0);84Atomics.notify(this.outputLength, 0);85return data;86}8788getExtraOptions(): Buffers {89return this.buffers;90}9192signal(sig: number = SIGINT): void {93log("signal", sig);94// tell worker about this signal.95Atomics.store(this.signalInt32Array, 0, sig);96Atomics.notify(this.signalInt32Array, 0);97}98}99100101