@volter/browser-wali 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/browser-wali-command.d.ts +22 -0
- package/dist/browser-wali-command.d.ts.map +1 -0
- package/dist/browser-wali-command.js +44 -0
- package/dist/browser-wali-command.js.map +1 -0
- package/dist/capabilities.d.ts +3 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +23 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/coherent-file-locks.d.ts +23 -0
- package/dist/coherent-file-locks.d.ts.map +1 -0
- package/dist/coherent-file-locks.js +134 -0
- package/dist/coherent-file-locks.js.map +1 -0
- package/dist/events.d.ts +30 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +289 -0
- package/dist/events.js.map +1 -0
- package/dist/filesystem-protocol.d.ts +48 -0
- package/dist/filesystem-protocol.d.ts.map +1 -0
- package/dist/filesystem-protocol.js +27 -0
- package/dist/filesystem-protocol.js.map +1 -0
- package/dist/filesystem-remote.d.ts +65 -0
- package/dist/filesystem-remote.d.ts.map +1 -0
- package/dist/filesystem-remote.js +271 -0
- package/dist/filesystem-remote.js.map +1 -0
- package/dist/filesystem-worker.d.ts +2 -0
- package/dist/filesystem-worker.d.ts.map +1 -0
- package/dist/filesystem-worker.js +269 -0
- package/dist/filesystem-worker.js.map +1 -0
- package/dist/filesystem.d.ts +115 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +1179 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +7 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +32 -0
- package/dist/inspect.js.map +1 -0
- package/dist/local-sockets.d.ts +13 -0
- package/dist/local-sockets.d.ts.map +1 -0
- package/dist/local-sockets.js +139 -0
- package/dist/local-sockets.js.map +1 -0
- package/dist/loopback-host.d.ts +14 -0
- package/dist/loopback-host.d.ts.map +1 -0
- package/dist/loopback-host.js +476 -0
- package/dist/loopback-host.js.map +1 -0
- package/dist/loopback-protocol.d.ts +41 -0
- package/dist/loopback-protocol.d.ts.map +1 -0
- package/dist/loopback-protocol.js +2 -0
- package/dist/loopback-protocol.js.map +1 -0
- package/dist/memory.d.ts +39 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +520 -0
- package/dist/memory.js.map +1 -0
- package/dist/module-layout.d.ts +9 -0
- package/dist/module-layout.d.ts.map +1 -0
- package/dist/module-layout.js +105 -0
- package/dist/module-layout.js.map +1 -0
- package/dist/network-protocol.d.ts +43 -0
- package/dist/network-protocol.d.ts.map +1 -0
- package/dist/network-protocol.js +26 -0
- package/dist/network-protocol.js.map +1 -0
- package/dist/network-worker.d.ts +2 -0
- package/dist/network-worker.d.ts.map +1 -0
- package/dist/network-worker.js +943 -0
- package/dist/network-worker.js.map +1 -0
- package/dist/network.d.ts +52 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +427 -0
- package/dist/network.js.map +1 -0
- package/dist/process-adapter.d.ts +14 -0
- package/dist/process-adapter.d.ts.map +1 -0
- package/dist/process-adapter.js +45 -0
- package/dist/process-adapter.js.map +1 -0
- package/dist/process-bridge.d.ts +54 -0
- package/dist/process-bridge.d.ts.map +1 -0
- package/dist/process-bridge.js +150 -0
- package/dist/process-bridge.js.map +1 -0
- package/dist/program.d.ts +49 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +204 -0
- package/dist/program.js.map +1 -0
- package/dist/runtime.d.ts +9 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +528 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shared-pipes.d.ts +44 -0
- package/dist/shared-pipes.d.ts.map +1 -0
- package/dist/shared-pipes.js +306 -0
- package/dist/shared-pipes.js.map +1 -0
- package/dist/snapshot-filesystem.d.ts +31 -0
- package/dist/snapshot-filesystem.d.ts.map +1 -0
- package/dist/snapshot-filesystem.js +247 -0
- package/dist/snapshot-filesystem.js.map +1 -0
- package/dist/stdin.d.ts +36 -0
- package/dist/stdin.d.ts.map +1 -0
- package/dist/stdin.js +143 -0
- package/dist/stdin.js.map +1 -0
- package/dist/symlink.d.ts +8 -0
- package/dist/symlink.d.ts.map +1 -0
- package/dist/symlink.js +66 -0
- package/dist/symlink.js.map +1 -0
- package/dist/system.d.ts +41 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +305 -0
- package/dist/system.js.map +1 -0
- package/dist/thread-coordinator-worker.d.ts +25 -0
- package/dist/thread-coordinator-worker.d.ts.map +1 -0
- package/dist/thread-coordinator-worker.js +49 -0
- package/dist/thread-coordinator-worker.js.map +1 -0
- package/dist/thread-worker.d.ts +2 -0
- package/dist/thread-worker.d.ts.map +1 -0
- package/dist/thread-worker.js +725 -0
- package/dist/thread-worker.js.map +1 -0
- package/dist/threads.d.ts +44 -0
- package/dist/threads.d.ts.map +1 -0
- package/dist/threads.js +154 -0
- package/dist/threads.js.map +1 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/websocket-peer.d.ts +38 -0
- package/dist/websocket-peer.d.ts.map +1 -0
- package/dist/websocket-peer.js +407 -0
- package/dist/websocket-peer.js.map +1 -0
- package/dist/worker-program-protocol.d.ts +71 -0
- package/dist/worker-program-protocol.d.ts.map +1 -0
- package/dist/worker-program-protocol.js +2 -0
- package/dist/worker-program-protocol.js.map +1 -0
- package/dist/worker-program-worker.d.ts +2 -0
- package/dist/worker-program-worker.d.ts.map +1 -0
- package/dist/worker-program-worker.js +109 -0
- package/dist/worker-program-worker.js.map +1 -0
- package/dist/worker-program.d.ts +58 -0
- package/dist/worker-program.d.ts.map +1 -0
- package/dist/worker-program.js +425 -0
- package/dist/worker-program.js.map +1 -0
- package/package.json +23 -0
package/dist/stdin.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { WaliStdin, WaliTerminalSize } from "./types.js";
|
|
2
|
+
/** Main-thread half of a blocking stdin channel shared with a WALI worker. */
|
|
3
|
+
export declare class SharedWaliStdinWriter {
|
|
4
|
+
readonly buffer: SharedArrayBuffer;
|
|
5
|
+
private readonly control;
|
|
6
|
+
private readonly bytes;
|
|
7
|
+
constructor(capacity?: number, buffer?: SharedArrayBuffer);
|
|
8
|
+
write(value: string | Uint8Array): boolean;
|
|
9
|
+
resize(columns: number, rows: number): void;
|
|
10
|
+
close(): void;
|
|
11
|
+
get availableBytes(): number;
|
|
12
|
+
private wake;
|
|
13
|
+
}
|
|
14
|
+
/** Worker-thread half of the shared stdin channel. Reads block without blocking the UI. */
|
|
15
|
+
export declare class SharedWaliStdinReader implements WaliStdin {
|
|
16
|
+
readonly buffer: SharedArrayBuffer;
|
|
17
|
+
private readonly control;
|
|
18
|
+
private readonly bytes;
|
|
19
|
+
constructor(buffer: SharedArrayBuffer);
|
|
20
|
+
read(length: number): Uint8Array;
|
|
21
|
+
poll(): boolean;
|
|
22
|
+
wait(timeoutMilliseconds: number): boolean;
|
|
23
|
+
available(): number;
|
|
24
|
+
generation(): number;
|
|
25
|
+
terminalSize(): WaliTerminalSize;
|
|
26
|
+
}
|
|
27
|
+
export declare class BufferedWaliStdin implements WaliStdin {
|
|
28
|
+
private readonly bytes;
|
|
29
|
+
private offset;
|
|
30
|
+
constructor(bytes: Uint8Array);
|
|
31
|
+
read(length: number): Uint8Array;
|
|
32
|
+
poll(): boolean;
|
|
33
|
+
wait(): boolean;
|
|
34
|
+
available(): number;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=stdin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../src/stdin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAW9D,8EAA8E;AAC9E,qBAAa,qBAAqB;IAChC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAEvB,QAAQ,SAAmB,EAAE,MAAM,CAAC,EAAE,iBAAiB;IAUnE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO;IAc1C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAM3C,KAAK,IAAI,IAAI;IAKb,IAAI,cAAc,IAAI,MAAM,CAM3B;IAED,OAAO,CAAC,IAAI;CAIb;AAED,2FAA2F;AAC3F,qBAAa,qBAAsB,YAAW,SAAS;IAIzC,QAAQ,CAAC,MAAM,EAAE,iBAAiB;IAH9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;gBAEd,MAAM,EAAE,iBAAiB;IAQ9C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU;IAsBhC,IAAI,IAAI,OAAO;IAIf,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,OAAO;IAc1C,SAAS,IAAI,MAAM;IAQnB,UAAU,IAAI,MAAM;IAEpB,YAAY,IAAI,gBAAgB;CAMjC;AAED,qBAAa,iBAAkB,YAAW,SAAS;IAGrC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,OAAO,CAAC,MAAM,CAAK;gBAEU,KAAK,EAAE,UAAU;IAE9C,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU;IAMhC,IAAI,IAAI,OAAO;IACf,IAAI,IAAI,OAAO;IACf,SAAS,IAAI,MAAM;CACpB"}
|
package/dist/stdin.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const READ_INDEX = 0;
|
|
2
|
+
const WRITE_INDEX = 1;
|
|
3
|
+
const CLOSED_INDEX = 2;
|
|
4
|
+
const WAKE_INDEX = 3;
|
|
5
|
+
const ROWS_INDEX = 4;
|
|
6
|
+
const COLUMNS_INDEX = 5;
|
|
7
|
+
const CONTROL_WORDS = 6;
|
|
8
|
+
const DEFAULT_CAPACITY = 256 * 1024;
|
|
9
|
+
/** Main-thread half of a blocking stdin channel shared with a WALI worker. */
|
|
10
|
+
export class SharedWaliStdinWriter {
|
|
11
|
+
buffer;
|
|
12
|
+
control;
|
|
13
|
+
bytes;
|
|
14
|
+
constructor(capacity = DEFAULT_CAPACITY, buffer) {
|
|
15
|
+
if (!Number.isSafeInteger(capacity) || capacity < 2)
|
|
16
|
+
throw new Error("WALI stdin capacity must be at least two bytes.");
|
|
17
|
+
this.buffer = buffer ?? new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * CONTROL_WORDS + capacity);
|
|
18
|
+
if (this.buffer.byteLength !== Int32Array.BYTES_PER_ELEMENT * CONTROL_WORDS + capacity) {
|
|
19
|
+
throw new Error("WALI stdin shared buffer has an invalid size.");
|
|
20
|
+
}
|
|
21
|
+
this.control = new Int32Array(this.buffer, 0, CONTROL_WORDS);
|
|
22
|
+
this.bytes = new Uint8Array(this.buffer, Int32Array.BYTES_PER_ELEMENT * CONTROL_WORDS);
|
|
23
|
+
}
|
|
24
|
+
write(value) {
|
|
25
|
+
const input = typeof value === "string" ? new TextEncoder().encode(value) : value;
|
|
26
|
+
if (input.byteLength === 0)
|
|
27
|
+
return true;
|
|
28
|
+
const read = Atomics.load(this.control, READ_INDEX);
|
|
29
|
+
const write = Atomics.load(this.control, WRITE_INDEX);
|
|
30
|
+
if (input.byteLength > freeBytes(read, write, this.bytes.byteLength))
|
|
31
|
+
return false;
|
|
32
|
+
for (let index = 0; index < input.byteLength; index += 1) {
|
|
33
|
+
this.bytes[(write + index) % this.bytes.byteLength] = input[index];
|
|
34
|
+
}
|
|
35
|
+
Atomics.store(this.control, WRITE_INDEX, (write + input.byteLength) % this.bytes.byteLength);
|
|
36
|
+
this.wake();
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
resize(columns, rows) {
|
|
40
|
+
Atomics.store(this.control, COLUMNS_INDEX, normalizeDimension(columns));
|
|
41
|
+
Atomics.store(this.control, ROWS_INDEX, normalizeDimension(rows));
|
|
42
|
+
this.wake();
|
|
43
|
+
}
|
|
44
|
+
close() {
|
|
45
|
+
Atomics.store(this.control, CLOSED_INDEX, 1);
|
|
46
|
+
this.wake();
|
|
47
|
+
}
|
|
48
|
+
get availableBytes() {
|
|
49
|
+
return availableBytes(Atomics.load(this.control, READ_INDEX), Atomics.load(this.control, WRITE_INDEX), this.bytes.byteLength);
|
|
50
|
+
}
|
|
51
|
+
wake() {
|
|
52
|
+
Atomics.add(this.control, WAKE_INDEX, 1);
|
|
53
|
+
Atomics.notify(this.control, WAKE_INDEX);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Worker-thread half of the shared stdin channel. Reads block without blocking the UI. */
|
|
57
|
+
export class SharedWaliStdinReader {
|
|
58
|
+
buffer;
|
|
59
|
+
control;
|
|
60
|
+
bytes;
|
|
61
|
+
constructor(buffer) {
|
|
62
|
+
this.buffer = buffer;
|
|
63
|
+
if (buffer.byteLength <= Int32Array.BYTES_PER_ELEMENT * CONTROL_WORDS + 1) {
|
|
64
|
+
throw new Error("WALI stdin shared buffer is too small.");
|
|
65
|
+
}
|
|
66
|
+
this.control = new Int32Array(buffer, 0, CONTROL_WORDS);
|
|
67
|
+
this.bytes = new Uint8Array(buffer, Int32Array.BYTES_PER_ELEMENT * CONTROL_WORDS);
|
|
68
|
+
}
|
|
69
|
+
read(length) {
|
|
70
|
+
if (!Number.isSafeInteger(length) || length < 0)
|
|
71
|
+
throw new Error("WALI stdin read length is invalid.");
|
|
72
|
+
if (length === 0)
|
|
73
|
+
return new Uint8Array();
|
|
74
|
+
for (;;) {
|
|
75
|
+
const read = Atomics.load(this.control, READ_INDEX);
|
|
76
|
+
const write = Atomics.load(this.control, WRITE_INDEX);
|
|
77
|
+
const available = availableBytes(read, write, this.bytes.byteLength);
|
|
78
|
+
if (available > 0) {
|
|
79
|
+
const count = Math.min(length, available);
|
|
80
|
+
const result = new Uint8Array(count);
|
|
81
|
+
for (let index = 0; index < count; index += 1) {
|
|
82
|
+
result[index] = this.bytes[(read + index) % this.bytes.byteLength];
|
|
83
|
+
}
|
|
84
|
+
Atomics.store(this.control, READ_INDEX, (read + count) % this.bytes.byteLength);
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
if (Atomics.load(this.control, CLOSED_INDEX) !== 0)
|
|
88
|
+
return new Uint8Array();
|
|
89
|
+
const wake = Atomics.load(this.control, WAKE_INDEX);
|
|
90
|
+
Atomics.wait(this.control, WAKE_INDEX, wake);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
poll() {
|
|
94
|
+
return Atomics.load(this.control, CLOSED_INDEX) !== 0 || this.available() > 0;
|
|
95
|
+
}
|
|
96
|
+
wait(timeoutMilliseconds) {
|
|
97
|
+
if (this.poll())
|
|
98
|
+
return true;
|
|
99
|
+
const wake = Atomics.load(this.control, WAKE_INDEX);
|
|
100
|
+
// Close the race between the readiness check and taking the wait token.
|
|
101
|
+
if (this.poll())
|
|
102
|
+
return true;
|
|
103
|
+
Atomics.wait(this.control, WAKE_INDEX, wake, timeoutMilliseconds < 0 ? undefined : Math.max(0, timeoutMilliseconds));
|
|
104
|
+
return this.poll();
|
|
105
|
+
}
|
|
106
|
+
available() {
|
|
107
|
+
return availableBytes(Atomics.load(this.control, READ_INDEX), Atomics.load(this.control, WRITE_INDEX), this.bytes.byteLength);
|
|
108
|
+
}
|
|
109
|
+
generation() { return Atomics.load(this.control, WAKE_INDEX); }
|
|
110
|
+
terminalSize() {
|
|
111
|
+
return {
|
|
112
|
+
columns: Atomics.load(this.control, COLUMNS_INDEX) || 80,
|
|
113
|
+
rows: Atomics.load(this.control, ROWS_INDEX) || 24,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export class BufferedWaliStdin {
|
|
118
|
+
bytes;
|
|
119
|
+
offset = 0;
|
|
120
|
+
constructor(bytes) {
|
|
121
|
+
this.bytes = bytes;
|
|
122
|
+
}
|
|
123
|
+
read(length) {
|
|
124
|
+
const chunk = this.bytes.slice(this.offset, this.offset + Math.max(0, length));
|
|
125
|
+
this.offset += chunk.byteLength;
|
|
126
|
+
return chunk;
|
|
127
|
+
}
|
|
128
|
+
poll() { return this.offset < this.bytes.byteLength; }
|
|
129
|
+
wait() { return this.poll(); }
|
|
130
|
+
available() { return Math.max(0, this.bytes.byteLength - this.offset); }
|
|
131
|
+
}
|
|
132
|
+
function normalizeDimension(value) {
|
|
133
|
+
if (!Number.isFinite(value))
|
|
134
|
+
return 0;
|
|
135
|
+
return Math.min(65_535, Math.max(1, Math.floor(value)));
|
|
136
|
+
}
|
|
137
|
+
function availableBytes(read, write, capacity) {
|
|
138
|
+
return write >= read ? write - read : capacity - read + write;
|
|
139
|
+
}
|
|
140
|
+
function freeBytes(read, write, capacity) {
|
|
141
|
+
return capacity - availableBytes(read, write, capacity) - 1;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=stdin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stdin.js","sourceRoot":"","sources":["../src/stdin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { WaliFileSystem } from "./types.js";
|
|
2
|
+
/** Stores a Unix link in a file-only snapshot without changing the host VFS schema. */
|
|
3
|
+
export declare function writeWaliSymlink(filesystem: WaliFileSystem, target: string, path: string): void;
|
|
4
|
+
/** Reads a marker-backed link without teaching the underlying VFS a new node type. */
|
|
5
|
+
export declare function readWaliSymlink(filesystem: WaliFileSystem, path: string): string | undefined;
|
|
6
|
+
export declare function resolveWaliSymlinkPath(filesystem: WaliFileSystem, path: string, followFinal?: boolean): string;
|
|
7
|
+
export declare function normalizeWaliAbsolutePath(path: string): string;
|
|
8
|
+
//# sourceMappingURL=symlink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink.d.ts","sourceRoot":"","sources":["../src/symlink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,uFAAuF;AACvF,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,IAAI,CAON;AAED,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQ5F;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,cAAc,EAC1B,IAAI,EAAE,MAAM,EACZ,WAAW,UAAO,GACjB,MAAM,CAqBR;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ9D"}
|
package/dist/symlink.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const MARKER = new TextEncoder().encode("\0supercode-wali-symlink-v1\0");
|
|
2
|
+
const MAXIMUM_DEPTH = 40;
|
|
3
|
+
/** Stores a Unix link in a file-only snapshot without changing the host VFS schema. */
|
|
4
|
+
export function writeWaliSymlink(filesystem, target, path) {
|
|
5
|
+
if (filesystem.existsSync(path))
|
|
6
|
+
throw filesystemError("EEXIST");
|
|
7
|
+
const encodedTarget = new TextEncoder().encode(target);
|
|
8
|
+
const bytes = new Uint8Array(MARKER.byteLength + encodedTarget.byteLength);
|
|
9
|
+
bytes.set(MARKER);
|
|
10
|
+
bytes.set(encodedTarget, MARKER.byteLength);
|
|
11
|
+
filesystem.writeFileSync(path, bytes);
|
|
12
|
+
}
|
|
13
|
+
/** Reads a marker-backed link without teaching the underlying VFS a new node type. */
|
|
14
|
+
export function readWaliSymlink(filesystem, path) {
|
|
15
|
+
if (!filesystem.existsSync(path) || !filesystem.statSync(path).isFile())
|
|
16
|
+
return;
|
|
17
|
+
const bytes = filesystem.readFileSync(path);
|
|
18
|
+
if (bytes.byteLength < MARKER.byteLength)
|
|
19
|
+
return;
|
|
20
|
+
for (let index = 0; index < MARKER.byteLength; index += 1) {
|
|
21
|
+
if (bytes[index] !== MARKER[index])
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(MARKER.byteLength));
|
|
25
|
+
}
|
|
26
|
+
export function resolveWaliSymlinkPath(filesystem, path, followFinal = true) {
|
|
27
|
+
let resolved = path;
|
|
28
|
+
for (let depth = 0; depth < MAXIMUM_DEPTH; depth += 1) {
|
|
29
|
+
const components = resolved.split("/").filter(Boolean);
|
|
30
|
+
let followed = false;
|
|
31
|
+
for (let index = 0; index < components.length; index += 1) {
|
|
32
|
+
if (!followFinal && index === components.length - 1)
|
|
33
|
+
break;
|
|
34
|
+
const candidate = `/${components.slice(0, index + 1).join("/")}`;
|
|
35
|
+
const target = readWaliSymlink(filesystem, candidate);
|
|
36
|
+
if (target === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
const parent = `/${components.slice(0, index).join("/")}`;
|
|
39
|
+
const targetPath = target.startsWith("/")
|
|
40
|
+
? normalizeWaliAbsolutePath(target)
|
|
41
|
+
: normalizeWaliAbsolutePath(`${parent}/${target}`);
|
|
42
|
+
resolved = normalizeWaliAbsolutePath(`${targetPath}/${components.slice(index + 1).join("/")}`);
|
|
43
|
+
followed = true;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
if (!followed)
|
|
47
|
+
return resolved;
|
|
48
|
+
}
|
|
49
|
+
throw filesystemError("ELOOP");
|
|
50
|
+
}
|
|
51
|
+
export function normalizeWaliAbsolutePath(path) {
|
|
52
|
+
const components = [];
|
|
53
|
+
for (const component of path.replaceAll("\\", "/").split("/")) {
|
|
54
|
+
if (!component || component === ".")
|
|
55
|
+
continue;
|
|
56
|
+
if (component === "..")
|
|
57
|
+
components.pop();
|
|
58
|
+
else
|
|
59
|
+
components.push(component);
|
|
60
|
+
}
|
|
61
|
+
return `/${components.join("/")}`;
|
|
62
|
+
}
|
|
63
|
+
function filesystemError(code) {
|
|
64
|
+
return Object.assign(new Error(code), { code });
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=symlink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symlink.js","sourceRoot":"","sources":["../src/symlink.ts"],"names":[],"mappings":"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"}
|
package/dist/system.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { WaliImportHandler, WaliStdin } from "./types.js";
|
|
2
|
+
/** Process-wide exit requested by a WALI pthread through exit_group(2). */
|
|
3
|
+
export declare class WaliPthreadProcessExit extends Error {
|
|
4
|
+
readonly code: number;
|
|
5
|
+
constructor(code: number);
|
|
6
|
+
}
|
|
7
|
+
export declare class WaliSystemHost {
|
|
8
|
+
private readonly memory;
|
|
9
|
+
private readonly pid;
|
|
10
|
+
private readonly terminal?;
|
|
11
|
+
private readonly pthreadFatal?;
|
|
12
|
+
private readonly limits;
|
|
13
|
+
private signalMask;
|
|
14
|
+
private alternateSignalStack;
|
|
15
|
+
private fileCreationMask;
|
|
16
|
+
private readonly sleepWord;
|
|
17
|
+
private termios;
|
|
18
|
+
private termios2;
|
|
19
|
+
constructor(memory: () => WebAssembly.Memory, pid: number, terminal?: WaliStdin | undefined, pthreadFatal?: Int32Array | undefined);
|
|
20
|
+
imports(): Record<string, WaliImportHandler>;
|
|
21
|
+
private bytes;
|
|
22
|
+
private view;
|
|
23
|
+
private range;
|
|
24
|
+
private schedGetAffinity;
|
|
25
|
+
private signalMaskCall;
|
|
26
|
+
private signalStack;
|
|
27
|
+
private clockGetResolution;
|
|
28
|
+
private clockNanosleep;
|
|
29
|
+
private defaultLimit;
|
|
30
|
+
private getLimit;
|
|
31
|
+
private setLimit;
|
|
32
|
+
private processLimit;
|
|
33
|
+
private getUsage;
|
|
34
|
+
private uname;
|
|
35
|
+
private sysinfo;
|
|
36
|
+
private ioctl;
|
|
37
|
+
private umask;
|
|
38
|
+
private futex;
|
|
39
|
+
private throwIfPthreadFailed;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../src/system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAY/D,2EAA2E;AAC3E,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM;CAIlC;AAED,qBAAa,cAAc;IAWvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IAbhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgD;IACvE,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuE;IAEjG,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,QAAQ,CAAsB;gBAGnB,MAAM,EAAE,MAAM,WAAW,CAAC,MAAM,EAChC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,SAAS,YAAA,EACpB,YAAY,CAAC,EAAE,UAAU,YAAA;IAG5C,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAuB5C,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,IAAI;IAEZ,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,cAAc;IA8BtB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,KAAK;IAuCb,OAAO,CAAC,KAAK;IAMb,OAAO,CAAC,KAAK;IAqCb,OAAO,CAAC,oBAAoB;CAO7B"}
|
package/dist/system.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
const EAGAIN = 11n;
|
|
2
|
+
const ESRCH = 3n;
|
|
3
|
+
const EINVAL = 22n;
|
|
4
|
+
const ETIMEDOUT = 110n;
|
|
5
|
+
const FUTEX_COMMAND_MASK = 0x7f;
|
|
6
|
+
const FUTEX_CLOCK_REALTIME = 0x100;
|
|
7
|
+
const FUTEX_WAIT = 0;
|
|
8
|
+
const FUTEX_WAIT_BITSET = 9;
|
|
9
|
+
const encoder = new TextEncoder();
|
|
10
|
+
/** Process-wide exit requested by a WALI pthread through exit_group(2). */
|
|
11
|
+
export class WaliPthreadProcessExit extends Error {
|
|
12
|
+
code;
|
|
13
|
+
constructor(code) {
|
|
14
|
+
super(`WALI pthread requested process exit ${code}.`);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.name = "WaliPthreadProcessExit";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class WaliSystemHost {
|
|
20
|
+
memory;
|
|
21
|
+
pid;
|
|
22
|
+
terminal;
|
|
23
|
+
pthreadFatal;
|
|
24
|
+
limits = new Map();
|
|
25
|
+
signalMask = new Uint8Array(8);
|
|
26
|
+
alternateSignalStack = new Uint8Array(12);
|
|
27
|
+
fileCreationMask = 0o022;
|
|
28
|
+
sleepWord = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));
|
|
29
|
+
termios = new Uint8Array(36);
|
|
30
|
+
termios2 = new Uint8Array(44);
|
|
31
|
+
constructor(memory, pid, terminal, pthreadFatal) {
|
|
32
|
+
this.memory = memory;
|
|
33
|
+
this.pid = pid;
|
|
34
|
+
this.terminal = terminal;
|
|
35
|
+
this.pthreadFatal = pthreadFatal;
|
|
36
|
+
}
|
|
37
|
+
imports() {
|
|
38
|
+
return {
|
|
39
|
+
SYS_sched_getaffinity: (pid, size, mask) => this.schedGetAffinity(Number(pid), Number(size), Number(mask)),
|
|
40
|
+
SYS_rt_sigprocmask: (_how, set, previous, size) => this.signalMaskCall(Number(set), Number(previous), Number(size)),
|
|
41
|
+
SYS_sigaltstack: (stack, previous) => this.signalStack(Number(stack), Number(previous)),
|
|
42
|
+
SYS_clock_getres: (clock, pointer) => this.clockGetResolution(Number(clock), Number(pointer)),
|
|
43
|
+
SYS_clock_nanosleep: (clock, flags, request, remaining) => this.clockNanosleep(Number(clock), Number(flags), Number(request), Number(remaining)),
|
|
44
|
+
SYS_nanosleep: (request, remaining) => this.clockNanosleep(1, 0, Number(request), Number(remaining)),
|
|
45
|
+
SYS_getrlimit: (resource, pointer) => this.getLimit(Number(resource), Number(pointer)),
|
|
46
|
+
SYS_prlimit64: (pid, resource, next, previous) => this.processLimit(Number(pid), Number(resource), Number(next), Number(previous)),
|
|
47
|
+
SYS_setrlimit: (resource, pointer) => this.setLimit(Number(resource), Number(pointer)),
|
|
48
|
+
SYS_getrusage: (who, pointer) => this.getUsage(Number(who), Number(pointer)),
|
|
49
|
+
SYS_uname: (pointer) => this.uname(Number(pointer)),
|
|
50
|
+
SYS_sysinfo: (pointer) => this.sysinfo(Number(pointer)),
|
|
51
|
+
SYS_ioctl: (fd, request, argument) => this.ioctl(Number(fd), Number(request), Number(argument)),
|
|
52
|
+
SYS_umask: (mask) => this.umask(Number(mask)),
|
|
53
|
+
SYS_set_robust_list: () => 0n,
|
|
54
|
+
SYS_futex: (address, operation, value, timeout) => this.futex(Number(address), Number(operation), Number(value), Number(timeout)),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
bytes() { return new Uint8Array(this.memory().buffer); }
|
|
58
|
+
view() { return new DataView(this.memory().buffer); }
|
|
59
|
+
range(pointer, length) {
|
|
60
|
+
if (!Number.isSafeInteger(pointer) || !Number.isSafeInteger(length) || pointer < 0 || length < 0
|
|
61
|
+
|| pointer + length > this.memory().buffer.byteLength) {
|
|
62
|
+
throw new WebAssembly.RuntimeError(`WALI memory access is out of bounds: ${pointer}+${length}.`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
schedGetAffinity(pid, size, pointer) {
|
|
66
|
+
if (pid !== 0 && pid !== this.pid)
|
|
67
|
+
return -ESRCH;
|
|
68
|
+
if (size < 4)
|
|
69
|
+
return -EINVAL;
|
|
70
|
+
this.range(pointer, size);
|
|
71
|
+
this.bytes().fill(0, pointer, pointer + size);
|
|
72
|
+
this.bytes()[pointer] = 1;
|
|
73
|
+
return BigInt(Math.min(size, 8));
|
|
74
|
+
}
|
|
75
|
+
signalMaskCall(set, previous, size) {
|
|
76
|
+
if (size !== 8)
|
|
77
|
+
return -EINVAL;
|
|
78
|
+
if (previous !== 0) {
|
|
79
|
+
this.range(previous, size);
|
|
80
|
+
this.bytes().set(this.signalMask, previous);
|
|
81
|
+
}
|
|
82
|
+
if (set !== 0) {
|
|
83
|
+
this.range(set, size);
|
|
84
|
+
this.signalMask = this.bytes().slice(set, set + size);
|
|
85
|
+
}
|
|
86
|
+
return 0n;
|
|
87
|
+
}
|
|
88
|
+
signalStack(stack, previous) {
|
|
89
|
+
if (previous !== 0) {
|
|
90
|
+
this.range(previous, this.alternateSignalStack.byteLength);
|
|
91
|
+
this.bytes().set(this.alternateSignalStack, previous);
|
|
92
|
+
}
|
|
93
|
+
if (stack !== 0) {
|
|
94
|
+
this.range(stack, this.alternateSignalStack.byteLength);
|
|
95
|
+
this.alternateSignalStack = this.bytes().slice(stack, stack + this.alternateSignalStack.byteLength);
|
|
96
|
+
}
|
|
97
|
+
return 0n;
|
|
98
|
+
}
|
|
99
|
+
clockGetResolution(clock, pointer) {
|
|
100
|
+
if (![0, 1, 2, 3, 4, 7].includes(clock))
|
|
101
|
+
return -EINVAL;
|
|
102
|
+
if (pointer !== 0) {
|
|
103
|
+
this.range(pointer, 16);
|
|
104
|
+
this.view().setBigInt64(pointer, 0n, true);
|
|
105
|
+
this.view().setBigInt64(pointer + 8, 1000000n, true);
|
|
106
|
+
}
|
|
107
|
+
return 0n;
|
|
108
|
+
}
|
|
109
|
+
clockNanosleep(clock, flags, request, remaining) {
|
|
110
|
+
if (![0, 1, 4].includes(clock) || (flags & ~1) !== 0)
|
|
111
|
+
return -EINVAL;
|
|
112
|
+
this.range(request, 16);
|
|
113
|
+
const seconds = this.view().getBigInt64(request, true);
|
|
114
|
+
const nanoseconds = this.view().getBigInt64(request + 8, true);
|
|
115
|
+
if (seconds < 0n || nanoseconds < 0n || nanoseconds >= 1000000000n)
|
|
116
|
+
return -EINVAL;
|
|
117
|
+
let duration = Number(seconds * 1000n + nanoseconds / 1000000n);
|
|
118
|
+
if (flags & 1) {
|
|
119
|
+
const now = clock === 0 ? Date.now() : performanceNow();
|
|
120
|
+
duration = Math.max(0, duration - now);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const deadline = performanceNow() + duration;
|
|
124
|
+
do {
|
|
125
|
+
this.throwIfPthreadFailed();
|
|
126
|
+
Atomics.wait(this.sleepWord, 0, 0, Math.min(100, Math.max(0, deadline - performanceNow())));
|
|
127
|
+
} while (performanceNow() < deadline);
|
|
128
|
+
this.throwIfPthreadFailed();
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (error instanceof WebAssembly.RuntimeError)
|
|
132
|
+
throw error;
|
|
133
|
+
// The main browser thread cannot block. BrowserWaliRuntime runs in a
|
|
134
|
+
// worker, but retain the nonblocking fallback for direct consumers.
|
|
135
|
+
}
|
|
136
|
+
if (remaining !== 0) {
|
|
137
|
+
this.range(remaining, 16);
|
|
138
|
+
this.bytes().fill(0, remaining, remaining + 16);
|
|
139
|
+
}
|
|
140
|
+
return 0n;
|
|
141
|
+
}
|
|
142
|
+
defaultLimit(resource) {
|
|
143
|
+
if (resource < 0 || resource >= 16)
|
|
144
|
+
return;
|
|
145
|
+
if (resource === 7)
|
|
146
|
+
return [65536n, 65536n];
|
|
147
|
+
if (resource === 3)
|
|
148
|
+
return [8n * 1024n * 1024n, 8n * 1024n * 1024n];
|
|
149
|
+
return [0xffffffffffffffffn, 0xffffffffffffffffn];
|
|
150
|
+
}
|
|
151
|
+
getLimit(resource, pointer) {
|
|
152
|
+
const limit = this.limits.get(resource) ?? this.defaultLimit(resource);
|
|
153
|
+
if (!limit)
|
|
154
|
+
return -EINVAL;
|
|
155
|
+
this.range(pointer, 16);
|
|
156
|
+
this.view().setBigUint64(pointer, limit[0], true);
|
|
157
|
+
this.view().setBigUint64(pointer + 8, limit[1], true);
|
|
158
|
+
return 0n;
|
|
159
|
+
}
|
|
160
|
+
setLimit(resource, pointer) {
|
|
161
|
+
if (!this.defaultLimit(resource))
|
|
162
|
+
return -EINVAL;
|
|
163
|
+
this.range(pointer, 16);
|
|
164
|
+
const current = this.view().getBigUint64(pointer, true);
|
|
165
|
+
const maximum = this.view().getBigUint64(pointer + 8, true);
|
|
166
|
+
if (current > maximum)
|
|
167
|
+
return -EINVAL;
|
|
168
|
+
this.limits.set(resource, [current, maximum]);
|
|
169
|
+
return 0n;
|
|
170
|
+
}
|
|
171
|
+
processLimit(pid, resource, next, previous) {
|
|
172
|
+
if (pid !== 0 && pid !== this.pid)
|
|
173
|
+
return -ESRCH;
|
|
174
|
+
if (previous !== 0) {
|
|
175
|
+
const result = this.getLimit(resource, previous);
|
|
176
|
+
if (result !== 0n)
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
return next === 0 ? 0n : this.setLimit(resource, next);
|
|
180
|
+
}
|
|
181
|
+
getUsage(who, pointer) {
|
|
182
|
+
if (who !== -1 && who !== 0 && who !== 1)
|
|
183
|
+
return -EINVAL;
|
|
184
|
+
this.range(pointer, 144);
|
|
185
|
+
this.bytes().fill(0, pointer, pointer + 144);
|
|
186
|
+
return 0n;
|
|
187
|
+
}
|
|
188
|
+
uname(pointer) {
|
|
189
|
+
this.range(pointer, 65 * 6);
|
|
190
|
+
this.bytes().fill(0, pointer, pointer + 65 * 6);
|
|
191
|
+
["Linux", "browser-runtime", "6.1.0-wali", "#1 WALI", "wasm32", "localdomain"].forEach((value, index) => {
|
|
192
|
+
this.bytes().set(encoder.encode(value).subarray(0, 64), pointer + index * 65);
|
|
193
|
+
});
|
|
194
|
+
return 0n;
|
|
195
|
+
}
|
|
196
|
+
sysinfo(pointer) {
|
|
197
|
+
this.range(pointer, 112);
|
|
198
|
+
this.bytes().fill(0, pointer, pointer + 112);
|
|
199
|
+
this.view().setBigInt64(pointer, BigInt(Math.floor(performanceNow() / 1_000)), true);
|
|
200
|
+
this.view().setBigUint64(pointer + 32, BigInt(this.memory().buffer.byteLength), true);
|
|
201
|
+
this.view().setUint32(pointer + 104, 1, true);
|
|
202
|
+
return 0n;
|
|
203
|
+
}
|
|
204
|
+
ioctl(fd, request, argument) {
|
|
205
|
+
if (fd < 0 || fd > 2)
|
|
206
|
+
return -9n;
|
|
207
|
+
const operation = request >>> 0;
|
|
208
|
+
if (operation === 0x5413) {
|
|
209
|
+
this.range(argument, 8);
|
|
210
|
+
const size = this.terminal?.terminalSize?.() ?? { rows: 24, columns: 80 };
|
|
211
|
+
this.view().setUint16(argument, size.rows, true);
|
|
212
|
+
this.view().setUint16(argument + 2, size.columns, true);
|
|
213
|
+
this.view().setUint32(argument + 4, 0, true);
|
|
214
|
+
return 0n;
|
|
215
|
+
}
|
|
216
|
+
if (operation === 0x5401) {
|
|
217
|
+
this.range(argument, 36);
|
|
218
|
+
this.bytes().set(this.termios, argument);
|
|
219
|
+
return 0n;
|
|
220
|
+
}
|
|
221
|
+
if (operation === 0x5402 || operation === 0x5403 || operation === 0x5404) {
|
|
222
|
+
this.range(argument, 36);
|
|
223
|
+
this.termios = this.bytes().slice(argument, argument + 36);
|
|
224
|
+
return 0n;
|
|
225
|
+
}
|
|
226
|
+
if (operation === 0x802c542a) {
|
|
227
|
+
this.range(argument, 44);
|
|
228
|
+
this.bytes().set(this.termios2, argument);
|
|
229
|
+
return 0n;
|
|
230
|
+
}
|
|
231
|
+
if (operation === 0x402c542b || operation === 0x402c542c || operation === 0x402c542d) {
|
|
232
|
+
this.range(argument, 44);
|
|
233
|
+
this.termios2 = this.bytes().slice(argument, argument + 44);
|
|
234
|
+
return 0n;
|
|
235
|
+
}
|
|
236
|
+
if (operation === 0x541b) {
|
|
237
|
+
this.range(argument, 4);
|
|
238
|
+
this.view().setInt32(argument, this.terminal?.available?.() ?? 0, true);
|
|
239
|
+
return 0n;
|
|
240
|
+
}
|
|
241
|
+
return -25n;
|
|
242
|
+
}
|
|
243
|
+
umask(mask) {
|
|
244
|
+
const previous = this.fileCreationMask;
|
|
245
|
+
this.fileCreationMask = mask & 0o777;
|
|
246
|
+
return BigInt(previous);
|
|
247
|
+
}
|
|
248
|
+
futex(address, operation, value, timeoutPointer) {
|
|
249
|
+
if (address % 4 !== 0)
|
|
250
|
+
return -EINVAL;
|
|
251
|
+
this.range(address, 4);
|
|
252
|
+
const words = new Int32Array(this.memory().buffer);
|
|
253
|
+
const index = address / 4;
|
|
254
|
+
const command = operation & FUTEX_COMMAND_MASK;
|
|
255
|
+
if (command === 1 || command === 10)
|
|
256
|
+
return BigInt(Atomics.notify(words, index, Math.max(0, value)));
|
|
257
|
+
if (command !== FUTEX_WAIT && command !== FUTEX_WAIT_BITSET)
|
|
258
|
+
return -38n;
|
|
259
|
+
let timeout;
|
|
260
|
+
if (timeoutPointer !== 0) {
|
|
261
|
+
this.range(timeoutPointer, 16);
|
|
262
|
+
const seconds = this.view().getBigInt64(timeoutPointer, true);
|
|
263
|
+
const nanoseconds = this.view().getBigInt64(timeoutPointer + 8, true);
|
|
264
|
+
if (seconds < 0n || nanoseconds < 0n || nanoseconds >= 1000000000n)
|
|
265
|
+
return -EINVAL;
|
|
266
|
+
const milliseconds = Number(seconds * 1000n + nanoseconds / 1000000n);
|
|
267
|
+
timeout = command === FUTEX_WAIT_BITSET
|
|
268
|
+
? Math.max(0, milliseconds - ((operation & FUTEX_CLOCK_REALTIME) !== 0 ? Date.now() : performanceNow()))
|
|
269
|
+
: milliseconds;
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
if (Atomics.load(words, index) !== value)
|
|
273
|
+
return -EAGAIN;
|
|
274
|
+
const deadline = timeout === undefined ? Number.POSITIVE_INFINITY : performanceNow() + timeout;
|
|
275
|
+
for (;;) {
|
|
276
|
+
this.throwIfPthreadFailed();
|
|
277
|
+
const remaining = deadline - performanceNow();
|
|
278
|
+
if (remaining <= 0)
|
|
279
|
+
return -ETIMEDOUT;
|
|
280
|
+
const result = Atomics.wait(words, index, value, Math.min(100, remaining));
|
|
281
|
+
this.throwIfPthreadFailed();
|
|
282
|
+
if (result === "not-equal")
|
|
283
|
+
return -EAGAIN;
|
|
284
|
+
if (result === "ok")
|
|
285
|
+
return 0n;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
this.throwIfPthreadFailed();
|
|
290
|
+
return -EAGAIN;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
throwIfPthreadFailed() {
|
|
294
|
+
const state = this.pthreadFatal ? Atomics.load(this.pthreadFatal, 0) : 0;
|
|
295
|
+
if (state === 2)
|
|
296
|
+
throw new WaliPthreadProcessExit(Atomics.load(this.pthreadFatal, 2));
|
|
297
|
+
if (state !== 0) {
|
|
298
|
+
throw new WebAssembly.RuntimeError("A WALI pthread terminated unexpectedly.");
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function performanceNow() {
|
|
303
|
+
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=system.js.map
|