@ai-ecoverse/slicc-kernel 1.94.3 → 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 +417 -59
- 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 +416 -58
- 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) {
|
|
@@ -2427,6 +2438,8 @@ var UserDb = class {
|
|
|
2427
2438
|
owners;
|
|
2428
2439
|
umasks = /* @__PURE__ */ new Map();
|
|
2429
2440
|
writing = Promise.resolve();
|
|
2441
|
+
stable;
|
|
2442
|
+
commits = 0;
|
|
2430
2443
|
constructor(fs, owners = false) {
|
|
2431
2444
|
this.fs = fs;
|
|
2432
2445
|
this.owners = owners;
|
|
@@ -2462,11 +2475,18 @@ var UserDb = class {
|
|
|
2462
2475
|
throw err;
|
|
2463
2476
|
}
|
|
2464
2477
|
}
|
|
2478
|
+
async texts() {
|
|
2479
|
+
for (; ; ) {
|
|
2480
|
+
if (this.stable) return this.stable;
|
|
2481
|
+
const commits = this.commits;
|
|
2482
|
+
const passwd = await this.read(PASSWD, DEFAULT_PASSWD);
|
|
2483
|
+
const group = await this.read(GROUP, DEFAULT_GROUP);
|
|
2484
|
+
if (this.commits === commits && !this.stable) return [passwd, group];
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2465
2487
|
async tables() {
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
group: parseGroup(await this.read(GROUP, DEFAULT_GROUP))
|
|
2469
|
-
};
|
|
2488
|
+
const [passwd, group] = await this.texts();
|
|
2489
|
+
return { passwd: parsePasswd(passwd), group: parseGroup(group) };
|
|
2470
2490
|
}
|
|
2471
2491
|
async provision(row, umask, shared) {
|
|
2472
2492
|
const dirs = 511 & ~umask | (shared ? 1024 : 0);
|
|
@@ -2485,15 +2505,25 @@ var UserDb = class {
|
|
|
2485
2505
|
}
|
|
2486
2506
|
}
|
|
2487
2507
|
async commit(passwd, group, then) {
|
|
2488
|
-
const before = [
|
|
2508
|
+
const before = [
|
|
2509
|
+
await this.read(PASSWD, DEFAULT_PASSWD),
|
|
2510
|
+
await this.read(GROUP, DEFAULT_GROUP)
|
|
2511
|
+
];
|
|
2512
|
+
this.stable = before;
|
|
2513
|
+
this.commits++;
|
|
2489
2514
|
try {
|
|
2490
2515
|
await this.fs.writeFile(GROUP, group);
|
|
2491
2516
|
await this.fs.writeFile(PASSWD, passwd);
|
|
2517
|
+
this.stable = void 0;
|
|
2492
2518
|
await then?.();
|
|
2493
2519
|
} catch (err) {
|
|
2520
|
+
this.stable = before;
|
|
2494
2521
|
await this.fs.writeFile(GROUP, before[1]);
|
|
2495
2522
|
await this.fs.writeFile(PASSWD, before[0]);
|
|
2496
2523
|
throw err;
|
|
2524
|
+
} finally {
|
|
2525
|
+
this.stable = void 0;
|
|
2526
|
+
this.commits++;
|
|
2497
2527
|
}
|
|
2498
2528
|
}
|
|
2499
2529
|
serial(work) {
|
|
@@ -10624,7 +10654,7 @@ function mountTable(mounts = []) {
|
|
|
10624
10654
|
}
|
|
10625
10655
|
|
|
10626
10656
|
// src/version.ts
|
|
10627
|
-
var KERNEL_VERSION = true ? "1.
|
|
10657
|
+
var KERNEL_VERSION = true ? "1.95.0" : "0.0.0-dev";
|
|
10628
10658
|
var OS_RELEASE = "6.0.0-slicc";
|
|
10629
10659
|
function procVersion() {
|
|
10630
10660
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -11011,6 +11041,295 @@ async function procAlias(fs, path, follow2) {
|
|
|
11011
11041
|
return step.value;
|
|
11012
11042
|
}
|
|
11013
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
|
+
|
|
11014
11333
|
// src/kernel/host-ops.ts
|
|
11015
11334
|
var HOST_OPS = [
|
|
11016
11335
|
"lock",
|
|
@@ -12665,14 +12984,14 @@ var Resolver = class {
|
|
|
12665
12984
|
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
12666
12985
|
const signal = blocking?.();
|
|
12667
12986
|
if (signal?.aborted) throw new KernelError("EINTR");
|
|
12668
|
-
let
|
|
12669
|
-
if (!
|
|
12987
|
+
let lookup4 = this.pending.get(id2);
|
|
12988
|
+
if (!lookup4) {
|
|
12670
12989
|
const abort = new AbortController();
|
|
12671
|
-
|
|
12672
|
-
this.pending.set(id2,
|
|
12673
|
-
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));
|
|
12674
12993
|
}
|
|
12675
|
-
return waitFor(
|
|
12994
|
+
return waitFor(lookup4, signal);
|
|
12676
12995
|
}
|
|
12677
12996
|
async lookup(name2, family, id2, abandoned) {
|
|
12678
12997
|
const uplink = this.uplink;
|
|
@@ -12713,17 +13032,17 @@ var Resolver = class {
|
|
|
12713
13032
|
}
|
|
12714
13033
|
}
|
|
12715
13034
|
};
|
|
12716
|
-
function waitFor(
|
|
12717
|
-
|
|
13035
|
+
function waitFor(lookup4, signal) {
|
|
13036
|
+
lookup4.waiters++;
|
|
12718
13037
|
return new Promise((resolve2, reject) => {
|
|
12719
13038
|
const abort = () => {
|
|
12720
|
-
if (--
|
|
13039
|
+
if (--lookup4.waiters === 0) lookup4.abort.abort(new KernelError("EINTR"));
|
|
12721
13040
|
reject(new KernelError("EINTR"));
|
|
12722
13041
|
};
|
|
12723
13042
|
signal?.addEventListener("abort", abort, { once: true });
|
|
12724
|
-
void
|
|
13043
|
+
void lookup4.work.then((value) => {
|
|
12725
13044
|
if (signal?.aborted) return;
|
|
12726
|
-
|
|
13045
|
+
lookup4.waiters--;
|
|
12727
13046
|
signal?.removeEventListener("abort", abort);
|
|
12728
13047
|
resolve2(value);
|
|
12729
13048
|
});
|
|
@@ -13370,17 +13689,17 @@ function socketAt(fds, fd) {
|
|
|
13370
13689
|
if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
|
|
13371
13690
|
return file;
|
|
13372
13691
|
}
|
|
13373
|
-
var
|
|
13692
|
+
var ok2 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
13374
13693
|
async function socketSyscall(req, proc) {
|
|
13375
13694
|
const { fds, net } = proc;
|
|
13376
13695
|
switch (req.op) {
|
|
13377
13696
|
case "sock-open":
|
|
13378
|
-
return
|
|
13697
|
+
return ok2(fds.install(new OpenFile(net.socket(req.domain)), 3));
|
|
13379
13698
|
case "sock-pair": {
|
|
13380
13699
|
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
13381
13700
|
const first = fds.install(new OpenFile(a), 3);
|
|
13382
13701
|
try {
|
|
13383
|
-
return
|
|
13702
|
+
return ok2([first, fds.install(new OpenFile(b), 3)]);
|
|
13384
13703
|
} catch (e) {
|
|
13385
13704
|
await Promise.resolve(fds.close(first));
|
|
13386
13705
|
throw e;
|
|
@@ -13388,12 +13707,12 @@ async function socketSyscall(req, proc) {
|
|
|
13388
13707
|
}
|
|
13389
13708
|
case "sock-bind":
|
|
13390
13709
|
socketAt(fds, req.fd).bind(req.addr);
|
|
13391
|
-
return
|
|
13710
|
+
return ok2();
|
|
13392
13711
|
case "sock-listen":
|
|
13393
13712
|
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
13394
|
-
return
|
|
13713
|
+
return ok2();
|
|
13395
13714
|
case "sock-accept":
|
|
13396
|
-
return
|
|
13715
|
+
return ok2(await accept(proc, req.fd, req.nonblock));
|
|
13397
13716
|
case "sock-connect": {
|
|
13398
13717
|
const socket = socketAt(fds, req.fd);
|
|
13399
13718
|
const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
|
|
@@ -13403,26 +13722,26 @@ async function socketSyscall(req, proc) {
|
|
|
13403
13722
|
throw new KernelError("EINPROGRESS");
|
|
13404
13723
|
}
|
|
13405
13724
|
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
13406
|
-
return
|
|
13725
|
+
return ok2();
|
|
13407
13726
|
}
|
|
13408
13727
|
case "sock-shutdown":
|
|
13409
13728
|
socketAt(fds, req.fd).shutdown(req.how);
|
|
13410
|
-
return
|
|
13729
|
+
return ok2();
|
|
13411
13730
|
case "sock-name": {
|
|
13412
13731
|
const socket = socketAt(fds, req.fd);
|
|
13413
13732
|
const addr = req.peer ? socket.peer : socket.local;
|
|
13414
13733
|
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
13415
|
-
return
|
|
13734
|
+
return ok2(addr ?? unnamed(socket.domain));
|
|
13416
13735
|
}
|
|
13417
13736
|
case "sock-getopt":
|
|
13418
|
-
return
|
|
13737
|
+
return ok2(socketAt(fds, req.fd).getOption(req.level, req.name));
|
|
13419
13738
|
case "sock-setopt":
|
|
13420
13739
|
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
13421
|
-
return
|
|
13740
|
+
return ok2();
|
|
13422
13741
|
case "sock-resolve": {
|
|
13423
13742
|
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
13424
13743
|
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
13425
|
-
return
|
|
13744
|
+
return ok2(addresses);
|
|
13426
13745
|
}
|
|
13427
13746
|
}
|
|
13428
13747
|
}
|
|
@@ -14123,6 +14442,9 @@ function isHttpSyscall(req) {
|
|
|
14123
14442
|
function isSocketSyscall(req) {
|
|
14124
14443
|
return req.op.startsWith("sock-");
|
|
14125
14444
|
}
|
|
14445
|
+
function isEpollSyscall(req) {
|
|
14446
|
+
return EPOLL_OPS.includes(req.op);
|
|
14447
|
+
}
|
|
14126
14448
|
function isHostSyscall(req) {
|
|
14127
14449
|
return HOST_OPS.includes(req.op);
|
|
14128
14450
|
}
|
|
@@ -14213,6 +14535,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
14213
14535
|
"sig-mask",
|
|
14214
14536
|
"sig-pause",
|
|
14215
14537
|
...SOCKET_OPS,
|
|
14538
|
+
...EPOLL_OPS,
|
|
14216
14539
|
...HTTP_OPS,
|
|
14217
14540
|
...PTY_OPS,
|
|
14218
14541
|
...HOST_OPS
|
|
@@ -14327,9 +14650,9 @@ var WasmProcess = class {
|
|
|
14327
14650
|
this.options.onPending?.(sig);
|
|
14328
14651
|
if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
|
|
14329
14652
|
this.owed = true;
|
|
14330
|
-
const
|
|
14653
|
+
const blocked2 = this.interrupt;
|
|
14331
14654
|
this.interrupt = new AbortController();
|
|
14332
|
-
|
|
14655
|
+
blocked2.abort();
|
|
14333
14656
|
return "deliver";
|
|
14334
14657
|
}
|
|
14335
14658
|
async spawn(req) {
|
|
@@ -14388,9 +14711,9 @@ var WasmProcess = class {
|
|
|
14388
14711
|
this.stopped = sig;
|
|
14389
14712
|
this.stops++;
|
|
14390
14713
|
this.resumed = new Promise((resolve2) => this.wake = resolve2);
|
|
14391
|
-
const
|
|
14714
|
+
const blocked2 = this.interrupt;
|
|
14392
14715
|
this.interrupt = new AbortController();
|
|
14393
|
-
|
|
14716
|
+
blocked2.abort();
|
|
14394
14717
|
for (const listener of this.stateListeners) listener("stopped", sig);
|
|
14395
14718
|
return "stop";
|
|
14396
14719
|
}
|
|
@@ -14440,6 +14763,13 @@ var WasmProcess = class {
|
|
|
14440
14763
|
if (isTtySyscall(req)) return this.ttySyscall(req);
|
|
14441
14764
|
if (isJobSyscall(req)) return this.jobSyscall(req);
|
|
14442
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
|
+
}
|
|
14443
14773
|
if (isHttpSyscall(req)) return await this.httpSyscall(req);
|
|
14444
14774
|
if (isHostSyscall(req)) {
|
|
14445
14775
|
return await hostSyscall(req, {
|
|
@@ -14506,6 +14836,7 @@ var WasmProcess = class {
|
|
|
14506
14836
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
14507
14837
|
if (file.tty) this.checkForeground(file.tty);
|
|
14508
14838
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
14839
|
+
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
14509
14840
|
if (req.max <= 0) return new Uint8Array(0);
|
|
14510
14841
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
14511
14842
|
const ready2 = pollFile(file).readable;
|
|
@@ -15353,9 +15684,9 @@ var WasmProcess = class {
|
|
|
15353
15684
|
}
|
|
15354
15685
|
timerExpired(which) {
|
|
15355
15686
|
this.options.onTimer?.(which);
|
|
15356
|
-
const
|
|
15687
|
+
const blocked2 = this.interrupt;
|
|
15357
15688
|
this.interrupt = new AbortController();
|
|
15358
|
-
|
|
15689
|
+
blocked2.abort();
|
|
15359
15690
|
}
|
|
15360
15691
|
clearAlarm() {
|
|
15361
15692
|
clearTimeout(this.alarm);
|
|
@@ -15459,9 +15790,9 @@ function killThread(thread, caught, sig) {
|
|
|
15459
15790
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
15460
15791
|
if (held) return true;
|
|
15461
15792
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
15462
|
-
const
|
|
15793
|
+
const blocked2 = thread.interrupt;
|
|
15463
15794
|
thread.interrupt = new AbortController();
|
|
15464
|
-
|
|
15795
|
+
blocked2.abort();
|
|
15465
15796
|
return true;
|
|
15466
15797
|
}
|
|
15467
15798
|
function unblocked(header4) {
|
|
@@ -15640,8 +15971,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
15640
15971
|
function spawnWasmProcess(opts) {
|
|
15641
15972
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15642
15973
|
const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
15643
|
-
const
|
|
15644
|
-
if (
|
|
15974
|
+
const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
|
|
15975
|
+
if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
|
|
15645
15976
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
15646
15977
|
const created3 = new Created();
|
|
15647
15978
|
const process2 = new WasmProcess(
|
|
@@ -19599,6 +19930,8 @@ var Launcher = class {
|
|
|
19599
19930
|
const head = await this.head(glue);
|
|
19600
19931
|
if (!head) return void 0;
|
|
19601
19932
|
if (isWasm(head)) {
|
|
19933
|
+
const owner2 = await this.wasmOwner(glue, baseName(file).replace(/\.wasm$/, ""), scope);
|
|
19934
|
+
if (owner2) return { ...targetOf(owner2), ...asked };
|
|
19602
19935
|
return {
|
|
19603
19936
|
abi: "wasi",
|
|
19604
19937
|
glue,
|
|
@@ -19621,6 +19954,17 @@ var Launcher = class {
|
|
|
19621
19954
|
);
|
|
19622
19955
|
return owners.find((c) => c.name === name2) ?? owners[0];
|
|
19623
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
|
+
}
|
|
19624
19968
|
async head(path) {
|
|
19625
19969
|
try {
|
|
19626
19970
|
return (await this.base.readFileBuffer(path)).subarray(0, SHEBANG_MAX);
|
|
@@ -19708,16 +20052,29 @@ var Launcher = class {
|
|
|
19708
20052
|
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
19709
20053
|
}
|
|
19710
20054
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
19711
|
-
const
|
|
19712
|
-
try {
|
|
19713
|
-
await this.mayExec(cred, { ...req, pid: ppid }, planned);
|
|
19714
|
-
} catch (err) {
|
|
20055
|
+
const refused2 = async (err) => {
|
|
19715
20056
|
await fds.closeAll();
|
|
19716
20057
|
throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
|
|
19717
|
-
}
|
|
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);
|
|
19718
20062
|
if (planned) return planned;
|
|
19719
20063
|
await fds.closeAll();
|
|
19720
|
-
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));
|
|
19721
20078
|
}
|
|
19722
20079
|
async ticketFile(req, fds) {
|
|
19723
20080
|
if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
|
|
@@ -19816,7 +20173,8 @@ var Launcher = class {
|
|
|
19816
20173
|
}
|
|
19817
20174
|
return manifests;
|
|
19818
20175
|
}
|
|
19819
|
-
async backing(
|
|
20176
|
+
async backing(asked, cwd) {
|
|
20177
|
+
const file = await this.execFile(asked, cwd);
|
|
19820
20178
|
const planned = await this.plan(file, [file], cwd, "");
|
|
19821
20179
|
return planned && this.backingOf(planned, file, cwd, "");
|
|
19822
20180
|
}
|
|
@@ -20453,8 +20811,8 @@ var Launcher = class {
|
|
|
20453
20811
|
}
|
|
20454
20812
|
signalMasksOf(pid) {
|
|
20455
20813
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
20456
|
-
const [
|
|
20457
|
-
const sigBlk =
|
|
20814
|
+
const [blocked2] = this.blockedBy(pid);
|
|
20815
|
+
const sigBlk = blocked2 ? { sigBlk: blocked2 } : {};
|
|
20458
20816
|
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
20459
20817
|
}
|
|
20460
20818
|
controlsJobs(pid) {
|
|
@@ -20902,7 +21260,7 @@ var Launcher = class {
|
|
|
20902
21260
|
const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
|
|
20903
21261
|
const start2 = dir ?? "/";
|
|
20904
21262
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
20905
|
-
const
|
|
21263
|
+
const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
|
|
20906
21264
|
if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
|
|
20907
21265
|
const planned = await this.plan(file, argv, cwd, scope);
|
|
20908
21266
|
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
|
|
@@ -21005,11 +21363,11 @@ var Launcher = class {
|
|
|
21005
21363
|
// src/node/loopback.ts
|
|
21006
21364
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
21007
21365
|
import { subscribe } from "node:diagnostics_channel";
|
|
21008
|
-
import { lookup } from "node:dns/promises";
|
|
21366
|
+
import { lookup as lookup2 } from "node:dns/promises";
|
|
21009
21367
|
import { isIP } from "node:net";
|
|
21010
21368
|
var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
|
|
21011
21369
|
var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
|
|
21012
|
-
var resolveHost = async (host) => (await
|
|
21370
|
+
var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
|
|
21013
21371
|
function ipv4Place(address) {
|
|
21014
21372
|
const [a, b] = address.split(".").map(Number);
|
|
21015
21373
|
if (a === 127 || a === 0) return "loopback";
|
|
@@ -21404,7 +21762,7 @@ function isMemoryRoot(handle) {
|
|
|
21404
21762
|
}
|
|
21405
21763
|
|
|
21406
21764
|
// src/node/ws-diagnose.ts
|
|
21407
|
-
import { lookup as
|
|
21765
|
+
import { lookup as lookup3 } from "node:dns/promises";
|
|
21408
21766
|
import { isIP as isIP2, connect as tcp } from "node:net";
|
|
21409
21767
|
import { connect as tls } from "node:tls";
|
|
21410
21768
|
var PROBE_MS = 3e3;
|
|
@@ -21436,7 +21794,7 @@ async function diagnose(url, ms = PROBE_MS) {
|
|
|
21436
21794
|
const secure = at.protocol === "wss:";
|
|
21437
21795
|
const port = Number(at.port) || (secure ? 443 : 80);
|
|
21438
21796
|
try {
|
|
21439
|
-
await
|
|
21797
|
+
await lookup3(host);
|
|
21440
21798
|
} catch (e) {
|
|
21441
21799
|
return NO_NAME.has(codeOf6(e) ?? "") ? "EAI_NONAME" : void 0;
|
|
21442
21800
|
}
|
|
@@ -22512,7 +22870,7 @@ async function createNodeKernel(options = {}) {
|
|
|
22512
22870
|
async connect({ user, tag } = {}) {
|
|
22513
22871
|
if (terminated) throw new Error(TERMINATED);
|
|
22514
22872
|
tagOption(tag);
|
|
22515
|
-
if (user !== void 0 && !await launcher.users.lookup(user)) {
|
|
22873
|
+
if (user !== void 0 && !await guard2(() => launcher.users.lookup(user))) {
|
|
22516
22874
|
throw fsError("ENOENT", `no user ${String(user)}`);
|
|
22517
22875
|
}
|
|
22518
22876
|
const { port1, port2 } = new MessageChannel2();
|