@ai-ecoverse/slicc-kernel 1.94.4 → 1.95.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/README.md +85 -3
- package/dist/kernel-worker.js +393 -54
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +108 -21
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +391 -52
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +108 -21
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -567,8 +567,8 @@ async function inParent(g, op, path, old = false) {
|
|
|
567
567
|
const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, linked(g, DIR));
|
|
568
568
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
569
569
|
if (dir.link) return deny(g, op, dir.denied);
|
|
570
|
-
const
|
|
571
|
-
if (!
|
|
570
|
+
const lookup4 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
571
|
+
if (!lookup4 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
572
572
|
}
|
|
573
573
|
async function makeIn(g, op, path) {
|
|
574
574
|
for (let dir = parentOf(path); ; dir = parentOf(dir)) {
|
|
@@ -888,6 +888,7 @@ function pollFile(file) {
|
|
|
888
888
|
}
|
|
889
889
|
var OpenFile = class {
|
|
890
890
|
refs = 1;
|
|
891
|
+
closers;
|
|
891
892
|
file;
|
|
892
893
|
constructor(file) {
|
|
893
894
|
this.file = file;
|
|
@@ -896,9 +897,18 @@ var OpenFile = class {
|
|
|
896
897
|
this.refs += 1;
|
|
897
898
|
return this;
|
|
898
899
|
}
|
|
900
|
+
onClose(fn) {
|
|
901
|
+
this.closers ??= /* @__PURE__ */ new Set();
|
|
902
|
+
this.closers.add(fn);
|
|
903
|
+
return () => void this.closers?.delete(fn);
|
|
904
|
+
}
|
|
899
905
|
release() {
|
|
900
906
|
this.refs -= 1;
|
|
901
|
-
if (this.refs
|
|
907
|
+
if (this.refs !== 0) return;
|
|
908
|
+
const closers = this.closers;
|
|
909
|
+
this.closers = void 0;
|
|
910
|
+
for (const fn of closers ?? []) fn();
|
|
911
|
+
return this.file.close();
|
|
902
912
|
}
|
|
903
913
|
};
|
|
904
914
|
function openPipe(capacity) {
|
|
@@ -1446,7 +1456,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
1446
1456
|
return {
|
|
1447
1457
|
readable: this.readShut || rx.readReady,
|
|
1448
1458
|
writable: this.writeShut || tx.writeReady,
|
|
1449
|
-
hangup: rx.writersGone && tx.readersGone
|
|
1459
|
+
hangup: rx.writersGone && tx.readersGone,
|
|
1460
|
+
rdhup: rx.writersGone
|
|
1450
1461
|
};
|
|
1451
1462
|
}
|
|
1452
1463
|
changed(signal) {
|
|
@@ -10643,7 +10654,7 @@ function mountTable(mounts = []) {
|
|
|
10643
10654
|
}
|
|
10644
10655
|
|
|
10645
10656
|
// src/version.ts
|
|
10646
|
-
var KERNEL_VERSION = true ? "1.
|
|
10657
|
+
var KERNEL_VERSION = true ? "1.95.0" : "0.0.0-dev";
|
|
10647
10658
|
var OS_RELEASE = "6.0.0-slicc";
|
|
10648
10659
|
function procVersion() {
|
|
10649
10660
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11030,6 +11041,295 @@ async function procAlias(fs, path, follow2) {
|
|
|
11030
11041
|
return step.value;
|
|
11031
11042
|
}
|
|
11032
11043
|
|
|
11044
|
+
// src/kernel/eventfd.ts
|
|
11045
|
+
var EVENTFD_MAX = 0xfffffffffffffffen;
|
|
11046
|
+
var Notifier = class {
|
|
11047
|
+
waiters = [];
|
|
11048
|
+
wait(signal) {
|
|
11049
|
+
if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
11050
|
+
return new Promise((resolve2, reject) => {
|
|
11051
|
+
const onAbort = () => {
|
|
11052
|
+
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
11053
|
+
reject(new KernelError("EINTR"));
|
|
11054
|
+
};
|
|
11055
|
+
const waiter = () => {
|
|
11056
|
+
signal?.removeEventListener("abort", onAbort);
|
|
11057
|
+
resolve2();
|
|
11058
|
+
};
|
|
11059
|
+
this.waiters.push(waiter);
|
|
11060
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
11061
|
+
});
|
|
11062
|
+
}
|
|
11063
|
+
wake() {
|
|
11064
|
+
const waiters = this.waiters;
|
|
11065
|
+
this.waiters = [];
|
|
11066
|
+
for (const resolve2 of waiters) resolve2();
|
|
11067
|
+
}
|
|
11068
|
+
};
|
|
11069
|
+
function blocked(signal) {
|
|
11070
|
+
if (signal?.aborted) throw new KernelError("EAGAIN");
|
|
11071
|
+
}
|
|
11072
|
+
var EventFd = class _EventFd {
|
|
11073
|
+
static SIZE = 8;
|
|
11074
|
+
count;
|
|
11075
|
+
semaphore;
|
|
11076
|
+
changes = new Notifier();
|
|
11077
|
+
constructor(initial, semaphore) {
|
|
11078
|
+
this.count = initial;
|
|
11079
|
+
this.semaphore = semaphore;
|
|
11080
|
+
}
|
|
11081
|
+
async read(max, signal) {
|
|
11082
|
+
if (max < _EventFd.SIZE) throw new KernelError("EINVAL");
|
|
11083
|
+
while (this.count === 0n) {
|
|
11084
|
+
blocked(signal);
|
|
11085
|
+
await this.changes.wait(signal);
|
|
11086
|
+
}
|
|
11087
|
+
const value = this.semaphore ? 1n : this.count;
|
|
11088
|
+
this.count -= value;
|
|
11089
|
+
this.changes.wake();
|
|
11090
|
+
const out = new Uint8Array(_EventFd.SIZE);
|
|
11091
|
+
new DataView(out.buffer).setBigUint64(0, value, true);
|
|
11092
|
+
return out;
|
|
11093
|
+
}
|
|
11094
|
+
async write(bytes, signal) {
|
|
11095
|
+
if (bytes.length < _EventFd.SIZE) throw new KernelError("EINVAL");
|
|
11096
|
+
const value = new DataView(bytes.buffer, bytes.byteOffset, _EventFd.SIZE).getBigUint64(0, true);
|
|
11097
|
+
if (value > EVENTFD_MAX) throw new KernelError("EINVAL");
|
|
11098
|
+
while (EVENTFD_MAX - this.count < value) {
|
|
11099
|
+
blocked(signal);
|
|
11100
|
+
await this.changes.wait(signal);
|
|
11101
|
+
}
|
|
11102
|
+
this.count += value;
|
|
11103
|
+
if (value > 0n) this.changes.wake();
|
|
11104
|
+
return _EventFd.SIZE;
|
|
11105
|
+
}
|
|
11106
|
+
poll() {
|
|
11107
|
+
return { readable: this.count > 0n, writable: this.count < EVENTFD_MAX, hangup: false };
|
|
11108
|
+
}
|
|
11109
|
+
changed(signal) {
|
|
11110
|
+
return this.changes.wait(signal);
|
|
11111
|
+
}
|
|
11112
|
+
close() {
|
|
11113
|
+
this.changes.wake();
|
|
11114
|
+
}
|
|
11115
|
+
};
|
|
11116
|
+
|
|
11117
|
+
// src/kernel/epoll.ts
|
|
11118
|
+
var EPOLL = {
|
|
11119
|
+
IN: 1,
|
|
11120
|
+
OUT: 2,
|
|
11121
|
+
RDHUP: 4,
|
|
11122
|
+
PRI: 8,
|
|
11123
|
+
ERR: 16,
|
|
11124
|
+
HUP: 32,
|
|
11125
|
+
ET: 64,
|
|
11126
|
+
ONESHOT: 128
|
|
11127
|
+
};
|
|
11128
|
+
var ALWAYS = EPOLL.ERR | EPOLL.HUP;
|
|
11129
|
+
var ASKED = EPOLL.IN | EPOLL.OUT | EPOLL.RDHUP;
|
|
11130
|
+
var RETRY_MS = 50;
|
|
11131
|
+
var UNPOLLABLE = /* @__PURE__ */ new Set(["file", "held", "device"]);
|
|
11132
|
+
var EPOLL_OPS = [
|
|
11133
|
+
"epoll-create",
|
|
11134
|
+
"epoll-ctl",
|
|
11135
|
+
"epoll-wait",
|
|
11136
|
+
"eventfd-open"
|
|
11137
|
+
];
|
|
11138
|
+
function levelOf(file) {
|
|
11139
|
+
const state = pollFile(file);
|
|
11140
|
+
let bits2 = 0;
|
|
11141
|
+
if (state.readable) bits2 |= EPOLL.IN;
|
|
11142
|
+
if (state.writable) bits2 |= EPOLL.OUT;
|
|
11143
|
+
if (state.rdhup) bits2 |= EPOLL.RDHUP;
|
|
11144
|
+
if (state.hangup) bits2 |= file.read ? EPOLL.HUP : EPOLL.ERR;
|
|
11145
|
+
return bits2;
|
|
11146
|
+
}
|
|
11147
|
+
function due(interest, level) {
|
|
11148
|
+
if (!interest.armed) return 0;
|
|
11149
|
+
const ready2 = level & (interest.events & ASKED | ALWAYS);
|
|
11150
|
+
if (ready2 === 0) return 0;
|
|
11151
|
+
if ((interest.events & EPOLL.ET) !== 0 && interest.reported === interest.gen) return 0;
|
|
11152
|
+
return ready2;
|
|
11153
|
+
}
|
|
11154
|
+
function consume(interest) {
|
|
11155
|
+
interest.reported = interest.gen;
|
|
11156
|
+
if ((interest.events & EPOLL.ONESHOT) !== 0) interest.armed = false;
|
|
11157
|
+
}
|
|
11158
|
+
function lookup(fds, fd) {
|
|
11159
|
+
try {
|
|
11160
|
+
return fds.get(fd);
|
|
11161
|
+
} catch {
|
|
11162
|
+
return void 0;
|
|
11163
|
+
}
|
|
11164
|
+
}
|
|
11165
|
+
function pause(ms, signal) {
|
|
11166
|
+
return new Promise((resolve2) => {
|
|
11167
|
+
const timer = setTimeout(resolve2, ms);
|
|
11168
|
+
signal.addEventListener(
|
|
11169
|
+
"abort",
|
|
11170
|
+
() => {
|
|
11171
|
+
clearTimeout(timer);
|
|
11172
|
+
resolve2();
|
|
11173
|
+
},
|
|
11174
|
+
{ once: true }
|
|
11175
|
+
);
|
|
11176
|
+
});
|
|
11177
|
+
}
|
|
11178
|
+
var EpollFile = class _EpollFile {
|
|
11179
|
+
regs = /* @__PURE__ */ new Map();
|
|
11180
|
+
changes = new Notifier();
|
|
11181
|
+
cursor = 0;
|
|
11182
|
+
ctl(fds, how, fd, events, data) {
|
|
11183
|
+
const open = fds.get(fd);
|
|
11184
|
+
if (open.file === this) throw new KernelError("EINVAL");
|
|
11185
|
+
const known = this.regs.get(fd);
|
|
11186
|
+
const current = known?.open === open ? known : void 0;
|
|
11187
|
+
if (how === "add" || how === "set" && !current) {
|
|
11188
|
+
if (current) throw new KernelError("EEXIST");
|
|
11189
|
+
if (UNPOLLABLE.has(kernelFdKind(open.file))) throw new KernelError("EPERM");
|
|
11190
|
+
if (open.file instanceof _EpollFile && open.file.reaches(this)) throw new KernelError("ELOOP");
|
|
11191
|
+
if (known) this.drop(known);
|
|
11192
|
+
this.register(fd, open, events, data);
|
|
11193
|
+
} else if (!current) {
|
|
11194
|
+
throw new KernelError("ENOENT");
|
|
11195
|
+
} else if (how === "del") {
|
|
11196
|
+
this.drop(current);
|
|
11197
|
+
} else {
|
|
11198
|
+
current.events = events;
|
|
11199
|
+
current.data = data;
|
|
11200
|
+
current.armed = true;
|
|
11201
|
+
current.gen++;
|
|
11202
|
+
}
|
|
11203
|
+
this.changes.wake();
|
|
11204
|
+
}
|
|
11205
|
+
reaches(target) {
|
|
11206
|
+
if (this === target) return true;
|
|
11207
|
+
return [...this.regs.values()].some(
|
|
11208
|
+
(reg) => reg.open.file instanceof _EpollFile && reg.open.file.reaches(target)
|
|
11209
|
+
);
|
|
11210
|
+
}
|
|
11211
|
+
collect(fds, max) {
|
|
11212
|
+
const list = [...this.regs.values()];
|
|
11213
|
+
const out = [];
|
|
11214
|
+
const start2 = list.length === 0 ? 0 : this.cursor % list.length;
|
|
11215
|
+
for (let i = 0; i < list.length && out.length < max; i++) {
|
|
11216
|
+
const reg = list[(start2 + i) % list.length];
|
|
11217
|
+
if (lookup(fds, reg.fd) !== reg.open) {
|
|
11218
|
+
this.drop(reg);
|
|
11219
|
+
continue;
|
|
11220
|
+
}
|
|
11221
|
+
const bits2 = due(reg, levelOf(reg.open.file));
|
|
11222
|
+
if (bits2 === 0) continue;
|
|
11223
|
+
consume(reg);
|
|
11224
|
+
out.push({ events: bits2, data: reg.data });
|
|
11225
|
+
this.cursor = start2 + i + 1;
|
|
11226
|
+
}
|
|
11227
|
+
return out;
|
|
11228
|
+
}
|
|
11229
|
+
async wait(fds, max, timeoutMs, signal) {
|
|
11230
|
+
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
11231
|
+
for (; ; ) {
|
|
11232
|
+
const events = this.collect(fds, max);
|
|
11233
|
+
if (events.length > 0 || Date.now() >= deadline) return events;
|
|
11234
|
+
const round = new AbortController();
|
|
11235
|
+
const woken = this.changes.wait(AbortSignal.any([round.signal, signal]));
|
|
11236
|
+
woken.catch(() => void 0);
|
|
11237
|
+
let timer;
|
|
11238
|
+
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
11239
|
+
try {
|
|
11240
|
+
await Promise.race([woken, ...expiry]);
|
|
11241
|
+
} finally {
|
|
11242
|
+
round.abort();
|
|
11243
|
+
clearTimeout(timer);
|
|
11244
|
+
}
|
|
11245
|
+
}
|
|
11246
|
+
}
|
|
11247
|
+
poll() {
|
|
11248
|
+
const ready2 = [...this.regs.values()].some((reg) => due(reg, levelOf(reg.open.file)) !== 0);
|
|
11249
|
+
return { readable: ready2, writable: false, hangup: false };
|
|
11250
|
+
}
|
|
11251
|
+
changed(signal) {
|
|
11252
|
+
return this.changes.wait(signal);
|
|
11253
|
+
}
|
|
11254
|
+
close() {
|
|
11255
|
+
for (const reg of [...this.regs.values()]) this.drop(reg);
|
|
11256
|
+
this.changes.wake();
|
|
11257
|
+
}
|
|
11258
|
+
register(fd, open, events, data) {
|
|
11259
|
+
const stop = new AbortController();
|
|
11260
|
+
const unhook = open.onClose(() => {
|
|
11261
|
+
this.drop(reg);
|
|
11262
|
+
this.changes.wake();
|
|
11263
|
+
});
|
|
11264
|
+
const reg = {
|
|
11265
|
+
fd,
|
|
11266
|
+
open,
|
|
11267
|
+
events,
|
|
11268
|
+
data,
|
|
11269
|
+
gen: 1,
|
|
11270
|
+
reported: 0,
|
|
11271
|
+
armed: true,
|
|
11272
|
+
stop,
|
|
11273
|
+
unhook
|
|
11274
|
+
};
|
|
11275
|
+
this.regs.set(fd, reg);
|
|
11276
|
+
void this.watch(reg);
|
|
11277
|
+
}
|
|
11278
|
+
drop(reg) {
|
|
11279
|
+
reg.stop.abort();
|
|
11280
|
+
reg.unhook();
|
|
11281
|
+
if (this.regs.get(reg.fd) === reg) this.regs.delete(reg.fd);
|
|
11282
|
+
}
|
|
11283
|
+
async watch(reg) {
|
|
11284
|
+
const file = reg.open.file;
|
|
11285
|
+
const { signal } = reg.stop;
|
|
11286
|
+
while (file.changed && !signal.aborted) {
|
|
11287
|
+
const round = new AbortController();
|
|
11288
|
+
const stop = () => round.abort();
|
|
11289
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
11290
|
+
let failed3 = false;
|
|
11291
|
+
try {
|
|
11292
|
+
await file.changed(round.signal);
|
|
11293
|
+
} catch {
|
|
11294
|
+
failed3 = true;
|
|
11295
|
+
} finally {
|
|
11296
|
+
round.abort();
|
|
11297
|
+
signal.removeEventListener("abort", stop);
|
|
11298
|
+
}
|
|
11299
|
+
if (signal.aborted) return;
|
|
11300
|
+
reg.gen++;
|
|
11301
|
+
this.changes.wake();
|
|
11302
|
+
if (failed3) await pause(RETRY_MS, signal);
|
|
11303
|
+
}
|
|
11304
|
+
}
|
|
11305
|
+
};
|
|
11306
|
+
function epollAt(fds, fd) {
|
|
11307
|
+
const file = fds.get(fd).file;
|
|
11308
|
+
if (!(file instanceof EpollFile)) throw new KernelError("EINVAL");
|
|
11309
|
+
return file;
|
|
11310
|
+
}
|
|
11311
|
+
var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
11312
|
+
async function epollSyscall(req, proc) {
|
|
11313
|
+
const { fds } = proc;
|
|
11314
|
+
switch (req.op) {
|
|
11315
|
+
case "epoll-create":
|
|
11316
|
+
return ok(fds.install(new OpenFile(new EpollFile()), 3));
|
|
11317
|
+
case "eventfd-open":
|
|
11318
|
+
return ok(fds.install(new OpenFile(new EventFd(BigInt(req.initial), req.semaphore)), 3));
|
|
11319
|
+
case "epoll-ctl":
|
|
11320
|
+
epollAt(fds, req.epfd).ctl(fds, req.how, req.fd, req.events, req.data);
|
|
11321
|
+
return ok();
|
|
11322
|
+
case "epoll-wait": {
|
|
11323
|
+
const ep = epollAt(fds, req.epfd);
|
|
11324
|
+
if (req.timeoutMs === 0 || proc.owed()) {
|
|
11325
|
+
const now = ep.collect(fds, req.max);
|
|
11326
|
+
if (req.timeoutMs === 0 || now.length > 0) return ok(now);
|
|
11327
|
+
}
|
|
11328
|
+
return ok(await ep.wait(fds, req.max, req.timeoutMs, proc.blocking()));
|
|
11329
|
+
}
|
|
11330
|
+
}
|
|
11331
|
+
}
|
|
11332
|
+
|
|
11033
11333
|
// src/kernel/host-ops.ts
|
|
11034
11334
|
var HOST_OPS = [
|
|
11035
11335
|
"lock",
|
|
@@ -12684,14 +12984,14 @@ var Resolver = class {
|
|
|
12684
12984
|
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
12685
12985
|
const signal = blocking?.();
|
|
12686
12986
|
if (signal?.aborted) throw new KernelError("EINTR");
|
|
12687
|
-
let
|
|
12688
|
-
if (!
|
|
12987
|
+
let lookup4 = this.pending.get(id2);
|
|
12988
|
+
if (!lookup4) {
|
|
12689
12989
|
const abort = new AbortController();
|
|
12690
|
-
|
|
12691
|
-
this.pending.set(id2,
|
|
12692
|
-
void
|
|
12990
|
+
lookup4 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
|
|
12991
|
+
this.pending.set(id2, lookup4);
|
|
12992
|
+
void lookup4.work.then(() => this.pending.delete(id2));
|
|
12693
12993
|
}
|
|
12694
|
-
return waitFor(
|
|
12994
|
+
return waitFor(lookup4, signal);
|
|
12695
12995
|
}
|
|
12696
12996
|
async lookup(name2, family, id2, abandoned) {
|
|
12697
12997
|
const uplink = this.uplink;
|
|
@@ -12732,17 +13032,17 @@ var Resolver = class {
|
|
|
12732
13032
|
}
|
|
12733
13033
|
}
|
|
12734
13034
|
};
|
|
12735
|
-
function waitFor(
|
|
12736
|
-
|
|
13035
|
+
function waitFor(lookup4, signal) {
|
|
13036
|
+
lookup4.waiters++;
|
|
12737
13037
|
return new Promise((resolve2, reject) => {
|
|
12738
13038
|
const abort = () => {
|
|
12739
|
-
if (--
|
|
13039
|
+
if (--lookup4.waiters === 0) lookup4.abort.abort(new KernelError("EINTR"));
|
|
12740
13040
|
reject(new KernelError("EINTR"));
|
|
12741
13041
|
};
|
|
12742
13042
|
signal?.addEventListener("abort", abort, { once: true });
|
|
12743
|
-
void
|
|
13043
|
+
void lookup4.work.then((value) => {
|
|
12744
13044
|
if (signal?.aborted) return;
|
|
12745
|
-
|
|
13045
|
+
lookup4.waiters--;
|
|
12746
13046
|
signal?.removeEventListener("abort", abort);
|
|
12747
13047
|
resolve2(value);
|
|
12748
13048
|
});
|
|
@@ -13389,17 +13689,17 @@ function socketAt(fds, fd) {
|
|
|
13389
13689
|
if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
|
|
13390
13690
|
return file;
|
|
13391
13691
|
}
|
|
13392
|
-
var
|
|
13692
|
+
var ok2 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
13393
13693
|
async function socketSyscall(req, proc) {
|
|
13394
13694
|
const { fds, net } = proc;
|
|
13395
13695
|
switch (req.op) {
|
|
13396
13696
|
case "sock-open":
|
|
13397
|
-
return
|
|
13697
|
+
return ok2(fds.install(new OpenFile(net.socket(req.domain)), 3));
|
|
13398
13698
|
case "sock-pair": {
|
|
13399
13699
|
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
13400
13700
|
const first = fds.install(new OpenFile(a), 3);
|
|
13401
13701
|
try {
|
|
13402
|
-
return
|
|
13702
|
+
return ok2([first, fds.install(new OpenFile(b), 3)]);
|
|
13403
13703
|
} catch (e) {
|
|
13404
13704
|
await Promise.resolve(fds.close(first));
|
|
13405
13705
|
throw e;
|
|
@@ -13407,12 +13707,12 @@ async function socketSyscall(req, proc) {
|
|
|
13407
13707
|
}
|
|
13408
13708
|
case "sock-bind":
|
|
13409
13709
|
socketAt(fds, req.fd).bind(req.addr);
|
|
13410
|
-
return
|
|
13710
|
+
return ok2();
|
|
13411
13711
|
case "sock-listen":
|
|
13412
13712
|
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
13413
|
-
return
|
|
13713
|
+
return ok2();
|
|
13414
13714
|
case "sock-accept":
|
|
13415
|
-
return
|
|
13715
|
+
return ok2(await accept(proc, req.fd, req.nonblock));
|
|
13416
13716
|
case "sock-connect": {
|
|
13417
13717
|
const socket = socketAt(fds, req.fd);
|
|
13418
13718
|
const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
|
|
@@ -13422,26 +13722,26 @@ async function socketSyscall(req, proc) {
|
|
|
13422
13722
|
throw new KernelError("EINPROGRESS");
|
|
13423
13723
|
}
|
|
13424
13724
|
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
13425
|
-
return
|
|
13725
|
+
return ok2();
|
|
13426
13726
|
}
|
|
13427
13727
|
case "sock-shutdown":
|
|
13428
13728
|
socketAt(fds, req.fd).shutdown(req.how);
|
|
13429
|
-
return
|
|
13729
|
+
return ok2();
|
|
13430
13730
|
case "sock-name": {
|
|
13431
13731
|
const socket = socketAt(fds, req.fd);
|
|
13432
13732
|
const addr = req.peer ? socket.peer : socket.local;
|
|
13433
13733
|
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
13434
|
-
return
|
|
13734
|
+
return ok2(addr ?? unnamed(socket.domain));
|
|
13435
13735
|
}
|
|
13436
13736
|
case "sock-getopt":
|
|
13437
|
-
return
|
|
13737
|
+
return ok2(socketAt(fds, req.fd).getOption(req.level, req.name));
|
|
13438
13738
|
case "sock-setopt":
|
|
13439
13739
|
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
13440
|
-
return
|
|
13740
|
+
return ok2();
|
|
13441
13741
|
case "sock-resolve": {
|
|
13442
13742
|
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
13443
13743
|
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
13444
|
-
return
|
|
13744
|
+
return ok2(addresses);
|
|
13445
13745
|
}
|
|
13446
13746
|
}
|
|
13447
13747
|
}
|
|
@@ -14142,6 +14442,9 @@ function isHttpSyscall(req) {
|
|
|
14142
14442
|
function isSocketSyscall(req) {
|
|
14143
14443
|
return req.op.startsWith("sock-");
|
|
14144
14444
|
}
|
|
14445
|
+
function isEpollSyscall(req) {
|
|
14446
|
+
return EPOLL_OPS.includes(req.op);
|
|
14447
|
+
}
|
|
14145
14448
|
function isHostSyscall(req) {
|
|
14146
14449
|
return HOST_OPS.includes(req.op);
|
|
14147
14450
|
}
|
|
@@ -14232,6 +14535,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
14232
14535
|
"sig-mask",
|
|
14233
14536
|
"sig-pause",
|
|
14234
14537
|
...SOCKET_OPS,
|
|
14538
|
+
...EPOLL_OPS,
|
|
14235
14539
|
...HTTP_OPS,
|
|
14236
14540
|
...PTY_OPS,
|
|
14237
14541
|
...HOST_OPS
|
|
@@ -14346,9 +14650,9 @@ var WasmProcess = class {
|
|
|
14346
14650
|
this.options.onPending?.(sig);
|
|
14347
14651
|
if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
|
|
14348
14652
|
this.owed = true;
|
|
14349
|
-
const
|
|
14653
|
+
const blocked2 = this.interrupt;
|
|
14350
14654
|
this.interrupt = new AbortController();
|
|
14351
|
-
|
|
14655
|
+
blocked2.abort();
|
|
14352
14656
|
return "deliver";
|
|
14353
14657
|
}
|
|
14354
14658
|
async spawn(req) {
|
|
@@ -14407,9 +14711,9 @@ var WasmProcess = class {
|
|
|
14407
14711
|
this.stopped = sig;
|
|
14408
14712
|
this.stops++;
|
|
14409
14713
|
this.resumed = new Promise((resolve2) => this.wake = resolve2);
|
|
14410
|
-
const
|
|
14714
|
+
const blocked2 = this.interrupt;
|
|
14411
14715
|
this.interrupt = new AbortController();
|
|
14412
|
-
|
|
14716
|
+
blocked2.abort();
|
|
14413
14717
|
for (const listener of this.stateListeners) listener("stopped", sig);
|
|
14414
14718
|
return "stop";
|
|
14415
14719
|
}
|
|
@@ -14459,6 +14763,13 @@ var WasmProcess = class {
|
|
|
14459
14763
|
if (isTtySyscall(req)) return this.ttySyscall(req);
|
|
14460
14764
|
if (isJobSyscall(req)) return this.jobSyscall(req);
|
|
14461
14765
|
if (isSocketSyscall(req)) return await this.socketSyscall(req, cancelled);
|
|
14766
|
+
if (isEpollSyscall(req)) {
|
|
14767
|
+
return await epollSyscall(req, {
|
|
14768
|
+
fds: this.fds,
|
|
14769
|
+
blocking: () => this.blockingSignal(cancelled),
|
|
14770
|
+
owed: () => this.owed
|
|
14771
|
+
});
|
|
14772
|
+
}
|
|
14462
14773
|
if (isHttpSyscall(req)) return await this.httpSyscall(req);
|
|
14463
14774
|
if (isHostSyscall(req)) {
|
|
14464
14775
|
return await hostSyscall(req, {
|
|
@@ -14525,6 +14836,7 @@ var WasmProcess = class {
|
|
|
14525
14836
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
14526
14837
|
if (file.tty) this.checkForeground(file.tty);
|
|
14527
14838
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
14839
|
+
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
14528
14840
|
if (req.max <= 0) return new Uint8Array(0);
|
|
14529
14841
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
14530
14842
|
const ready2 = pollFile(file).readable;
|
|
@@ -15372,9 +15684,9 @@ var WasmProcess = class {
|
|
|
15372
15684
|
}
|
|
15373
15685
|
timerExpired(which) {
|
|
15374
15686
|
this.options.onTimer?.(which);
|
|
15375
|
-
const
|
|
15687
|
+
const blocked2 = this.interrupt;
|
|
15376
15688
|
this.interrupt = new AbortController();
|
|
15377
|
-
|
|
15689
|
+
blocked2.abort();
|
|
15378
15690
|
}
|
|
15379
15691
|
clearAlarm() {
|
|
15380
15692
|
clearTimeout(this.alarm);
|
|
@@ -15478,9 +15790,9 @@ function killThread(thread, caught, sig) {
|
|
|
15478
15790
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
15479
15791
|
if (held) return true;
|
|
15480
15792
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
15481
|
-
const
|
|
15793
|
+
const blocked2 = thread.interrupt;
|
|
15482
15794
|
thread.interrupt = new AbortController();
|
|
15483
|
-
|
|
15795
|
+
blocked2.abort();
|
|
15484
15796
|
return true;
|
|
15485
15797
|
}
|
|
15486
15798
|
function unblocked(header4) {
|
|
@@ -15659,8 +15971,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
15659
15971
|
function spawnWasmProcess(opts) {
|
|
15660
15972
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15661
15973
|
const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
15662
|
-
const
|
|
15663
|
-
if (
|
|
15974
|
+
const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
|
|
15975
|
+
if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
|
|
15664
15976
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
15665
15977
|
const created3 = new Created();
|
|
15666
15978
|
const process2 = new WasmProcess(
|
|
@@ -19618,6 +19930,8 @@ var Launcher = class {
|
|
|
19618
19930
|
const head = await this.head(glue);
|
|
19619
19931
|
if (!head) return void 0;
|
|
19620
19932
|
if (isWasm(head)) {
|
|
19933
|
+
const owner2 = await this.wasmOwner(glue, baseName(file).replace(/\.wasm$/, ""), scope);
|
|
19934
|
+
if (owner2) return { ...targetOf(owner2), ...asked };
|
|
19621
19935
|
return {
|
|
19622
19936
|
abi: "wasi",
|
|
19623
19937
|
glue,
|
|
@@ -19640,6 +19954,17 @@ var Launcher = class {
|
|
|
19640
19954
|
);
|
|
19641
19955
|
return owners.find((c) => c.name === name2) ?? owners[0];
|
|
19642
19956
|
}
|
|
19957
|
+
async wasmOwner(wasm, name2, scope) {
|
|
19958
|
+
const leaf = baseName(wasm);
|
|
19959
|
+
const real = await physicalPathAsync(this.base, wasm);
|
|
19960
|
+
const owners = [];
|
|
19961
|
+
for (const command of (await this.commands(scope)).values()) {
|
|
19962
|
+
if (command.abi !== "wasi" || command.script || baseName(command.wasm) !== leaf) continue;
|
|
19963
|
+
if (command.wasm === wasm || await physicalPathAsync(this.base, command.wasm) === real)
|
|
19964
|
+
owners.push(command);
|
|
19965
|
+
}
|
|
19966
|
+
return owners.find((c) => c.name === name2) ?? owners[0];
|
|
19967
|
+
}
|
|
19643
19968
|
async head(path) {
|
|
19644
19969
|
try {
|
|
19645
19970
|
return (await this.base.readFileBuffer(path)).subarray(0, SHEBANG_MAX);
|
|
@@ -19727,16 +20052,29 @@ var Launcher = class {
|
|
|
19727
20052
|
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
19728
20053
|
}
|
|
19729
20054
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
19730
|
-
const
|
|
19731
|
-
try {
|
|
19732
|
-
await this.mayExec(cred, { ...req, pid: ppid }, planned);
|
|
19733
|
-
} catch (err) {
|
|
20055
|
+
const refused2 = async (err) => {
|
|
19734
20056
|
await fds.closeAll();
|
|
19735
20057
|
throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
|
|
19736
|
-
}
|
|
20058
|
+
};
|
|
20059
|
+
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused2);
|
|
20060
|
+
const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
|
|
20061
|
+
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused2);
|
|
19737
20062
|
if (planned) return planned;
|
|
19738
20063
|
await fds.closeAll();
|
|
19739
|
-
throw new SpawnError(await this.unrunnable(
|
|
20064
|
+
throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
|
|
20065
|
+
}
|
|
20066
|
+
execGuard(cred, pid, tag) {
|
|
20067
|
+
const { dac } = this;
|
|
20068
|
+
return dac && { fs: this.fs, cred, pid, dac, tag, links: this.links.get(pid) };
|
|
20069
|
+
}
|
|
20070
|
+
async execFile(file, cwd, g) {
|
|
20071
|
+
if (!file.split("/").includes("..")) return file;
|
|
20072
|
+
const path = file.startsWith("/") ? file : `${cwd}/${file}`;
|
|
20073
|
+
const slash = path.lastIndexOf("/");
|
|
20074
|
+
const dir = path.slice(0, slash);
|
|
20075
|
+
const walked = g && await need(g, "exec", dir, X_OK, { directory: true });
|
|
20076
|
+
const real = walked && walked.denied === void 0 ? walked.path : await physicalPathAsync(this.base, dir);
|
|
20077
|
+
return joinName(real, path.slice(slash + 1));
|
|
19740
20078
|
}
|
|
19741
20079
|
async ticketFile(req, fds) {
|
|
19742
20080
|
if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
|
|
@@ -19835,7 +20173,8 @@ var Launcher = class {
|
|
|
19835
20173
|
}
|
|
19836
20174
|
return manifests;
|
|
19837
20175
|
}
|
|
19838
|
-
async backing(
|
|
20176
|
+
async backing(asked, cwd) {
|
|
20177
|
+
const file = await this.execFile(asked, cwd);
|
|
19839
20178
|
const planned = await this.plan(file, [file], cwd, "");
|
|
19840
20179
|
return planned && this.backingOf(planned, file, cwd, "");
|
|
19841
20180
|
}
|
|
@@ -20472,8 +20811,8 @@ var Launcher = class {
|
|
|
20472
20811
|
}
|
|
20473
20812
|
signalMasksOf(pid) {
|
|
20474
20813
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
20475
|
-
const [
|
|
20476
|
-
const sigBlk =
|
|
20814
|
+
const [blocked2] = this.blockedBy(pid);
|
|
20815
|
+
const sigBlk = blocked2 ? { sigBlk: blocked2 } : {};
|
|
20477
20816
|
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
20478
20817
|
}
|
|
20479
20818
|
controlsJobs(pid) {
|
|
@@ -20921,7 +21260,7 @@ var Launcher = class {
|
|
|
20921
21260
|
const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
|
|
20922
21261
|
const start2 = dir ?? "/";
|
|
20923
21262
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
20924
|
-
const
|
|
21263
|
+
const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
|
|
20925
21264
|
if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
|
|
20926
21265
|
const planned = await this.plan(file, argv, cwd, scope);
|
|
20927
21266
|
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
|
|
@@ -21024,11 +21363,11 @@ var Launcher = class {
|
|
|
21024
21363
|
// src/node/loopback.ts
|
|
21025
21364
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
21026
21365
|
import { subscribe } from "node:diagnostics_channel";
|
|
21027
|
-
import { lookup } from "node:dns/promises";
|
|
21366
|
+
import { lookup as lookup2 } from "node:dns/promises";
|
|
21028
21367
|
import { isIP } from "node:net";
|
|
21029
21368
|
var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
|
|
21030
21369
|
var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
|
|
21031
|
-
var resolveHost = async (host) => (await
|
|
21370
|
+
var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
|
|
21032
21371
|
function ipv4Place(address) {
|
|
21033
21372
|
const [a, b] = address.split(".").map(Number);
|
|
21034
21373
|
if (a === 127 || a === 0) return "loopback";
|
|
@@ -21423,7 +21762,7 @@ function isMemoryRoot(handle) {
|
|
|
21423
21762
|
}
|
|
21424
21763
|
|
|
21425
21764
|
// src/node/ws-diagnose.ts
|
|
21426
|
-
import { lookup as
|
|
21765
|
+
import { lookup as lookup3 } from "node:dns/promises";
|
|
21427
21766
|
import { isIP as isIP2, connect as tcp } from "node:net";
|
|
21428
21767
|
import { connect as tls } from "node:tls";
|
|
21429
21768
|
var PROBE_MS = 3e3;
|
|
@@ -21455,7 +21794,7 @@ async function diagnose(url, ms = PROBE_MS) {
|
|
|
21455
21794
|
const secure = at.protocol === "wss:";
|
|
21456
21795
|
const port = Number(at.port) || (secure ? 443 : 80);
|
|
21457
21796
|
try {
|
|
21458
|
-
await
|
|
21797
|
+
await lookup3(host);
|
|
21459
21798
|
} catch (e) {
|
|
21460
21799
|
return NO_NAME.has(codeOf6(e) ?? "") ? "EAI_NONAME" : void 0;
|
|
21461
21800
|
}
|