@ai-ecoverse/slicc-kernel 1.54.2 → 1.54.4
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/README.md +2 -2
- package/dist/kernel-worker.js +973 -486
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +247 -65
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +1073 -586
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +247 -65
- package/dist/process-worker.js.map +3 -3
- package/package.json +3 -3
package/dist/node.js
CHANGED
|
@@ -329,6 +329,32 @@ function bytesSource(data) {
|
|
|
329
329
|
}
|
|
330
330
|
});
|
|
331
331
|
}
|
|
332
|
+
function memoryFile(data, path, position = 0) {
|
|
333
|
+
let offset = position;
|
|
334
|
+
return new OpenFile({
|
|
335
|
+
read: async (max) => {
|
|
336
|
+
const out = data.subarray(offset, offset + max);
|
|
337
|
+
offset += out.length;
|
|
338
|
+
return out;
|
|
339
|
+
},
|
|
340
|
+
pread: async (max, at) => data.subarray(at, at + max),
|
|
341
|
+
seek: async (by, whence) => {
|
|
342
|
+
const at = (whence === 1 ? offset : whence === 2 ? data.length : 0) + by;
|
|
343
|
+
if (at < 0) throw new KernelError("EINVAL");
|
|
344
|
+
offset = at;
|
|
345
|
+
return at;
|
|
346
|
+
},
|
|
347
|
+
pwrite: async () => {
|
|
348
|
+
throw new KernelError("EBADF");
|
|
349
|
+
},
|
|
350
|
+
resize: async () => {
|
|
351
|
+
throw new KernelError("EBADF");
|
|
352
|
+
},
|
|
353
|
+
stat: async () => ({ path, size: data.length }),
|
|
354
|
+
close: () => {
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
332
358
|
function sinkFile(onData) {
|
|
333
359
|
return new OpenFile({
|
|
334
360
|
write: async (bytes) => {
|
|
@@ -5866,179 +5892,6 @@ function attachSyncSabResponder(port, sab, token, opts) {
|
|
|
5866
5892
|
};
|
|
5867
5893
|
}
|
|
5868
5894
|
|
|
5869
|
-
// src/kernel/host-ops.ts
|
|
5870
|
-
var HOST_OPS = [
|
|
5871
|
-
"lock",
|
|
5872
|
-
"unlock",
|
|
5873
|
-
"async-submit",
|
|
5874
|
-
"async-wait",
|
|
5875
|
-
"async-take",
|
|
5876
|
-
"async-resolve",
|
|
5877
|
-
"async-hold",
|
|
5878
|
-
"async-cancel",
|
|
5879
|
-
"async-close"
|
|
5880
|
-
];
|
|
5881
|
-
var json3 = (value) => ({ ok: true, kind: "json", json: value });
|
|
5882
|
-
var done2 = { ok: true, kind: "void" };
|
|
5883
|
-
var LockTable = class {
|
|
5884
|
-
held = /* @__PURE__ */ new Map();
|
|
5885
|
-
lock(pid, path, exclusive, fd) {
|
|
5886
|
-
const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
|
|
5887
|
-
for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
|
|
5888
|
-
const mine = holders.get(pid) ?? { exclusive, fds: /* @__PURE__ */ new Set() };
|
|
5889
|
-
mine.exclusive = exclusive;
|
|
5890
|
-
mine.fds.add(fd);
|
|
5891
|
-
holders.set(pid, mine);
|
|
5892
|
-
this.held.set(path, holders);
|
|
5893
|
-
return true;
|
|
5894
|
-
}
|
|
5895
|
-
unlock(pid, path) {
|
|
5896
|
-
const holders = this.held.get(path);
|
|
5897
|
-
holders?.delete(pid);
|
|
5898
|
-
if (holders?.size === 0) this.held.delete(path);
|
|
5899
|
-
}
|
|
5900
|
-
closed(pid, fd) {
|
|
5901
|
-
for (const [path, holders] of [...this.held]) {
|
|
5902
|
-
const mine = holders.get(pid);
|
|
5903
|
-
if (mine?.fds.delete(fd) && mine.fds.size === 0) this.unlock(pid, path);
|
|
5904
|
-
}
|
|
5905
|
-
}
|
|
5906
|
-
release(pid) {
|
|
5907
|
-
for (const path of [...this.held.keys()]) this.unlock(pid, path);
|
|
5908
|
-
}
|
|
5909
|
-
};
|
|
5910
|
-
var AsyncOps = class {
|
|
5911
|
-
next = 1;
|
|
5912
|
-
results = /* @__PURE__ */ new Map();
|
|
5913
|
-
ready = [];
|
|
5914
|
-
running = /* @__PURE__ */ new Map();
|
|
5915
|
-
waiters = /* @__PURE__ */ new Set();
|
|
5916
|
-
closed = false;
|
|
5917
|
-
run;
|
|
5918
|
-
onReady;
|
|
5919
|
-
constructor(run2, onReady) {
|
|
5920
|
-
this.run = run2;
|
|
5921
|
-
this.onReady = onReady;
|
|
5922
|
-
}
|
|
5923
|
-
submit(req) {
|
|
5924
|
-
const id2 = this.hold();
|
|
5925
|
-
const running = new AbortController();
|
|
5926
|
-
this.running.set(id2, running);
|
|
5927
|
-
this.run(req, running.signal).then(
|
|
5928
|
-
(result) => this.complete(id2, result),
|
|
5929
|
-
(err) => this.complete(id2, { ok: false, errno: "EIO", message: String(err) })
|
|
5930
|
-
);
|
|
5931
|
-
return id2;
|
|
5932
|
-
}
|
|
5933
|
-
resolve(value) {
|
|
5934
|
-
const id2 = this.hold();
|
|
5935
|
-
this.complete(id2, json3(value));
|
|
5936
|
-
return id2;
|
|
5937
|
-
}
|
|
5938
|
-
hold() {
|
|
5939
|
-
const id2 = this.next++;
|
|
5940
|
-
this.results.set(id2, void 0);
|
|
5941
|
-
return id2;
|
|
5942
|
-
}
|
|
5943
|
-
take(id2) {
|
|
5944
|
-
if (!this.results.has(id2)) throw new KernelError("EINVAL");
|
|
5945
|
-
const result = this.results.get(id2);
|
|
5946
|
-
if (!result) throw new KernelError("EAGAIN");
|
|
5947
|
-
this.forget(id2);
|
|
5948
|
-
return result;
|
|
5949
|
-
}
|
|
5950
|
-
cancel(id2) {
|
|
5951
|
-
this.running.get(id2)?.abort();
|
|
5952
|
-
this.forget(id2);
|
|
5953
|
-
}
|
|
5954
|
-
forget(id2) {
|
|
5955
|
-
this.running.delete(id2);
|
|
5956
|
-
this.results.delete(id2);
|
|
5957
|
-
const at = this.ready.indexOf(id2);
|
|
5958
|
-
if (at >= 0) this.ready.splice(at, 1);
|
|
5959
|
-
}
|
|
5960
|
-
async wait(timeoutMs, signal) {
|
|
5961
|
-
for (; ; ) {
|
|
5962
|
-
if (this.closed) return -1;
|
|
5963
|
-
const id2 = this.ready.shift();
|
|
5964
|
-
if (id2 !== void 0) return id2;
|
|
5965
|
-
if (timeoutMs !== void 0 && timeoutMs <= 0) return 0;
|
|
5966
|
-
const woke = await this.sleep(timeoutMs, signal);
|
|
5967
|
-
if (!woke) return 0;
|
|
5968
|
-
}
|
|
5969
|
-
}
|
|
5970
|
-
close() {
|
|
5971
|
-
this.closed = true;
|
|
5972
|
-
this.wake();
|
|
5973
|
-
}
|
|
5974
|
-
sleep(timeoutMs, signal) {
|
|
5975
|
-
return new Promise((resolve, reject) => {
|
|
5976
|
-
let timer;
|
|
5977
|
-
const cleanup = () => {
|
|
5978
|
-
clearTimeout(timer);
|
|
5979
|
-
this.waiters.delete(wake);
|
|
5980
|
-
signal.removeEventListener("abort", abort);
|
|
5981
|
-
};
|
|
5982
|
-
const wake = () => {
|
|
5983
|
-
cleanup();
|
|
5984
|
-
resolve(true);
|
|
5985
|
-
};
|
|
5986
|
-
const abort = () => {
|
|
5987
|
-
cleanup();
|
|
5988
|
-
reject(new KernelError("EINTR"));
|
|
5989
|
-
};
|
|
5990
|
-
this.waiters.add(wake);
|
|
5991
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
5992
|
-
if (timeoutMs !== void 0) {
|
|
5993
|
-
timer = setTimeout(() => {
|
|
5994
|
-
cleanup();
|
|
5995
|
-
resolve(false);
|
|
5996
|
-
}, timeoutMs);
|
|
5997
|
-
}
|
|
5998
|
-
});
|
|
5999
|
-
}
|
|
6000
|
-
complete(id2, result) {
|
|
6001
|
-
this.running.delete(id2);
|
|
6002
|
-
if (!this.results.has(id2)) return;
|
|
6003
|
-
this.results.set(id2, result);
|
|
6004
|
-
this.ready.push(id2);
|
|
6005
|
-
this.wake();
|
|
6006
|
-
this.onReady?.();
|
|
6007
|
-
}
|
|
6008
|
-
wake() {
|
|
6009
|
-
for (const wake of [...this.waiters]) wake();
|
|
6010
|
-
}
|
|
6011
|
-
};
|
|
6012
|
-
async function hostSyscall(req, ctx) {
|
|
6013
|
-
switch (req.op) {
|
|
6014
|
-
case "lock":
|
|
6015
|
-
if (!ctx.locks) throw new KernelError("ENOSYS");
|
|
6016
|
-
if (!ctx.locks.lock(ctx.pid, req.path, req.exclusive, req.fd))
|
|
6017
|
-
throw new KernelError("EAGAIN");
|
|
6018
|
-
return done2;
|
|
6019
|
-
case "unlock":
|
|
6020
|
-
ctx.locks?.unlock(ctx.pid, req.path);
|
|
6021
|
-
return done2;
|
|
6022
|
-
case "async-submit":
|
|
6023
|
-
if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
|
|
6024
|
-
return json3(ctx.ops.submit(req.req));
|
|
6025
|
-
case "async-wait":
|
|
6026
|
-
return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking()));
|
|
6027
|
-
case "async-take":
|
|
6028
|
-
return ctx.ops.take(req.id);
|
|
6029
|
-
case "async-resolve":
|
|
6030
|
-
return json3(ctx.ops.resolve(req.value));
|
|
6031
|
-
case "async-hold":
|
|
6032
|
-
return json3(ctx.ops.hold());
|
|
6033
|
-
case "async-cancel":
|
|
6034
|
-
ctx.ops.cancel(req.id);
|
|
6035
|
-
return done2;
|
|
6036
|
-
case "async-close":
|
|
6037
|
-
ctx.ops.close();
|
|
6038
|
-
return done2;
|
|
6039
|
-
}
|
|
6040
|
-
}
|
|
6041
|
-
|
|
6042
5895
|
// src/kernel/net/loopback-names.ts
|
|
6043
5896
|
var HOST_LOOPBACK = "host.slicc.internal";
|
|
6044
5897
|
var HOST_LOOPBACK_ADDRESS = [10, 0, 2, 2];
|
|
@@ -6066,67 +5919,818 @@ function ownNames(hostname) {
|
|
|
6066
5919
|
return [.../* @__PURE__ */ new Set([hostname.toLowerCase(), ...LIBC_HOSTNAMES])];
|
|
6067
5920
|
}
|
|
6068
5921
|
|
|
6069
|
-
// src/
|
|
6070
|
-
var
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
};
|
|
6082
|
-
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
6083
|
-
"connection",
|
|
6084
|
-
"keep-alive",
|
|
6085
|
-
"proxy-connection",
|
|
6086
|
-
"proxy-authenticate",
|
|
6087
|
-
"proxy-authorization",
|
|
6088
|
-
"te",
|
|
6089
|
-
"trailer",
|
|
6090
|
-
"transfer-encoding",
|
|
6091
|
-
"upgrade"
|
|
6092
|
-
]);
|
|
6093
|
-
var REQUEST_OWN = /* @__PURE__ */ new Set(["host", "content-length", "expect"]);
|
|
6094
|
-
var Budget = class {
|
|
6095
|
-
free;
|
|
6096
|
-
waiters = [];
|
|
6097
|
-
constructor(free) {
|
|
6098
|
-
this.free = free;
|
|
5922
|
+
// src/process/process-fds.ts
|
|
5923
|
+
var field2 = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
|
|
5924
|
+
function mountTable(mounts = []) {
|
|
5925
|
+
const root = globalThis.navigator?.storage ? "opfs" : "memory";
|
|
5926
|
+
const lines2 = [`${root} / ${root} rw 0 0`, "devfs /dev devfs rw 0 0", "proc /proc proc rw 0 0"];
|
|
5927
|
+
for (const m of mounts) {
|
|
5928
|
+
const options = Object.entries(m.options).map(([k, v]) => v === "" ? k : `${k}=${v}`);
|
|
5929
|
+
if (m.state !== "ok") options.push(m.state);
|
|
5930
|
+
const access = options.includes("ro") ? [] : ["rw"];
|
|
5931
|
+
lines2.push(
|
|
5932
|
+
`${field2(m.source)} ${field2(m.target)} ${m.type} ${[...access, ...options].join(",")} 0 0`
|
|
5933
|
+
);
|
|
6099
5934
|
}
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
5935
|
+
return `${lines2.join("\n")}
|
|
5936
|
+
`;
|
|
5937
|
+
}
|
|
5938
|
+
|
|
5939
|
+
// src/process/procfs.ts
|
|
5940
|
+
var HZ = 100;
|
|
5941
|
+
var KIB = 1024;
|
|
5942
|
+
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
5943
|
+
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
5944
|
+
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
|
|
5945
|
+
function commOf(info) {
|
|
5946
|
+
const name2 = info.argv[0] ?? "";
|
|
5947
|
+
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
5948
|
+
}
|
|
5949
|
+
function ttyNumber(tty) {
|
|
5950
|
+
const pts = tty && /^\/dev\/pts\/(\d+)$/.exec(tty);
|
|
5951
|
+
if (pts) return 136 << 8 | Number(pts[1]);
|
|
5952
|
+
const vt = tty && /^\/dev\/tty(\d+)$/.exec(tty);
|
|
5953
|
+
return vt ? 4 << 8 | Number(vt[1]) : 0;
|
|
5954
|
+
}
|
|
5955
|
+
function pages(bytes) {
|
|
5956
|
+
return Math.ceil(bytes / 4096);
|
|
5957
|
+
}
|
|
5958
|
+
function ticks(ms) {
|
|
5959
|
+
return Math.max(0, Math.floor(ms * HZ / 1e3));
|
|
5960
|
+
}
|
|
5961
|
+
function pidStat(info, boot) {
|
|
5962
|
+
const fields = [
|
|
5963
|
+
info.pid,
|
|
5964
|
+
`(${commOf(info)})`,
|
|
5965
|
+
info.state,
|
|
5966
|
+
info.ppid,
|
|
5967
|
+
info.pgid,
|
|
5968
|
+
info.sid,
|
|
5969
|
+
ttyNumber(info.tty),
|
|
5970
|
+
info.tty ? info.pgid : -1,
|
|
5971
|
+
4194304,
|
|
5972
|
+
0,
|
|
5973
|
+
0,
|
|
5974
|
+
0,
|
|
5975
|
+
0,
|
|
5976
|
+
0,
|
|
5977
|
+
0,
|
|
5978
|
+
0,
|
|
5979
|
+
0,
|
|
5980
|
+
20,
|
|
5981
|
+
0,
|
|
5982
|
+
1,
|
|
5983
|
+
0,
|
|
5984
|
+
ticks(info.started - boot),
|
|
5985
|
+
info.memory,
|
|
5986
|
+
pages(info.memory),
|
|
5987
|
+
"18446744073709551615",
|
|
5988
|
+
...Array(12).fill(0),
|
|
5989
|
+
17,
|
|
5990
|
+
0,
|
|
5991
|
+
0,
|
|
5992
|
+
0,
|
|
5993
|
+
0,
|
|
5994
|
+
0,
|
|
5995
|
+
0,
|
|
5996
|
+
...Array(7).fill(0),
|
|
5997
|
+
0
|
|
5998
|
+
];
|
|
5999
|
+
return `${fields.join(" ")}
|
|
6000
|
+
`;
|
|
6001
|
+
}
|
|
6002
|
+
var sigMask = (mask = 0) => (mask >>> 1).toString(16).padStart(16, "0");
|
|
6003
|
+
function pidStatus(info) {
|
|
6004
|
+
const state = info.state === "Z" ? "Z (zombie)" : "S (sleeping)";
|
|
6005
|
+
const c = info.cred ?? ROOT;
|
|
6006
|
+
const ids = (r, e, s) => `${r} ${e} ${s} ${e}`;
|
|
6007
|
+
return [
|
|
6008
|
+
`Name: ${commOf(info)}`,
|
|
6009
|
+
`Umask: ${(info.umask ?? 18).toString(8).padStart(4, "0")}`,
|
|
6010
|
+
`State: ${state}`,
|
|
6011
|
+
`Tgid: ${info.pid}`,
|
|
6012
|
+
"Ngid: 0",
|
|
6013
|
+
`Pid: ${info.pid}`,
|
|
6014
|
+
`PPid: ${info.ppid}`,
|
|
6015
|
+
"TracerPid: 0",
|
|
6016
|
+
`Uid: ${ids(c.ruid, c.euid, c.suid)}`,
|
|
6017
|
+
`Gid: ${ids(c.rgid, c.egid, c.sgid)}`,
|
|
6018
|
+
"FDSize: 64",
|
|
6019
|
+
`VmSize: ${Math.ceil(info.memory / KIB)} kB`,
|
|
6020
|
+
`VmRSS: ${Math.ceil(info.memory / KIB)} kB`,
|
|
6021
|
+
`Groups: ${c.groups.join(" ")}`,
|
|
6022
|
+
`NSpid: ${info.pid}`,
|
|
6023
|
+
`NSpgid: ${info.pgid}`,
|
|
6024
|
+
`NSsid: ${info.sid}`,
|
|
6025
|
+
"Threads: 1",
|
|
6026
|
+
"SigQ: 0/0",
|
|
6027
|
+
"SigPnd: 0000000000000000",
|
|
6028
|
+
"ShdPnd: 0000000000000000",
|
|
6029
|
+
"SigBlk: 0000000000000000",
|
|
6030
|
+
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
6031
|
+
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
6032
|
+
""
|
|
6033
|
+
].join("\n");
|
|
6034
|
+
}
|
|
6035
|
+
function pidFile(name2, info, boot) {
|
|
6036
|
+
if (name2 === "cmdline") return info.state === "Z" ? "" : `${info.argv.join("\0")}\0`;
|
|
6037
|
+
if (name2 === "comm") return `${commOf(info)}
|
|
6038
|
+
`;
|
|
6039
|
+
if (name2 === "stat") return pidStat(info, boot);
|
|
6040
|
+
if (name2 === "statm") {
|
|
6041
|
+
const p = pages(info.memory);
|
|
6042
|
+
return `${p} ${p} 0 0 0 ${p} 0
|
|
6043
|
+
`;
|
|
6113
6044
|
}
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6045
|
+
return pidStatus(info);
|
|
6046
|
+
}
|
|
6047
|
+
function memoryInfo(source, used = 0) {
|
|
6048
|
+
const total = source.deviceMemory ? source.deviceMemory * KIB * KIB * KIB : FALLBACK_MEMORY;
|
|
6049
|
+
const free = Math.max(0, total - used - (source.usedHeap ?? 0));
|
|
6050
|
+
const kb = (bytes) => `${Math.floor(bytes / KIB)} kB`;
|
|
6051
|
+
return [
|
|
6052
|
+
["MemTotal", kb(total)],
|
|
6053
|
+
["MemFree", kb(free)],
|
|
6054
|
+
["MemAvailable", kb(free)],
|
|
6055
|
+
["Buffers", kb(0)],
|
|
6056
|
+
["Cached", kb(0)],
|
|
6057
|
+
["SwapCached", kb(0)],
|
|
6058
|
+
["Shmem", kb(0)],
|
|
6059
|
+
["SReclaimable", kb(0)],
|
|
6060
|
+
["SwapTotal", kb(0)],
|
|
6061
|
+
["SwapFree", kb(0)]
|
|
6062
|
+
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
6063
|
+
}
|
|
6064
|
+
function systemFile(name2, listing, now, memory) {
|
|
6065
|
+
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
6066
|
+
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
6067
|
+
`;
|
|
6068
|
+
if (name2 === "meminfo") {
|
|
6069
|
+
return memoryInfo(
|
|
6070
|
+
memory,
|
|
6071
|
+
listing.processes.reduce((sum, p) => sum + p.memory, 0)
|
|
6072
|
+
);
|
|
6119
6073
|
}
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
} catch {
|
|
6126
|
-
return void 0;
|
|
6074
|
+
const live = listing.processes.filter((p) => p.state !== "Z");
|
|
6075
|
+
if (name2 === "loadavg") {
|
|
6076
|
+
const last = Math.max(0, ...listing.processes.map((p) => p.pid));
|
|
6077
|
+
return `0.00 0.00 0.00 1/${live.length} ${last}
|
|
6078
|
+
`;
|
|
6127
6079
|
}
|
|
6080
|
+
const idle = ticks(now - listing.boot);
|
|
6081
|
+
return [
|
|
6082
|
+
`cpu 0 0 0 ${idle} 0 0 0 0 0 0`,
|
|
6083
|
+
`cpu0 0 0 0 ${idle} 0 0 0 0 0 0`,
|
|
6084
|
+
"intr 0",
|
|
6085
|
+
"ctxt 0",
|
|
6086
|
+
`btime ${Math.floor(listing.boot / 1e3)}`,
|
|
6087
|
+
`processes ${listing.processes.length}`,
|
|
6088
|
+
"procs_running 1",
|
|
6089
|
+
"procs_blocked 0",
|
|
6090
|
+
""
|
|
6091
|
+
].join("\n");
|
|
6092
|
+
}
|
|
6093
|
+
function memorySource(scope = globalThis) {
|
|
6094
|
+
const nav = scope.navigator;
|
|
6095
|
+
const perf = scope.performance;
|
|
6096
|
+
const deviceMemory = nav?.deviceMemory;
|
|
6097
|
+
const used = perf?.memory?.usedJSHeapSize;
|
|
6098
|
+
return {
|
|
6099
|
+
...typeof deviceMemory === "number" && deviceMemory > 0 ? { deviceMemory } : {},
|
|
6100
|
+
...typeof used === "number" ? { usedHeap: used } : {}
|
|
6101
|
+
};
|
|
6128
6102
|
}
|
|
6129
|
-
|
|
6103
|
+
|
|
6104
|
+
// src/fs/pages.ts
|
|
6105
|
+
var PAGE = 64 * 1024;
|
|
6106
|
+
var READAHEAD = 1024 * 1024;
|
|
6107
|
+
var CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
6108
|
+
var WRITEBACK = 8 * 1024 * 1024;
|
|
6109
|
+
var RUN = 1024 * 1024;
|
|
6110
|
+
var Pages = class {
|
|
6111
|
+
length;
|
|
6112
|
+
stored;
|
|
6113
|
+
shrink;
|
|
6114
|
+
pages = /* @__PURE__ */ new Map();
|
|
6115
|
+
dirty = /* @__PURE__ */ new Set();
|
|
6116
|
+
free = [];
|
|
6117
|
+
pinned = false;
|
|
6118
|
+
constructor(size) {
|
|
6119
|
+
this.length = size;
|
|
6120
|
+
this.stored = size;
|
|
6121
|
+
}
|
|
6122
|
+
get dirtyBytes() {
|
|
6123
|
+
return this.dirty.size * PAGE;
|
|
6124
|
+
}
|
|
6125
|
+
get changed() {
|
|
6126
|
+
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
6127
|
+
}
|
|
6128
|
+
missing(at, length2) {
|
|
6129
|
+
this.evict();
|
|
6130
|
+
const end = Math.min(this.stored, at + length2, this.length);
|
|
6131
|
+
const runs = [];
|
|
6132
|
+
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
6133
|
+
if (this.pages.has(page)) continue;
|
|
6134
|
+
const last2 = runs[runs.length - 1];
|
|
6135
|
+
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
6136
|
+
else runs.push([page * PAGE, PAGE]);
|
|
6137
|
+
}
|
|
6138
|
+
const last = runs[runs.length - 1];
|
|
6139
|
+
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
6140
|
+
return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
|
|
6141
|
+
}
|
|
6142
|
+
partial(at, length2) {
|
|
6143
|
+
if (length2 === 0) return [];
|
|
6144
|
+
this.evict();
|
|
6145
|
+
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
|
|
6146
|
+
const runs = [];
|
|
6147
|
+
for (const page of edges) {
|
|
6148
|
+
const start2 = page * PAGE;
|
|
6149
|
+
const covered = at <= start2 && at + length2 >= start2 + PAGE;
|
|
6150
|
+
if (covered || this.pages.has(page) || start2 >= this.stored) continue;
|
|
6151
|
+
runs.push([start2, Math.min(PAGE, this.stored - start2)]);
|
|
6152
|
+
}
|
|
6153
|
+
return runs;
|
|
6154
|
+
}
|
|
6155
|
+
fill(start2, bytes) {
|
|
6156
|
+
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
6157
|
+
const page = (start2 + at) / PAGE;
|
|
6158
|
+
if (this.pages.has(page)) continue;
|
|
6159
|
+
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
6160
|
+
const fresh = this.take(part.length);
|
|
6161
|
+
fresh.set(part);
|
|
6162
|
+
this.pages.set(page, fresh);
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
read(at, length2) {
|
|
6166
|
+
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
|
|
6167
|
+
this.readInto(at, out);
|
|
6168
|
+
return out;
|
|
6169
|
+
}
|
|
6170
|
+
readInto(at, out) {
|
|
6171
|
+
const end = Math.min(this.length, at + out.length);
|
|
6172
|
+
for (let pos = at; pos < end; ) {
|
|
6173
|
+
const page = Math.floor(pos / PAGE);
|
|
6174
|
+
const from = pos - page * PAGE;
|
|
6175
|
+
const n = Math.min(PAGE - from, end - pos);
|
|
6176
|
+
const bytes = this.pages.get(page);
|
|
6177
|
+
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
6178
|
+
else out.fill(0, pos - at, pos - at + n);
|
|
6179
|
+
pos += n;
|
|
6180
|
+
}
|
|
6181
|
+
return Math.max(0, end - at);
|
|
6182
|
+
}
|
|
6183
|
+
write(at, bytes) {
|
|
6184
|
+
for (let done4 = 0; done4 < bytes.length; ) {
|
|
6185
|
+
const pos = at + done4;
|
|
6186
|
+
const page = Math.floor(pos / PAGE);
|
|
6187
|
+
const from = pos - page * PAGE;
|
|
6188
|
+
const n = Math.min(PAGE - from, bytes.length - done4);
|
|
6189
|
+
let target = this.pages.get(page);
|
|
6190
|
+
if (!target) {
|
|
6191
|
+
target = this.take(0);
|
|
6192
|
+
this.pages.set(page, target);
|
|
6193
|
+
}
|
|
6194
|
+
target.set(bytes.subarray(done4, done4 + n), from);
|
|
6195
|
+
this.dirty.add(page);
|
|
6196
|
+
done4 += n;
|
|
6197
|
+
}
|
|
6198
|
+
this.length = Math.max(this.length, at + bytes.length);
|
|
6199
|
+
}
|
|
6200
|
+
truncate(size) {
|
|
6201
|
+
if (size < this.stored) {
|
|
6202
|
+
this.stored = size;
|
|
6203
|
+
this.shrink = Math.min(this.shrink ?? size, size);
|
|
6204
|
+
}
|
|
6205
|
+
if (size < this.length) {
|
|
6206
|
+
const edge = Math.floor(size / PAGE);
|
|
6207
|
+
for (const page of [...this.pages.keys()]) {
|
|
6208
|
+
if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
|
|
6209
|
+
}
|
|
6210
|
+
this.pages.get(edge)?.fill(0, size - edge * PAGE);
|
|
6211
|
+
}
|
|
6212
|
+
this.length = size;
|
|
6213
|
+
}
|
|
6214
|
+
plan() {
|
|
6215
|
+
const runs = [];
|
|
6216
|
+
const sorted = [...this.dirty].sort((a, b) => a - b);
|
|
6217
|
+
for (let i = 0; i < sorted.length; ) {
|
|
6218
|
+
let j = i + 1;
|
|
6219
|
+
const first = sorted[i];
|
|
6220
|
+
while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
|
|
6221
|
+
j++;
|
|
6222
|
+
}
|
|
6223
|
+
const start2 = first * PAGE;
|
|
6224
|
+
const end = Math.min(this.length, (first + (j - i)) * PAGE);
|
|
6225
|
+
const bytes = new Uint8Array(end - start2);
|
|
6226
|
+
for (let k = i; k < j; k++) {
|
|
6227
|
+
const page = this.pages.get(sorted[k]);
|
|
6228
|
+
bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start2)), (k - i) * PAGE);
|
|
6229
|
+
}
|
|
6230
|
+
runs.push({ offset: start2, bytes });
|
|
6231
|
+
i = j;
|
|
6232
|
+
}
|
|
6233
|
+
const written2 = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
|
|
6234
|
+
return {
|
|
6235
|
+
...this.shrink !== void 0 ? { shrink: this.shrink } : {},
|
|
6236
|
+
runs,
|
|
6237
|
+
...this.length > written2 ? { extend: this.length } : {}
|
|
6238
|
+
};
|
|
6239
|
+
}
|
|
6240
|
+
flushed() {
|
|
6241
|
+
this.dirty.clear();
|
|
6242
|
+
this.shrink = void 0;
|
|
6243
|
+
this.stored = this.length;
|
|
6244
|
+
this.evict();
|
|
6245
|
+
}
|
|
6246
|
+
pin() {
|
|
6247
|
+
this.pinned = true;
|
|
6248
|
+
}
|
|
6249
|
+
reset(size) {
|
|
6250
|
+
if (this.pinned) return;
|
|
6251
|
+
for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
|
|
6252
|
+
if (this.changed) return;
|
|
6253
|
+
this.length = size;
|
|
6254
|
+
this.stored = size;
|
|
6255
|
+
}
|
|
6256
|
+
evict() {
|
|
6257
|
+
if (this.pinned) return;
|
|
6258
|
+
let clean = (this.pages.size - this.dirty.size) * PAGE;
|
|
6259
|
+
for (const page of this.pages.keys()) {
|
|
6260
|
+
if (clean <= CLEAN_LIMIT) return;
|
|
6261
|
+
if (this.dirty.has(page)) continue;
|
|
6262
|
+
this.drop(page);
|
|
6263
|
+
clean -= PAGE;
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
take(used) {
|
|
6267
|
+
const page = this.free.pop();
|
|
6268
|
+
if (!page) return new Uint8Array(PAGE);
|
|
6269
|
+
page.fill(0, used);
|
|
6270
|
+
return page;
|
|
6271
|
+
}
|
|
6272
|
+
drop(page) {
|
|
6273
|
+
const bytes = this.pages.get(page);
|
|
6274
|
+
this.pages.delete(page);
|
|
6275
|
+
this.dirty.delete(page);
|
|
6276
|
+
if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
|
|
6277
|
+
}
|
|
6278
|
+
};
|
|
6279
|
+
|
|
6280
|
+
// src/fs/ranged.ts
|
|
6281
|
+
var AsyncRangedFile = class {
|
|
6282
|
+
pages;
|
|
6283
|
+
io;
|
|
6284
|
+
pinned = false;
|
|
6285
|
+
version;
|
|
6286
|
+
path;
|
|
6287
|
+
constructor(io, path, size, version) {
|
|
6288
|
+
this.io = io;
|
|
6289
|
+
this.path = path;
|
|
6290
|
+
this.version = version;
|
|
6291
|
+
this.pages = new Pages(size);
|
|
6292
|
+
}
|
|
6293
|
+
size() {
|
|
6294
|
+
return this.pages.length;
|
|
6295
|
+
}
|
|
6296
|
+
async fetch(runs) {
|
|
6297
|
+
for (const [start2, n] of runs) {
|
|
6298
|
+
this.pages.fill(start2, await this.io.pread(this.path, start2, n, this.version));
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
async read(at, length2) {
|
|
6302
|
+
await this.fetch(this.pages.missing(at, length2));
|
|
6303
|
+
return this.pages.read(at, length2);
|
|
6304
|
+
}
|
|
6305
|
+
async write(at, bytes) {
|
|
6306
|
+
await this.fetch(this.pages.partial(at, bytes.length));
|
|
6307
|
+
this.pages.write(at, bytes);
|
|
6308
|
+
if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) await this.flush();
|
|
6309
|
+
}
|
|
6310
|
+
truncate(size) {
|
|
6311
|
+
this.pages.truncate(size);
|
|
6312
|
+
}
|
|
6313
|
+
async flush() {
|
|
6314
|
+
if (this.pinned || !this.pages.changed) return;
|
|
6315
|
+
const plan = this.pages.plan();
|
|
6316
|
+
if (plan.shrink !== void 0) await this.io.truncate(this.path, plan.shrink);
|
|
6317
|
+
for (const run2 of plan.runs) await this.io.pwrite(this.path, run2.offset, run2.bytes, true);
|
|
6318
|
+
if (plan.extend !== void 0) await this.io.truncate(this.path, plan.extend);
|
|
6319
|
+
this.version = void 0;
|
|
6320
|
+
this.pages.flushed();
|
|
6321
|
+
}
|
|
6322
|
+
async pin() {
|
|
6323
|
+
this.pinned = true;
|
|
6324
|
+
this.pages.pin();
|
|
6325
|
+
await this.fetch(this.pages.missing(0, this.pages.length));
|
|
6326
|
+
}
|
|
6327
|
+
};
|
|
6328
|
+
|
|
6329
|
+
// src/process/wasi/wasi-files.ts
|
|
6330
|
+
function normalize(path) {
|
|
6331
|
+
const out = [];
|
|
6332
|
+
for (const seg of path.split("/")) {
|
|
6333
|
+
if (seg === "" || seg === ".") continue;
|
|
6334
|
+
if (seg === "..") out.pop();
|
|
6335
|
+
else out.push(seg);
|
|
6336
|
+
}
|
|
6337
|
+
return `/${out.join("/")}`;
|
|
6338
|
+
}
|
|
6339
|
+
|
|
6340
|
+
// src/process/wasi/wasi-procfs.ts
|
|
6341
|
+
var DIR_MODE = 16749;
|
|
6342
|
+
var FILE_MODE = 33060;
|
|
6343
|
+
var LINK_MODE = 41471;
|
|
6344
|
+
var PID_NAMES = PID_FILES;
|
|
6345
|
+
var SYSTEM_NAMES = SYSTEM_FILES;
|
|
6346
|
+
function inProc(path) {
|
|
6347
|
+
return path === "/proc" || path.startsWith("/proc/");
|
|
6348
|
+
}
|
|
6349
|
+
var ProcTree = class {
|
|
6350
|
+
source;
|
|
6351
|
+
pid;
|
|
6352
|
+
memory;
|
|
6353
|
+
constructor(source, pid, memory = memorySource()) {
|
|
6354
|
+
this.source = source;
|
|
6355
|
+
this.pid = pid;
|
|
6356
|
+
this.memory = memory;
|
|
6357
|
+
}
|
|
6358
|
+
listing() {
|
|
6359
|
+
return this.source.procList();
|
|
6360
|
+
}
|
|
6361
|
+
alive(pid) {
|
|
6362
|
+
return this.listing().processes.some((p) => p.pid === pid);
|
|
6363
|
+
}
|
|
6364
|
+
node(parts) {
|
|
6365
|
+
const [top, leaf, ...rest2] = parts;
|
|
6366
|
+
if (top === void 0) {
|
|
6367
|
+
return {
|
|
6368
|
+
kind: "dir",
|
|
6369
|
+
names: () => [
|
|
6370
|
+
...SYSTEM_NAMES,
|
|
6371
|
+
"mounts",
|
|
6372
|
+
"self",
|
|
6373
|
+
...this.listing().processes.map((p) => String(p.pid))
|
|
6374
|
+
]
|
|
6375
|
+
};
|
|
6376
|
+
}
|
|
6377
|
+
if (top === "self") {
|
|
6378
|
+
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
6379
|
+
}
|
|
6380
|
+
if (leaf === void 0 && top === "mounts") {
|
|
6381
|
+
return { kind: "file", content: () => mountTable(this.source.mountList()) };
|
|
6382
|
+
}
|
|
6383
|
+
if (leaf === void 0 && SYSTEM_NAMES.includes(top)) {
|
|
6384
|
+
return {
|
|
6385
|
+
kind: "file",
|
|
6386
|
+
content: () => systemFile(top, this.listing(), Date.now(), this.memory)
|
|
6387
|
+
};
|
|
6388
|
+
}
|
|
6389
|
+
if (!/^[1-9]\d*$/.test(top) || rest2.length > 0 || !this.alive(Number(top))) return void 0;
|
|
6390
|
+
if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES] };
|
|
6391
|
+
if (!PID_NAMES.includes(leaf)) return void 0;
|
|
6392
|
+
return {
|
|
6393
|
+
kind: "file",
|
|
6394
|
+
content: () => {
|
|
6395
|
+
const listing = this.listing();
|
|
6396
|
+
const info = listing.processes.find((p) => p.pid === Number(top));
|
|
6397
|
+
if (!info) throw syncError("ENOENT", `/proc/${top}/${leaf}`);
|
|
6398
|
+
return pidFile(leaf, info, listing.boot);
|
|
6399
|
+
}
|
|
6400
|
+
};
|
|
6401
|
+
}
|
|
6402
|
+
parts(path, follow2) {
|
|
6403
|
+
const parts = path.split("/").filter((p) => p !== "").slice(1);
|
|
6404
|
+
if (parts[0] === "self" && (follow2 || parts.length > 1)) parts[0] = String(this.pid);
|
|
6405
|
+
return parts;
|
|
6406
|
+
}
|
|
6407
|
+
find(path, follow2) {
|
|
6408
|
+
const node = this.node(this.parts(path, follow2));
|
|
6409
|
+
if (!node) throw syncError("ENOENT", path);
|
|
6410
|
+
return node;
|
|
6411
|
+
}
|
|
6412
|
+
stat(path, follow2 = true) {
|
|
6413
|
+
const node = this.find(path, follow2);
|
|
6414
|
+
const base = {
|
|
6415
|
+
isFile: false,
|
|
6416
|
+
isDirectory: false,
|
|
6417
|
+
size: 0,
|
|
6418
|
+
mtimeMs: Date.now(),
|
|
6419
|
+
readonly: true
|
|
6420
|
+
};
|
|
6421
|
+
if (node.kind === "dir") return { ...base, isDirectory: true, mode: DIR_MODE };
|
|
6422
|
+
if (node.kind === "link") {
|
|
6423
|
+
return { ...base, isSymbolicLink: true, mode: LINK_MODE, size: node.target.length };
|
|
6424
|
+
}
|
|
6425
|
+
return { ...base, isFile: true, mode: FILE_MODE, size: this.bytes(node).length };
|
|
6426
|
+
}
|
|
6427
|
+
bytes(node) {
|
|
6428
|
+
return new TextEncoder().encode(node.kind === "file" ? node.content() : "");
|
|
6429
|
+
}
|
|
6430
|
+
read(path) {
|
|
6431
|
+
const node = this.find(path, true);
|
|
6432
|
+
if (node.kind !== "file") throw syncError("EISDIR", path);
|
|
6433
|
+
return this.bytes(node);
|
|
6434
|
+
}
|
|
6435
|
+
readdir(path) {
|
|
6436
|
+
const node = this.find(path, true);
|
|
6437
|
+
if (node.kind !== "dir") throw syncError("ENOTDIR", path);
|
|
6438
|
+
return node.names();
|
|
6439
|
+
}
|
|
6440
|
+
readlink(path) {
|
|
6441
|
+
const node = this.find(path, false);
|
|
6442
|
+
if (node.kind !== "link") throw syncError("EINVAL", path);
|
|
6443
|
+
return node.target;
|
|
6444
|
+
}
|
|
6445
|
+
exists(path) {
|
|
6446
|
+
try {
|
|
6447
|
+
this.find(path, true);
|
|
6448
|
+
return true;
|
|
6449
|
+
} catch {
|
|
6450
|
+
return false;
|
|
6451
|
+
}
|
|
6452
|
+
}
|
|
6453
|
+
};
|
|
6454
|
+
var MAX_HOPS2 = 40;
|
|
6455
|
+
function* procWalk(path, follow2) {
|
|
6456
|
+
let done4 = [];
|
|
6457
|
+
let todo = path.split("/").filter((part) => part !== "");
|
|
6458
|
+
let hops = 0;
|
|
6459
|
+
while (todo.length > 0) {
|
|
6460
|
+
const part = todo.shift();
|
|
6461
|
+
if (part === ".") continue;
|
|
6462
|
+
if (part === "..") {
|
|
6463
|
+
done4.pop();
|
|
6464
|
+
continue;
|
|
6465
|
+
}
|
|
6466
|
+
const at = `/${[...done4, part].join("/")}`;
|
|
6467
|
+
const whole = normalize(`/${[...done4, part, ...todo].join("/")}`);
|
|
6468
|
+
if (inProc(at) && inProc(whole)) return whole;
|
|
6469
|
+
if (!follow2 && todo.length === 0) return void 0;
|
|
6470
|
+
const target = yield at;
|
|
6471
|
+
if (target === null) return void 0;
|
|
6472
|
+
if (target === void 0) done4.push(part);
|
|
6473
|
+
else {
|
|
6474
|
+
if (++hops > MAX_HOPS2) return void 0;
|
|
6475
|
+
if (target.startsWith("/")) done4 = [];
|
|
6476
|
+
todo = [...target.split("/").filter((part2) => part2 !== ""), ...todo];
|
|
6477
|
+
}
|
|
6478
|
+
}
|
|
6479
|
+
return void 0;
|
|
6480
|
+
}
|
|
6481
|
+
async function procAlias(fs, path, follow2) {
|
|
6482
|
+
const { readlink, lstat } = fs;
|
|
6483
|
+
if (!readlink || !lstat) return void 0;
|
|
6484
|
+
const physical = await lstat.call(fs, "/proc").then(
|
|
6485
|
+
() => true,
|
|
6486
|
+
() => false
|
|
6487
|
+
);
|
|
6488
|
+
if (!physical) return void 0;
|
|
6489
|
+
const walk = procWalk(path, follow2);
|
|
6490
|
+
let step = walk.next();
|
|
6491
|
+
while (!step.done) {
|
|
6492
|
+
const target = await readlink.call(fs, step.value).catch(() => void 0);
|
|
6493
|
+
step = walk.next(target);
|
|
6494
|
+
}
|
|
6495
|
+
return step.value;
|
|
6496
|
+
}
|
|
6497
|
+
|
|
6498
|
+
// src/kernel/host-ops.ts
|
|
6499
|
+
var HOST_OPS = [
|
|
6500
|
+
"lock",
|
|
6501
|
+
"unlock",
|
|
6502
|
+
"async-submit",
|
|
6503
|
+
"async-wait",
|
|
6504
|
+
"async-take",
|
|
6505
|
+
"async-resolve",
|
|
6506
|
+
"async-hold",
|
|
6507
|
+
"async-cancel",
|
|
6508
|
+
"async-close"
|
|
6509
|
+
];
|
|
6510
|
+
var json3 = (value) => ({ ok: true, kind: "json", json: value });
|
|
6511
|
+
var done2 = { ok: true, kind: "void" };
|
|
6512
|
+
var LockTable = class {
|
|
6513
|
+
held = /* @__PURE__ */ new Map();
|
|
6514
|
+
lock(pid, path, exclusive, fd) {
|
|
6515
|
+
const holders = this.held.get(path) ?? /* @__PURE__ */ new Map();
|
|
6516
|
+
for (const [other, h] of holders) if (other !== pid && (exclusive || h.exclusive)) return false;
|
|
6517
|
+
const mine = holders.get(pid) ?? { exclusive, fds: /* @__PURE__ */ new Set() };
|
|
6518
|
+
mine.exclusive = exclusive;
|
|
6519
|
+
mine.fds.add(fd);
|
|
6520
|
+
holders.set(pid, mine);
|
|
6521
|
+
this.held.set(path, holders);
|
|
6522
|
+
return true;
|
|
6523
|
+
}
|
|
6524
|
+
unlock(pid, path) {
|
|
6525
|
+
const holders = this.held.get(path);
|
|
6526
|
+
holders?.delete(pid);
|
|
6527
|
+
if (holders?.size === 0) this.held.delete(path);
|
|
6528
|
+
}
|
|
6529
|
+
closed(pid, fd) {
|
|
6530
|
+
for (const [path, holders] of [...this.held]) {
|
|
6531
|
+
const mine = holders.get(pid);
|
|
6532
|
+
if (mine?.fds.delete(fd) && mine.fds.size === 0) this.unlock(pid, path);
|
|
6533
|
+
}
|
|
6534
|
+
}
|
|
6535
|
+
release(pid) {
|
|
6536
|
+
for (const path of [...this.held.keys()]) this.unlock(pid, path);
|
|
6537
|
+
}
|
|
6538
|
+
};
|
|
6539
|
+
var AsyncOps = class {
|
|
6540
|
+
next = 1;
|
|
6541
|
+
results = /* @__PURE__ */ new Map();
|
|
6542
|
+
ready = [];
|
|
6543
|
+
running = /* @__PURE__ */ new Map();
|
|
6544
|
+
waiters = /* @__PURE__ */ new Set();
|
|
6545
|
+
closed = false;
|
|
6546
|
+
run;
|
|
6547
|
+
onReady;
|
|
6548
|
+
constructor(run2, onReady) {
|
|
6549
|
+
this.run = run2;
|
|
6550
|
+
this.onReady = onReady;
|
|
6551
|
+
}
|
|
6552
|
+
submit(req) {
|
|
6553
|
+
const id2 = this.hold();
|
|
6554
|
+
const running = new AbortController();
|
|
6555
|
+
this.running.set(id2, running);
|
|
6556
|
+
this.run(req, running.signal).then(
|
|
6557
|
+
(result) => this.complete(id2, result),
|
|
6558
|
+
(err) => this.complete(id2, { ok: false, errno: "EIO", message: String(err) })
|
|
6559
|
+
);
|
|
6560
|
+
return id2;
|
|
6561
|
+
}
|
|
6562
|
+
resolve(value) {
|
|
6563
|
+
const id2 = this.hold();
|
|
6564
|
+
this.complete(id2, json3(value));
|
|
6565
|
+
return id2;
|
|
6566
|
+
}
|
|
6567
|
+
hold() {
|
|
6568
|
+
const id2 = this.next++;
|
|
6569
|
+
this.results.set(id2, void 0);
|
|
6570
|
+
return id2;
|
|
6571
|
+
}
|
|
6572
|
+
take(id2) {
|
|
6573
|
+
if (!this.results.has(id2)) throw new KernelError("EINVAL");
|
|
6574
|
+
const result = this.results.get(id2);
|
|
6575
|
+
if (!result) throw new KernelError("EAGAIN");
|
|
6576
|
+
this.forget(id2);
|
|
6577
|
+
return result;
|
|
6578
|
+
}
|
|
6579
|
+
cancel(id2) {
|
|
6580
|
+
this.running.get(id2)?.abort();
|
|
6581
|
+
this.forget(id2);
|
|
6582
|
+
}
|
|
6583
|
+
forget(id2) {
|
|
6584
|
+
this.running.delete(id2);
|
|
6585
|
+
this.results.delete(id2);
|
|
6586
|
+
const at = this.ready.indexOf(id2);
|
|
6587
|
+
if (at >= 0) this.ready.splice(at, 1);
|
|
6588
|
+
}
|
|
6589
|
+
async wait(timeoutMs, blocking) {
|
|
6590
|
+
let signal;
|
|
6591
|
+
for (; ; ) {
|
|
6592
|
+
if (this.closed) return -1;
|
|
6593
|
+
const id2 = this.ready.shift();
|
|
6594
|
+
if (id2 !== void 0) return id2;
|
|
6595
|
+
if (timeoutMs !== void 0 && timeoutMs <= 0) return 0;
|
|
6596
|
+
signal ??= blocking();
|
|
6597
|
+
const woke = await this.sleep(timeoutMs, signal);
|
|
6598
|
+
if (!woke) return 0;
|
|
6599
|
+
}
|
|
6600
|
+
}
|
|
6601
|
+
close() {
|
|
6602
|
+
this.closed = true;
|
|
6603
|
+
this.wake();
|
|
6604
|
+
}
|
|
6605
|
+
sleep(timeoutMs, signal) {
|
|
6606
|
+
return new Promise((resolve, reject) => {
|
|
6607
|
+
let timer;
|
|
6608
|
+
const cleanup = () => {
|
|
6609
|
+
clearTimeout(timer);
|
|
6610
|
+
this.waiters.delete(wake);
|
|
6611
|
+
signal.removeEventListener("abort", abort);
|
|
6612
|
+
};
|
|
6613
|
+
const wake = () => {
|
|
6614
|
+
cleanup();
|
|
6615
|
+
resolve(true);
|
|
6616
|
+
};
|
|
6617
|
+
const abort = () => {
|
|
6618
|
+
cleanup();
|
|
6619
|
+
reject(new KernelError("EINTR"));
|
|
6620
|
+
};
|
|
6621
|
+
this.waiters.add(wake);
|
|
6622
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
6623
|
+
if (timeoutMs !== void 0) {
|
|
6624
|
+
timer = setTimeout(() => {
|
|
6625
|
+
cleanup();
|
|
6626
|
+
resolve(false);
|
|
6627
|
+
}, timeoutMs);
|
|
6628
|
+
}
|
|
6629
|
+
});
|
|
6630
|
+
}
|
|
6631
|
+
complete(id2, result) {
|
|
6632
|
+
this.running.delete(id2);
|
|
6633
|
+
if (!this.results.has(id2)) return;
|
|
6634
|
+
this.results.set(id2, result);
|
|
6635
|
+
this.ready.push(id2);
|
|
6636
|
+
this.wake();
|
|
6637
|
+
this.onReady?.();
|
|
6638
|
+
}
|
|
6639
|
+
wake() {
|
|
6640
|
+
for (const wake of [...this.waiters]) wake();
|
|
6641
|
+
}
|
|
6642
|
+
};
|
|
6643
|
+
async function hostSyscall(req, ctx) {
|
|
6644
|
+
switch (req.op) {
|
|
6645
|
+
case "lock":
|
|
6646
|
+
if (!ctx.locks) throw new KernelError("ENOSYS");
|
|
6647
|
+
if (!ctx.locks.lock(ctx.pid, req.path, req.exclusive, req.fd))
|
|
6648
|
+
throw new KernelError("EAGAIN");
|
|
6649
|
+
return done2;
|
|
6650
|
+
case "unlock":
|
|
6651
|
+
ctx.locks?.unlock(ctx.pid, req.path);
|
|
6652
|
+
return done2;
|
|
6653
|
+
case "async-submit":
|
|
6654
|
+
if (!ctx.valid(req.req)) throw new KernelError("EINVAL");
|
|
6655
|
+
return json3(ctx.ops.submit(req.req));
|
|
6656
|
+
case "async-wait":
|
|
6657
|
+
return json3(await ctx.ops.wait(req.timeoutMs, ctx.blocking));
|
|
6658
|
+
case "async-take":
|
|
6659
|
+
return ctx.ops.take(req.id);
|
|
6660
|
+
case "async-resolve":
|
|
6661
|
+
return json3(ctx.ops.resolve(req.value));
|
|
6662
|
+
case "async-hold":
|
|
6663
|
+
return json3(ctx.ops.hold());
|
|
6664
|
+
case "async-cancel":
|
|
6665
|
+
ctx.ops.cancel(req.id);
|
|
6666
|
+
return done2;
|
|
6667
|
+
case "async-close":
|
|
6668
|
+
ctx.ops.close();
|
|
6669
|
+
return done2;
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
|
|
6673
|
+
// src/kernel/net/proxy-service.ts
|
|
6674
|
+
var SEND_BUFFER2 = 1024 * 1024;
|
|
6675
|
+
var TLS_HANDSHAKE = 22;
|
|
6676
|
+
var TOKEN2 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
6677
|
+
var NO_WEBSOCKET2 = "WebSocket not supported by this transport (fetchTransport needs { webSocket: true })";
|
|
6678
|
+
var REALM_PROXY_PORT = 3128;
|
|
6679
|
+
var DEFAULT_LIMITS = {
|
|
6680
|
+
maxConnections: 64,
|
|
6681
|
+
maxHead: 64 * 1024,
|
|
6682
|
+
idleMs: 12e4,
|
|
6683
|
+
bodyBudget: 128 * 1024 * 1024,
|
|
6684
|
+
closeWaitMs: 5e3
|
|
6685
|
+
};
|
|
6686
|
+
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
6687
|
+
"connection",
|
|
6688
|
+
"keep-alive",
|
|
6689
|
+
"proxy-connection",
|
|
6690
|
+
"proxy-authenticate",
|
|
6691
|
+
"proxy-authorization",
|
|
6692
|
+
"te",
|
|
6693
|
+
"trailer",
|
|
6694
|
+
"transfer-encoding",
|
|
6695
|
+
"upgrade"
|
|
6696
|
+
]);
|
|
6697
|
+
var REQUEST_OWN = /* @__PURE__ */ new Set(["host", "content-length", "expect"]);
|
|
6698
|
+
var Budget = class {
|
|
6699
|
+
free;
|
|
6700
|
+
waiters = [];
|
|
6701
|
+
constructor(free) {
|
|
6702
|
+
this.free = free;
|
|
6703
|
+
}
|
|
6704
|
+
async acquire(n, signal) {
|
|
6705
|
+
while (this.free < n) {
|
|
6706
|
+
signal.throwIfAborted();
|
|
6707
|
+
await new Promise((resolve) => {
|
|
6708
|
+
const done4 = () => {
|
|
6709
|
+
signal.removeEventListener("abort", done4);
|
|
6710
|
+
resolve();
|
|
6711
|
+
};
|
|
6712
|
+
this.waiters.push(done4);
|
|
6713
|
+
signal.addEventListener("abort", done4, { once: true });
|
|
6714
|
+
});
|
|
6715
|
+
}
|
|
6716
|
+
this.free -= n;
|
|
6717
|
+
}
|
|
6718
|
+
release(n) {
|
|
6719
|
+
this.free += n;
|
|
6720
|
+
const waiters = this.waiters;
|
|
6721
|
+
this.waiters = [];
|
|
6722
|
+
for (const wake of waiters) wake();
|
|
6723
|
+
}
|
|
6724
|
+
};
|
|
6725
|
+
function canonicalHost2(host) {
|
|
6726
|
+
const bare = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
6727
|
+
try {
|
|
6728
|
+
return new URL(`http://${bare}/`).hostname;
|
|
6729
|
+
} catch {
|
|
6730
|
+
return void 0;
|
|
6731
|
+
}
|
|
6732
|
+
}
|
|
6733
|
+
function localV4(a, b) {
|
|
6130
6734
|
return a === 127 || a === 0 || a === 169 && b === 254;
|
|
6131
6735
|
}
|
|
6132
6736
|
function hextets(address) {
|
|
@@ -8259,343 +8863,118 @@ async function selectFds(fds, read, write, timeoutMs, interrupt) {
|
|
|
8259
8863
|
try {
|
|
8260
8864
|
return await waitReady(fds, read, write, deadline, interrupted2.promise);
|
|
8261
8865
|
} finally {
|
|
8262
|
-
interrupted2.done();
|
|
8263
|
-
}
|
|
8264
|
-
}
|
|
8265
|
-
async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
8266
|
-
for (; ; ) {
|
|
8267
|
-
const now = ready(fds, read, write);
|
|
8268
|
-
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
8269
|
-
const round = new AbortController();
|
|
8270
|
-
const changes = [.../* @__PURE__ */ new Set([...read, ...write])].flatMap((fd) => {
|
|
8271
|
-
const file = fds.get(fd).file;
|
|
8272
|
-
return file.changed === void 0 ? [] : [file.changed(round.signal).catch(() => void 0)];
|
|
8273
|
-
});
|
|
8274
|
-
let timer;
|
|
8275
|
-
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve) => timer = setTimeout(resolve, deadline - Date.now()))];
|
|
8276
|
-
try {
|
|
8277
|
-
await Promise.race([...changes, ...expiry, interrupted2]);
|
|
8278
|
-
} finally {
|
|
8279
|
-
round.abort();
|
|
8280
|
-
clearTimeout(timer);
|
|
8281
|
-
}
|
|
8282
|
-
}
|
|
8283
|
-
}
|
|
8284
|
-
|
|
8285
|
-
// src/kernel/socket-syscalls.ts
|
|
8286
|
-
var SOCKET_OPS = [
|
|
8287
|
-
"sock-open",
|
|
8288
|
-
"sock-pair",
|
|
8289
|
-
"sock-bind",
|
|
8290
|
-
"sock-listen",
|
|
8291
|
-
"sock-accept",
|
|
8292
|
-
"sock-connect",
|
|
8293
|
-
"sock-shutdown",
|
|
8294
|
-
"sock-name",
|
|
8295
|
-
"sock-getopt",
|
|
8296
|
-
"sock-setopt",
|
|
8297
|
-
"sock-resolve"
|
|
8298
|
-
];
|
|
8299
|
-
function socketAt(fds, fd) {
|
|
8300
|
-
const file = fds.get(fd).file;
|
|
8301
|
-
if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
|
|
8302
|
-
return file;
|
|
8303
|
-
}
|
|
8304
|
-
var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
8305
|
-
async function socketSyscall(req, proc) {
|
|
8306
|
-
const { fds, net } = proc;
|
|
8307
|
-
switch (req.op) {
|
|
8308
|
-
case "sock-open":
|
|
8309
|
-
return ok(fds.install(new OpenFile(net.socket(req.domain)), 3));
|
|
8310
|
-
case "sock-pair": {
|
|
8311
|
-
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
8312
|
-
const first = fds.install(new OpenFile(a), 3);
|
|
8313
|
-
try {
|
|
8314
|
-
return ok([first, fds.install(new OpenFile(b), 3)]);
|
|
8315
|
-
} catch (e) {
|
|
8316
|
-
await Promise.resolve(fds.close(first));
|
|
8317
|
-
throw e;
|
|
8318
|
-
}
|
|
8319
|
-
}
|
|
8320
|
-
case "sock-bind":
|
|
8321
|
-
socketAt(fds, req.fd).bind(req.addr);
|
|
8322
|
-
return ok();
|
|
8323
|
-
case "sock-listen":
|
|
8324
|
-
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
8325
|
-
return ok();
|
|
8326
|
-
case "sock-accept":
|
|
8327
|
-
return ok(await accept(proc, req.fd, req.nonblock));
|
|
8328
|
-
case "sock-connect": {
|
|
8329
|
-
const dialing = socketAt(fds, req.fd).connect(req.addr, true, proc.cred?.());
|
|
8330
|
-
if (req.nonblock) {
|
|
8331
|
-
dialing?.catch(() => void 0);
|
|
8332
|
-
throw new KernelError("EINPROGRESS");
|
|
8333
|
-
}
|
|
8334
|
-
if (dialing !== void 0) await interruptible(dialing, proc.blocking());
|
|
8335
|
-
return ok();
|
|
8336
|
-
}
|
|
8337
|
-
case "sock-shutdown":
|
|
8338
|
-
socketAt(fds, req.fd).shutdown(req.how);
|
|
8339
|
-
return ok();
|
|
8340
|
-
case "sock-name": {
|
|
8341
|
-
const socket = socketAt(fds, req.fd);
|
|
8342
|
-
const addr = req.peer ? socket.peer : socket.local;
|
|
8343
|
-
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
8344
|
-
return ok(addr ?? unnamed(socket.domain));
|
|
8345
|
-
}
|
|
8346
|
-
case "sock-getopt":
|
|
8347
|
-
return ok(socketAt(fds, req.fd).getOption(req.level, req.name));
|
|
8348
|
-
case "sock-setopt":
|
|
8349
|
-
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
8350
|
-
return ok();
|
|
8351
|
-
case "sock-resolve": {
|
|
8352
|
-
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
8353
|
-
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
8354
|
-
return ok(addresses);
|
|
8355
|
-
}
|
|
8356
|
-
}
|
|
8357
|
-
}
|
|
8358
|
-
function interruptible(dialing, signal) {
|
|
8359
|
-
return new Promise((resolve, reject) => {
|
|
8360
|
-
const abort = () => reject(new KernelError("EINTR"));
|
|
8361
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
8362
|
-
dialing.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
8363
|
-
});
|
|
8364
|
-
}
|
|
8365
|
-
function unnamed(domain) {
|
|
8366
|
-
return domain === "inet" ? { family: "inet", host: "0.0.0.0", port: 0 } : { family: "unix", path: "" };
|
|
8367
|
-
}
|
|
8368
|
-
async function accept(proc, fd, nonblock) {
|
|
8369
|
-
const listener = socketAt(proc.fds, fd);
|
|
8370
|
-
const waits = !nonblock && !pollFile(listener).readable;
|
|
8371
|
-
const socket = await listener.accept(waits ? proc.blocking() : void 0, nonblock);
|
|
8372
|
-
return { fd: proc.fds.install(new OpenFile(socket), 3), peer: socket.peer };
|
|
8373
|
-
}
|
|
8374
|
-
|
|
8375
|
-
// src/fs/pages.ts
|
|
8376
|
-
var PAGE = 64 * 1024;
|
|
8377
|
-
var READAHEAD = 1024 * 1024;
|
|
8378
|
-
var CLEAN_LIMIT = 4 * 1024 * 1024;
|
|
8379
|
-
var WRITEBACK = 8 * 1024 * 1024;
|
|
8380
|
-
var RUN = 1024 * 1024;
|
|
8381
|
-
var Pages = class {
|
|
8382
|
-
length;
|
|
8383
|
-
stored;
|
|
8384
|
-
shrink;
|
|
8385
|
-
pages = /* @__PURE__ */ new Map();
|
|
8386
|
-
dirty = /* @__PURE__ */ new Set();
|
|
8387
|
-
free = [];
|
|
8388
|
-
pinned = false;
|
|
8389
|
-
constructor(size) {
|
|
8390
|
-
this.length = size;
|
|
8391
|
-
this.stored = size;
|
|
8392
|
-
}
|
|
8393
|
-
get dirtyBytes() {
|
|
8394
|
-
return this.dirty.size * PAGE;
|
|
8395
|
-
}
|
|
8396
|
-
get changed() {
|
|
8397
|
-
return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
|
|
8398
|
-
}
|
|
8399
|
-
missing(at, length2) {
|
|
8400
|
-
this.evict();
|
|
8401
|
-
const end = Math.min(this.stored, at + length2, this.length);
|
|
8402
|
-
const runs = [];
|
|
8403
|
-
for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
|
|
8404
|
-
if (this.pages.has(page)) continue;
|
|
8405
|
-
const last2 = runs[runs.length - 1];
|
|
8406
|
-
if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
|
|
8407
|
-
else runs.push([page * PAGE, PAGE]);
|
|
8408
|
-
}
|
|
8409
|
-
const last = runs[runs.length - 1];
|
|
8410
|
-
if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
|
|
8411
|
-
return runs.map(([start2, n]) => [start2, Math.min(n, this.stored - start2)]);
|
|
8412
|
-
}
|
|
8413
|
-
partial(at, length2) {
|
|
8414
|
-
if (length2 === 0) return [];
|
|
8415
|
-
this.evict();
|
|
8416
|
-
const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length2 - 1) / PAGE)]);
|
|
8417
|
-
const runs = [];
|
|
8418
|
-
for (const page of edges) {
|
|
8419
|
-
const start2 = page * PAGE;
|
|
8420
|
-
const covered = at <= start2 && at + length2 >= start2 + PAGE;
|
|
8421
|
-
if (covered || this.pages.has(page) || start2 >= this.stored) continue;
|
|
8422
|
-
runs.push([start2, Math.min(PAGE, this.stored - start2)]);
|
|
8423
|
-
}
|
|
8424
|
-
return runs;
|
|
8425
|
-
}
|
|
8426
|
-
fill(start2, bytes) {
|
|
8427
|
-
for (let at = 0; at < bytes.length; at += PAGE) {
|
|
8428
|
-
const page = (start2 + at) / PAGE;
|
|
8429
|
-
if (this.pages.has(page)) continue;
|
|
8430
|
-
const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
|
|
8431
|
-
const fresh = this.take(part.length);
|
|
8432
|
-
fresh.set(part);
|
|
8433
|
-
this.pages.set(page, fresh);
|
|
8434
|
-
}
|
|
8435
|
-
}
|
|
8436
|
-
read(at, length2) {
|
|
8437
|
-
const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length2) - at));
|
|
8438
|
-
this.readInto(at, out);
|
|
8439
|
-
return out;
|
|
8440
|
-
}
|
|
8441
|
-
readInto(at, out) {
|
|
8442
|
-
const end = Math.min(this.length, at + out.length);
|
|
8443
|
-
for (let pos = at; pos < end; ) {
|
|
8444
|
-
const page = Math.floor(pos / PAGE);
|
|
8445
|
-
const from = pos - page * PAGE;
|
|
8446
|
-
const n = Math.min(PAGE - from, end - pos);
|
|
8447
|
-
const bytes = this.pages.get(page);
|
|
8448
|
-
if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
|
|
8449
|
-
else out.fill(0, pos - at, pos - at + n);
|
|
8450
|
-
pos += n;
|
|
8451
|
-
}
|
|
8452
|
-
return Math.max(0, end - at);
|
|
8453
|
-
}
|
|
8454
|
-
write(at, bytes) {
|
|
8455
|
-
for (let done4 = 0; done4 < bytes.length; ) {
|
|
8456
|
-
const pos = at + done4;
|
|
8457
|
-
const page = Math.floor(pos / PAGE);
|
|
8458
|
-
const from = pos - page * PAGE;
|
|
8459
|
-
const n = Math.min(PAGE - from, bytes.length - done4);
|
|
8460
|
-
let target = this.pages.get(page);
|
|
8461
|
-
if (!target) {
|
|
8462
|
-
target = this.take(0);
|
|
8463
|
-
this.pages.set(page, target);
|
|
8464
|
-
}
|
|
8465
|
-
target.set(bytes.subarray(done4, done4 + n), from);
|
|
8466
|
-
this.dirty.add(page);
|
|
8467
|
-
done4 += n;
|
|
8468
|
-
}
|
|
8469
|
-
this.length = Math.max(this.length, at + bytes.length);
|
|
8866
|
+
interrupted2.done();
|
|
8470
8867
|
}
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8868
|
+
}
|
|
8869
|
+
async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
8870
|
+
for (; ; ) {
|
|
8871
|
+
const now = ready(fds, read, write);
|
|
8872
|
+
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
8873
|
+
const round = new AbortController();
|
|
8874
|
+
const changes = [.../* @__PURE__ */ new Set([...read, ...write])].flatMap((fd) => {
|
|
8875
|
+
const file = fds.get(fd).file;
|
|
8876
|
+
return file.changed === void 0 ? [] : [file.changed(round.signal).catch(() => void 0)];
|
|
8877
|
+
});
|
|
8878
|
+
let timer;
|
|
8879
|
+
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve) => timer = setTimeout(resolve, deadline - Date.now()))];
|
|
8880
|
+
try {
|
|
8881
|
+
await Promise.race([...changes, ...expiry, interrupted2]);
|
|
8882
|
+
} finally {
|
|
8883
|
+
round.abort();
|
|
8884
|
+
clearTimeout(timer);
|
|
8482
8885
|
}
|
|
8483
|
-
this.length = size;
|
|
8484
8886
|
}
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8887
|
+
}
|
|
8888
|
+
|
|
8889
|
+
// src/kernel/socket-syscalls.ts
|
|
8890
|
+
var SOCKET_OPS = [
|
|
8891
|
+
"sock-open",
|
|
8892
|
+
"sock-pair",
|
|
8893
|
+
"sock-bind",
|
|
8894
|
+
"sock-listen",
|
|
8895
|
+
"sock-accept",
|
|
8896
|
+
"sock-connect",
|
|
8897
|
+
"sock-shutdown",
|
|
8898
|
+
"sock-name",
|
|
8899
|
+
"sock-getopt",
|
|
8900
|
+
"sock-setopt",
|
|
8901
|
+
"sock-resolve"
|
|
8902
|
+
];
|
|
8903
|
+
function socketAt(fds, fd) {
|
|
8904
|
+
const file = fds.get(fd).file;
|
|
8905
|
+
if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
|
|
8906
|
+
return file;
|
|
8907
|
+
}
|
|
8908
|
+
var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
8909
|
+
async function socketSyscall(req, proc) {
|
|
8910
|
+
const { fds, net } = proc;
|
|
8911
|
+
switch (req.op) {
|
|
8912
|
+
case "sock-open":
|
|
8913
|
+
return ok(fds.install(new OpenFile(net.socket(req.domain)), 3));
|
|
8914
|
+
case "sock-pair": {
|
|
8915
|
+
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
8916
|
+
const first = fds.install(new OpenFile(a), 3);
|
|
8917
|
+
try {
|
|
8918
|
+
return ok([first, fds.install(new OpenFile(b), 3)]);
|
|
8919
|
+
} catch (e) {
|
|
8920
|
+
await Promise.resolve(fds.close(first));
|
|
8921
|
+
throw e;
|
|
8493
8922
|
}
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8923
|
+
}
|
|
8924
|
+
case "sock-bind":
|
|
8925
|
+
socketAt(fds, req.fd).bind(req.addr);
|
|
8926
|
+
return ok();
|
|
8927
|
+
case "sock-listen":
|
|
8928
|
+
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
8929
|
+
return ok();
|
|
8930
|
+
case "sock-accept":
|
|
8931
|
+
return ok(await accept(proc, req.fd, req.nonblock));
|
|
8932
|
+
case "sock-connect": {
|
|
8933
|
+
const dialing = socketAt(fds, req.fd).connect(req.addr, true, proc.cred?.());
|
|
8934
|
+
if (req.nonblock) {
|
|
8935
|
+
dialing?.catch(() => void 0);
|
|
8936
|
+
throw new KernelError("EINPROGRESS");
|
|
8500
8937
|
}
|
|
8501
|
-
|
|
8502
|
-
|
|
8938
|
+
if (dialing !== void 0) await interruptible(dialing, proc.blocking());
|
|
8939
|
+
return ok();
|
|
8503
8940
|
}
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
this.dirty.clear();
|
|
8513
|
-
this.shrink = void 0;
|
|
8514
|
-
this.stored = this.length;
|
|
8515
|
-
this.evict();
|
|
8516
|
-
}
|
|
8517
|
-
pin() {
|
|
8518
|
-
this.pinned = true;
|
|
8519
|
-
}
|
|
8520
|
-
reset(size) {
|
|
8521
|
-
if (this.pinned) return;
|
|
8522
|
-
for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
|
|
8523
|
-
if (this.changed) return;
|
|
8524
|
-
this.length = size;
|
|
8525
|
-
this.stored = size;
|
|
8526
|
-
}
|
|
8527
|
-
evict() {
|
|
8528
|
-
if (this.pinned) return;
|
|
8529
|
-
let clean = (this.pages.size - this.dirty.size) * PAGE;
|
|
8530
|
-
for (const page of this.pages.keys()) {
|
|
8531
|
-
if (clean <= CLEAN_LIMIT) return;
|
|
8532
|
-
if (this.dirty.has(page)) continue;
|
|
8533
|
-
this.drop(page);
|
|
8534
|
-
clean -= PAGE;
|
|
8941
|
+
case "sock-shutdown":
|
|
8942
|
+
socketAt(fds, req.fd).shutdown(req.how);
|
|
8943
|
+
return ok();
|
|
8944
|
+
case "sock-name": {
|
|
8945
|
+
const socket = socketAt(fds, req.fd);
|
|
8946
|
+
const addr = req.peer ? socket.peer : socket.local;
|
|
8947
|
+
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
8948
|
+
return ok(addr ?? unnamed(socket.domain));
|
|
8535
8949
|
}
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
this.pages.delete(page);
|
|
8546
|
-
this.dirty.delete(page);
|
|
8547
|
-
if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
|
|
8548
|
-
}
|
|
8549
|
-
};
|
|
8550
|
-
|
|
8551
|
-
// src/fs/ranged.ts
|
|
8552
|
-
var AsyncRangedFile = class {
|
|
8553
|
-
pages;
|
|
8554
|
-
io;
|
|
8555
|
-
pinned = false;
|
|
8556
|
-
version;
|
|
8557
|
-
path;
|
|
8558
|
-
constructor(io, path, size, version) {
|
|
8559
|
-
this.io = io;
|
|
8560
|
-
this.path = path;
|
|
8561
|
-
this.version = version;
|
|
8562
|
-
this.pages = new Pages(size);
|
|
8563
|
-
}
|
|
8564
|
-
size() {
|
|
8565
|
-
return this.pages.length;
|
|
8566
|
-
}
|
|
8567
|
-
async fetch(runs) {
|
|
8568
|
-
for (const [start2, n] of runs) {
|
|
8569
|
-
this.pages.fill(start2, await this.io.pread(this.path, start2, n, this.version));
|
|
8950
|
+
case "sock-getopt":
|
|
8951
|
+
return ok(socketAt(fds, req.fd).getOption(req.level, req.name));
|
|
8952
|
+
case "sock-setopt":
|
|
8953
|
+
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
8954
|
+
return ok();
|
|
8955
|
+
case "sock-resolve": {
|
|
8956
|
+
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
8957
|
+
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
8958
|
+
return ok(addresses);
|
|
8570
8959
|
}
|
|
8571
8960
|
}
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
if (plan.extend !== void 0) await this.io.truncate(this.path, plan.extend);
|
|
8590
|
-
this.version = void 0;
|
|
8591
|
-
this.pages.flushed();
|
|
8592
|
-
}
|
|
8593
|
-
async pin() {
|
|
8594
|
-
this.pinned = true;
|
|
8595
|
-
this.pages.pin();
|
|
8596
|
-
await this.fetch(this.pages.missing(0, this.pages.length));
|
|
8597
|
-
}
|
|
8598
|
-
};
|
|
8961
|
+
}
|
|
8962
|
+
function interruptible(dialing, signal) {
|
|
8963
|
+
return new Promise((resolve, reject) => {
|
|
8964
|
+
const abort = () => reject(new KernelError("EINTR"));
|
|
8965
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
8966
|
+
dialing.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
8967
|
+
});
|
|
8968
|
+
}
|
|
8969
|
+
function unnamed(domain) {
|
|
8970
|
+
return domain === "inet" ? { family: "inet", host: "0.0.0.0", port: 0 } : { family: "unix", path: "" };
|
|
8971
|
+
}
|
|
8972
|
+
async function accept(proc, fd, nonblock) {
|
|
8973
|
+
const listener = socketAt(proc.fds, fd);
|
|
8974
|
+
const waits = !nonblock && !pollFile(listener).readable;
|
|
8975
|
+
const socket = await listener.accept(waits ? proc.blocking() : void 0, nonblock);
|
|
8976
|
+
return { fd: proc.fds.install(new OpenFile(socket), 3), peer: socket.peer };
|
|
8977
|
+
}
|
|
8599
8978
|
|
|
8600
8979
|
// src/kernel/vfs-file.ts
|
|
8601
8980
|
var O_ACCMODE = 3;
|
|
@@ -9198,6 +9577,9 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
9198
9577
|
"dl-closure",
|
|
9199
9578
|
"dl-closure-free",
|
|
9200
9579
|
"dl-reserve",
|
|
9580
|
+
"dl-load-reserve",
|
|
9581
|
+
"dl-lock",
|
|
9582
|
+
"dl-unlock",
|
|
9201
9583
|
"fd-renumber",
|
|
9202
9584
|
"fd-promote",
|
|
9203
9585
|
"fd-open-tty",
|
|
@@ -9236,6 +9618,7 @@ function isWasmSyscall(req) {
|
|
|
9236
9618
|
return typeof op === "string" && SYSCALL_OPS.has(op);
|
|
9237
9619
|
}
|
|
9238
9620
|
var MAX_READ = 1024 * 1024;
|
|
9621
|
+
var WRITE_ACCESS = 3;
|
|
9239
9622
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
9240
9623
|
var DEFAULT_UMASK = 18;
|
|
9241
9624
|
var DYING = { ok: false, errno: "EINTR", message: "the process is being killed" };
|
|
@@ -9256,7 +9639,7 @@ var WasmProcess = class {
|
|
|
9256
9639
|
stopped = 0;
|
|
9257
9640
|
stops = 0;
|
|
9258
9641
|
owed = false;
|
|
9259
|
-
|
|
9642
|
+
waiting = /* @__PURE__ */ new Set();
|
|
9260
9643
|
resumed = Promise.resolve();
|
|
9261
9644
|
wake;
|
|
9262
9645
|
stateListeners = [];
|
|
@@ -9312,7 +9695,8 @@ var WasmProcess = class {
|
|
|
9312
9695
|
return "terminate";
|
|
9313
9696
|
}
|
|
9314
9697
|
this.options.onPending?.(sig);
|
|
9315
|
-
if (this.options.jobs?.keyboard && KEYBOARD.has(sig)
|
|
9698
|
+
if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
|
|
9699
|
+
this.owed = true;
|
|
9316
9700
|
const blocked = this.interrupt;
|
|
9317
9701
|
this.interrupt = new AbortController();
|
|
9318
9702
|
blocked.abort();
|
|
@@ -9357,10 +9741,15 @@ var WasmProcess = class {
|
|
|
9357
9741
|
await this.resumed;
|
|
9358
9742
|
if (this.dying) return DYING;
|
|
9359
9743
|
const stops = this.stops;
|
|
9360
|
-
const
|
|
9361
|
-
const
|
|
9744
|
+
const scope = new AbortController();
|
|
9745
|
+
const forward = () => scope.abort();
|
|
9746
|
+
if (cancelled?.aborted) scope.abort();
|
|
9747
|
+
cancelled?.addEventListener("abort", forward, { once: true });
|
|
9748
|
+
const result = await this.dispatch(req, scope.signal).finally(() => {
|
|
9749
|
+
cancelled?.removeEventListener("abort", forward);
|
|
9750
|
+
this.waiting.delete(scope.signal);
|
|
9751
|
+
});
|
|
9362
9752
|
if (this.dying) return DYING;
|
|
9363
|
-
if (!result.ok && result.errno === "EINTR" && this.waits !== waits) this.owed = false;
|
|
9364
9753
|
const restart = !result.ok && result.errno === "EINTR" && this.stops !== stops;
|
|
9365
9754
|
if (restart && !this.options.hasPending?.()) continue;
|
|
9366
9755
|
await this.resumed;
|
|
@@ -9413,12 +9802,31 @@ var WasmProcess = class {
|
|
|
9413
9802
|
refuseIfPending(restart) {
|
|
9414
9803
|
if (restart && this.options.hasPending?.()) throw new KernelError("EINTR");
|
|
9415
9804
|
}
|
|
9805
|
+
async procWait(req, cancelled) {
|
|
9806
|
+
const flags = {
|
|
9807
|
+
untraced: req.untraced,
|
|
9808
|
+
continued: req.continued,
|
|
9809
|
+
inGroup: this.waitGroup(req.pid)
|
|
9810
|
+
};
|
|
9811
|
+
if (this.owed && !req.nohang) {
|
|
9812
|
+
const now = await this.children.wait(req.pid, true, this.interrupt.signal, flags);
|
|
9813
|
+
if (now[0] !== 0) return now;
|
|
9814
|
+
}
|
|
9815
|
+
const signal = req.nohang ? this.interrupt.signal : this.blockingSignal(cancelled);
|
|
9816
|
+
const waited = await this.children.wait(req.pid, req.nohang, signal, flags);
|
|
9817
|
+
return waited;
|
|
9818
|
+
}
|
|
9416
9819
|
blockingSignal(cancelled, owing = true) {
|
|
9417
|
-
if (owing
|
|
9418
|
-
|
|
9820
|
+
if (owing && this.owed) {
|
|
9821
|
+
this.owed = false;
|
|
9419
9822
|
throw new KernelError("EINTR");
|
|
9420
9823
|
}
|
|
9421
|
-
|
|
9824
|
+
if (this.options.hasPending?.() || cancelled.aborted) throw new KernelError("EINTR");
|
|
9825
|
+
if (owing) this.waiting.add(cancelled);
|
|
9826
|
+
return this.cancelSignal(cancelled);
|
|
9827
|
+
}
|
|
9828
|
+
cancelSignal(cancelled) {
|
|
9829
|
+
return AbortSignal.any([this.interrupt.signal, cancelled]);
|
|
9422
9830
|
}
|
|
9423
9831
|
async read(req, cancelled) {
|
|
9424
9832
|
const file = this.fds.get(req.fd).file;
|
|
@@ -9442,15 +9850,22 @@ var WasmProcess = class {
|
|
|
9442
9850
|
if (nonblock) return file.write(body, AbortSignal.abort());
|
|
9443
9851
|
return file.write(
|
|
9444
9852
|
body,
|
|
9445
|
-
this.options.hasPending?.() ? AbortSignal.abort() : this.
|
|
9853
|
+
this.options.hasPending?.() ? AbortSignal.abort() : this.cancelSignal(cancelled)
|
|
9446
9854
|
);
|
|
9447
9855
|
}
|
|
9448
9856
|
async openVfs(req) {
|
|
9857
|
+
if (inProc(req.path)) return this.openProc(req, req.path);
|
|
9858
|
+
const alias = req.orphan ? void 0 : await procAlias(this.options.fs, req.path, !req.exclusive);
|
|
9859
|
+
if (alias !== void 0) return this.openProc(req, alias);
|
|
9449
9860
|
await refuseReadonly(this.options.fs, req.path, req.flags, req);
|
|
9450
9861
|
const fd = this.fds.install(heldFile(), 3);
|
|
9451
9862
|
try {
|
|
9452
9863
|
const nodes = this.nodes;
|
|
9453
9864
|
const path = req.orphan ? req.path : req.exclusive ? await nodes.entryKey(req.path) : req.create ? await nodes.targetKey(req.path) : await this.keptOr(await nodes.targetKey(req.path), req.handle);
|
|
9865
|
+
if (inProc(path)) {
|
|
9866
|
+
this.fds.installAt(fd, await this.procFile(req, path));
|
|
9867
|
+
return fd;
|
|
9868
|
+
}
|
|
9454
9869
|
const open = { ...req, path };
|
|
9455
9870
|
if (req.exclusive) {
|
|
9456
9871
|
await nodes.createExclusive(path);
|
|
@@ -9472,6 +9887,22 @@ var WasmProcess = class {
|
|
|
9472
9887
|
}
|
|
9473
9888
|
return fd;
|
|
9474
9889
|
}
|
|
9890
|
+
async openProc(req, path) {
|
|
9891
|
+
return this.fds.install(await this.procFile(req, path), 3);
|
|
9892
|
+
}
|
|
9893
|
+
async procFile(req, path) {
|
|
9894
|
+
if (req.flags & WRITE_ACCESS || req.create || req.truncate || req.exclusive) {
|
|
9895
|
+
throw new KernelError("EROFS");
|
|
9896
|
+
}
|
|
9897
|
+
const tree = new ProcTree(
|
|
9898
|
+
{
|
|
9899
|
+
procList: () => this.options.processes?.() ?? { boot: 0, processes: [] },
|
|
9900
|
+
mountList: () => this.options.mounts?.() ?? []
|
|
9901
|
+
},
|
|
9902
|
+
(await this.options.identity?.())?.pid ?? this.pid
|
|
9903
|
+
);
|
|
9904
|
+
return memoryFile(tree.read(path), path, req.position);
|
|
9905
|
+
}
|
|
9475
9906
|
openVfsFile(req) {
|
|
9476
9907
|
return vfsFile(
|
|
9477
9908
|
this.options.fs,
|
|
@@ -9563,6 +9994,11 @@ var WasmProcess = class {
|
|
|
9563
9994
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
9564
9995
|
case "fd-select": {
|
|
9565
9996
|
const { read, write, timeoutMs } = req;
|
|
9997
|
+
if (this.owed && timeoutMs !== 0) {
|
|
9998
|
+
const ready2 = await selectFds(this.fds, read, write, 0, this.interrupt.signal);
|
|
9999
|
+
if (ready2.read.length + ready2.write.length > 0)
|
|
10000
|
+
return { ok: true, kind: "json", json: ready2 };
|
|
10001
|
+
}
|
|
9566
10002
|
const signal = this.blockingSignal(cancelled, timeoutMs !== 0);
|
|
9567
10003
|
const selected = await selectFds(this.fds, read, write, timeoutMs, signal);
|
|
9568
10004
|
return { ok: true, kind: "json", json: selected };
|
|
@@ -9760,16 +10196,8 @@ var WasmProcess = class {
|
|
|
9760
10196
|
case "proc-spawn":
|
|
9761
10197
|
this.refuseIfPending(req.restart);
|
|
9762
10198
|
return { ok: true, kind: "json", json: await this.spawn(req) };
|
|
9763
|
-
case "proc-wait":
|
|
9764
|
-
|
|
9765
|
-
const flags = {
|
|
9766
|
-
untraced: req.untraced,
|
|
9767
|
-
continued: req.continued,
|
|
9768
|
-
inGroup: this.waitGroup(req.pid)
|
|
9769
|
-
};
|
|
9770
|
-
const waited = await this.children.wait(req.pid, req.nohang, signal, flags);
|
|
9771
|
-
return { ok: true, kind: "json", json: waited };
|
|
9772
|
-
}
|
|
10199
|
+
case "proc-wait":
|
|
10200
|
+
return { ok: true, kind: "json", json: await this.procWait(req, cancelled) };
|
|
9773
10201
|
case "proc-identity":
|
|
9774
10202
|
return { ok: true, kind: "json", json: await this.options.identity?.() ?? null };
|
|
9775
10203
|
case "proc-exec": {
|
|
@@ -9801,7 +10229,7 @@ var WasmProcess = class {
|
|
|
9801
10229
|
return { ok: true, kind: "json", json: this.options.mounts?.() ?? [] };
|
|
9802
10230
|
case "mount":
|
|
9803
10231
|
case "umount":
|
|
9804
|
-
return this.mountSyscall(req);
|
|
10232
|
+
return this.mountSyscall(req, cancelled);
|
|
9805
10233
|
case "proc-alarm":
|
|
9806
10234
|
this.setAlarm(req.sig, req.firstMs ?? req.ms, req.repeat ? req.ms : 0, req.timer);
|
|
9807
10235
|
return { ok: true, kind: "void" };
|
|
@@ -9822,6 +10250,18 @@ var WasmProcess = class {
|
|
|
9822
10250
|
return { ok: true, kind: "void" };
|
|
9823
10251
|
case "dl-reserve":
|
|
9824
10252
|
return { ok: true, kind: "json", json: this.reserveSlots(req.floor, req.size) };
|
|
10253
|
+
case "dl-load-reserve":
|
|
10254
|
+
return {
|
|
10255
|
+
ok: true,
|
|
10256
|
+
kind: "json",
|
|
10257
|
+
json: { base: this.reserveSlots(req.floor, req.size), handle: this.closures.handle++ }
|
|
10258
|
+
};
|
|
10259
|
+
case "dl-lock":
|
|
10260
|
+
await this.lockDl(req.owner);
|
|
10261
|
+
return { ok: true, kind: "void" };
|
|
10262
|
+
case "dl-unlock":
|
|
10263
|
+
this.unlockDl(req.owner);
|
|
10264
|
+
return { ok: true, kind: "void" };
|
|
9825
10265
|
case "sig-mask":
|
|
9826
10266
|
this.caught = req.caught;
|
|
9827
10267
|
this.ignored = req.ignored;
|
|
@@ -9836,14 +10276,14 @@ var WasmProcess = class {
|
|
|
9836
10276
|
return { ok: true, kind: "bytes", bytes: this.children.captured(req.pid, req.slot) };
|
|
9837
10277
|
}
|
|
9838
10278
|
}
|
|
9839
|
-
async mountSyscall(req) {
|
|
10279
|
+
async mountSyscall(req, cancelled) {
|
|
9840
10280
|
const { mount, umount } = this.options;
|
|
9841
10281
|
if (!mount || !umount) throw new KernelError("ENOSYS");
|
|
9842
10282
|
try {
|
|
9843
10283
|
if (req.op === "umount") await umount(req.target, req.flags);
|
|
9844
10284
|
else {
|
|
9845
10285
|
const { source, target, type, flags, data } = req;
|
|
9846
|
-
const signal = this.blockingSignal();
|
|
10286
|
+
const signal = this.blockingSignal(cancelled);
|
|
9847
10287
|
await Promise.race([mount({ source, target, type, flags, data }, signal), aborted(signal)]);
|
|
9848
10288
|
}
|
|
9849
10289
|
} catch (err) {
|
|
@@ -9858,7 +10298,12 @@ var WasmProcess = class {
|
|
|
9858
10298
|
}
|
|
9859
10299
|
alarm;
|
|
9860
10300
|
dlLog = [];
|
|
9861
|
-
closures = {
|
|
10301
|
+
closures = {
|
|
10302
|
+
next: 0,
|
|
10303
|
+
handle: 1,
|
|
10304
|
+
free: [],
|
|
10305
|
+
live: /* @__PURE__ */ new Set()
|
|
10306
|
+
};
|
|
9862
10307
|
allocateClosure(floor) {
|
|
9863
10308
|
const index = this.closures.free.pop() ?? Math.max(floor, this.closures.next);
|
|
9864
10309
|
this.closures.next = Math.max(this.closures.next, index + 1);
|
|
@@ -9871,6 +10316,47 @@ var WasmProcess = class {
|
|
|
9871
10316
|
this.closures.free.push(index);
|
|
9872
10317
|
this.dlLog.push({ kind: "closure-free", index });
|
|
9873
10318
|
}
|
|
10319
|
+
dlLock = {
|
|
10320
|
+
owner: 0,
|
|
10321
|
+
depth: 0,
|
|
10322
|
+
waiters: /* @__PURE__ */ new Set()
|
|
10323
|
+
};
|
|
10324
|
+
async lockDl(owner) {
|
|
10325
|
+
while (this.dlLock.depth > 0 && this.dlLock.owner !== owner) {
|
|
10326
|
+
if (this.dying) throw new KernelError("EINTR");
|
|
10327
|
+
const interrupt = this.interrupt.signal;
|
|
10328
|
+
const gone = await new Promise((resolve) => {
|
|
10329
|
+
const waiter = {
|
|
10330
|
+
owner,
|
|
10331
|
+
wake: (ended) => {
|
|
10332
|
+
this.dlLock.waiters.delete(waiter);
|
|
10333
|
+
interrupt.removeEventListener("abort", recheck);
|
|
10334
|
+
resolve(ended);
|
|
10335
|
+
}
|
|
10336
|
+
};
|
|
10337
|
+
const recheck = () => waiter.wake(false);
|
|
10338
|
+
this.dlLock.waiters.add(waiter);
|
|
10339
|
+
interrupt.addEventListener("abort", recheck, { once: true });
|
|
10340
|
+
});
|
|
10341
|
+
if (gone) throw new KernelError("EINTR");
|
|
10342
|
+
}
|
|
10343
|
+
this.dlLock.owner = owner;
|
|
10344
|
+
this.dlLock.depth++;
|
|
10345
|
+
}
|
|
10346
|
+
threadEnded(tid) {
|
|
10347
|
+
for (const waiter of [...this.dlLock.waiters]) if (waiter.owner === tid) waiter.wake(true);
|
|
10348
|
+
if (this.dlLock.depth === 0 || this.dlLock.owner !== tid) return;
|
|
10349
|
+
this.dlLock.depth = 0;
|
|
10350
|
+
this.wakeDl();
|
|
10351
|
+
}
|
|
10352
|
+
unlockDl(owner) {
|
|
10353
|
+
if (this.dlLock.depth === 0 || this.dlLock.owner !== owner) throw new KernelError("EPERM");
|
|
10354
|
+
this.dlLock.depth--;
|
|
10355
|
+
if (this.dlLock.depth === 0) this.wakeDl();
|
|
10356
|
+
}
|
|
10357
|
+
wakeDl() {
|
|
10358
|
+
for (const waiter of [...this.dlLock.waiters]) waiter.wake(false);
|
|
10359
|
+
}
|
|
9874
10360
|
reserveSlots(floor, size) {
|
|
9875
10361
|
const base = Math.max(floor, this.closures.next);
|
|
9876
10362
|
this.closures.next = base + size;
|
|
@@ -10182,6 +10668,7 @@ function spawnWasmProcess(opts) {
|
|
|
10182
10668
|
const endThread = (tid) => {
|
|
10183
10669
|
const end = threads.get(tid);
|
|
10184
10670
|
threads.delete(tid);
|
|
10671
|
+
process2.threadEnded(tid);
|
|
10185
10672
|
end?.();
|
|
10186
10673
|
};
|
|
10187
10674
|
const spawnThread = (thread) => {
|
|
@@ -10974,8 +11461,8 @@ function umountCall(target, flags) {
|
|
|
10974
11461
|
var FSTAB_PATH = "/etc/fstab";
|
|
10975
11462
|
var FSTAB_RETRIES = [1e3, 4e3, 16e3];
|
|
10976
11463
|
var FINAL = /* @__PURE__ */ new Set(["EINVAL", "EBUSY", "EPERM", "EACCES"]);
|
|
10977
|
-
function unescape(
|
|
10978
|
-
return
|
|
11464
|
+
function unescape(field3) {
|
|
11465
|
+
return field3.replace(
|
|
10979
11466
|
/\\([0-7]{3})/g,
|
|
10980
11467
|
(_, octal) => String.fromCharCode(Number.parseInt(octal, 8))
|
|
10981
11468
|
);
|
|
@@ -11868,7 +12355,7 @@ function importedMemory(bytes) {
|
|
|
11868
12355
|
const count = u32();
|
|
11869
12356
|
for (let i = 0; i < count; i++) {
|
|
11870
12357
|
const module = name2();
|
|
11871
|
-
const
|
|
12358
|
+
const field3 = name2();
|
|
11872
12359
|
const kind = bytes[at++];
|
|
11873
12360
|
if (kind === 0) u32();
|
|
11874
12361
|
else if (kind === 1) {
|
|
@@ -11876,7 +12363,7 @@ function importedMemory(bytes) {
|
|
|
11876
12363
|
limits();
|
|
11877
12364
|
} else if (kind === 2) {
|
|
11878
12365
|
const l = limits();
|
|
11879
|
-
return { module, name:
|
|
12366
|
+
return { module, name: field3, ...l };
|
|
11880
12367
|
} else if (kind === 3) at += 2;
|
|
11881
12368
|
else if (kind === 4) {
|
|
11882
12369
|
at++;
|
|
@@ -11967,12 +12454,12 @@ function readImports(r, types) {
|
|
|
11967
12454
|
const foreign = {};
|
|
11968
12455
|
for (let i = r.u32(); i > 0; i--) {
|
|
11969
12456
|
const module = r.name();
|
|
11970
|
-
const
|
|
12457
|
+
const field3 = r.name();
|
|
11971
12458
|
const kind = r.byte();
|
|
11972
12459
|
if (kind !== 0) skipImport(r, kind);
|
|
11973
12460
|
else {
|
|
11974
12461
|
const type = types[r.u32()] ?? "other";
|
|
11975
|
-
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[
|
|
12462
|
+
if (!RESERVED_NAMESPACES.has(module)) (foreign[module] ??= {})[field3] = type;
|
|
11976
12463
|
}
|
|
11977
12464
|
}
|
|
11978
12465
|
return foreign;
|