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