/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * arch/wasm32 syscall numbering — Linux x86_64 convention. * * The wasm32 port's syscall ABI is the x86_64 number space: the * dispatch table (arch/wasm32/kernel/syscall_table.c), HardwareJS's * router (hardwarejs/src/syscall-nr.ts + the worker routing tables), * musl's wasm32 arch (arch/wasm32/bits/syscall.h.in) and glibc's * wasm32 port (sysdeps/unix/sysv/linux/wasm32/arch-syscall.h) all * agree on it, per arch/x86/entry/syscalls/syscall_64.tbl. * * Until 2026-07-18 this header was the v0.1 placeholder that included * asm-generic/unistd.h (generic numbering: kill=129, getppid=173, ...) * — every OTHER layer had moved to x86_64 numbers, so any userland * compiled against the INSTALLED kernel headers (glibc's * SYS_* aliases pass through these __NR_* values) issued raw syscall(2) * calls the kernel dispatched as the WRONG x86_64 syscall — or, for * numbers the routing tables don't carry, got -ENOSYS. Witnessed by the * sjlj-sig gate arm: the fork child's syscall(SYS_kill, getppid(), ...) * issued 129/173, both -ENOSYS, child _exit(94). This is the K7-owed * "replace with the x86_64 set". * * NOT GENERATED — HAND-MAINTAINED, AND THE ONLY THING KEEPING IT HONEST * IS SOMEBODY CHECKING. This block used to say the numbers below "are * generated from musl's arch/wasm32/bits/syscall.h.in". No generator * exists anywhere in the tree; the two headers were transcribed and are * maintained by hand, in two different submodules, which is precisely * the shape that drifts unnoticed. They are IN AGREEMENT as of the * writing of this note (compared name-by-name against musl: 357 shared * names, zero value disagreements; the only musl-only entries are its * internal *_time64 equal-value aliases, which are deliberately omitted * here). If you change one, compare the other. * cite-path: brintium/musl/arch/wasm32/bits/syscall.h.in * * wasm32-EXTENSION numbers (>= 1024, outside the x86_64 table; the * HardwareJS worker intercepts them before kernel dispatch — see * hardwarejs/src/worker.mjs): * 1024 __NR_wasm_spawn_image (spawn/exec of a wasm image) * 1025 __NR_wasm_spawn_image_actions (spawn with fd actions — LIVE. * This line said "retired" while a live host handler answered * the number; the retirement was real but was REVERSED, and the * reversal landed in the other submodule so this header never * heard about it. A number advertised as retired next to a line * that says 1026 is "reserved" is an invitation to reassign it * on top of a live handler — that is the damage this class does.) * cite: __NR_wasm_spawn_image_actions @ hardwarejs/src/kernelSpawnHandler.ts * 1026 (reserved) * 1027 __NR_wasm_exit_by_signal (WIFSIGNALED exit, K11-C2) * 1028 __NR_wasm_sigconsume (W4 kernel-pending dequeue) * 1029/1030 (worker-private setjmp/longjmp, never kernel-routed) * 1031..1039 (free) * 1040 SYS_wasm_dlopen (asm/hwjs_dlopen.h; host-intercepted) * 1041 SYS_wasm_dlsym (asm/hwjs_dlopen.h; host-intercepted) * 1042 SYS_wasm_dlclose (asm/hwjs_dlopen.h; host-intercepted) * 1043 SYS_wasm_dlerror (asm/hwjs_dlopen.h; host-intercepted) * 1044 __NR_wasm_exec_load_begin (chunked in-place exec load, phase 1) * 1045 __NR_wasm_exec_load_step (chunked in-place exec load, phase 2..N) * 1046 __NR_wasm_libc_stage (libc.so digest hand-off, LIBC_STAGE) * 1047 __NR_wasm_dlopen_load (dlopen .so staging read) * 1048 __NR_wasm_needed_stage (needed-list staging read, by index) * 1049 SYS_wasm_root_map (asm/hwjs_dlopen.h; host-intercepted) * * 1044..1047 are the wasm32-ext numbers the kernel itself DISPATCHES: * entry.c's wasm32_user_syscall_dispatch answers them ahead of the * sys_call_table bound check, so they run INSIDE the coroutinized * user-syscall chain. That is what buys them the wasm_syscall park * machinery — a would-block deep inside a kernel_read (in fuse_get_req -> * wasm32_fuse_userproc_wait, NOT at a chunk boundary) * PRESERVES the in-flight coroutine handle on thread.parked_syscall_handle[] * and answers -ERESTARTRESCHED (-517, asm/resched.h — outside errno space); * re-issuing the SAME nr resumes that exact chain, and process teardown * drains it via wasm32_exit_drain_parked_syscall. The bare exports of the * same functions (scripts/link-vmlinux.sh --export=wasm32_user_exec_load_ * begin/_step, --export=wasm32_user_libc_stage, * --export=wasm32_user_dlopen_load) remain for hosts that call them * directly; those get no park preservation, which is exactly why the * syscall route exists. * * 1046/1047 JOINED THAT LIST LATE, AND THE REASON IS WORTH KEEPING. Both * read a WHOLE FILE through the FUSE root — /lib/libc.so. and the * dlopen'd .so — and both were reached only as bare exports, on the plain * host bracket, which is the one shape this very paragraph says gets no * park preservation. Three separate places in the tree recorded that (this * header, worker.mjs's exec-load route note, and asm/hwjs_dlopen.h) and * none of them was connected to these two call sites. A whole-file read * off a network-backed root is exactly the operation whose would-block is * not at a chunk boundary, so it is exactly the operation that needs the * preserved handle rather than a host-side spin. */ #ifndef _ASM_WASM32_UNISTD_H #define _ASM_WASM32_UNISTD_H /* * ===================================================================== * DIVERGENCES — where this port does not behave as Linux does * ===================================================================== * * The numbers below are Linux's numbers and, with the exceptions listed * in THIS section, they mean what they mean on Linux. Read this list * before you trust a number further down the file. * * Every entry here has the same cause: Linux's behaviour is downstream * of an architectural property this substrate does not offer on the same * terms. Where that happens we document the difference rather than * emulate a property we lack, because a half-emulation lets a guest * observe a state no Linux guest can observe, and it does so silently. * * State the property precisely. "This substrate cannot do X" and "this * port does not implement X" are different sentences, and writing the * first when the second is true has repeatedly hidden real defects in * this tree. If an entry below asserts an impossibility, it says which * instruction-set or substrate fact makes it one. * * --------------------------------------------------------------------- * SHAPE OF AN ENTRY (a convention, not a rule the build enforces) * --------------------------------------------------------------------- * * Nothing checks this. There is no script, no test, and no build step * that will fail if a future divergence is added elsewhere, or added * here in the wrong shape, or not added at all. This paragraph is the * only thing asking you to keep them together — please treat scattering * them as the defect it is, and add to this list instead. * * A well-formed entry states four things, in this order: * * TAG D-, e.g. D-AFFINITY. Descriptive and * permanent; the implementation cites it in a * comment so a reader arriving from the code lands * here. * LINUX PROPERTY What Linux guarantees, and the architectural fact * that guarantee rests on. * WHY IT DOES NOT The specific thing this substrate lacks. Name the * TRANSFER file or mechanism, so the claim can be re-checked * when the substrate changes. * WHAT WE DO The observable behaviour, including the errno, and * INSTEAD the alternative that was rejected and why. * * If a decision is still open, mark it OPEN in place rather than * writing a confident sentence you have not established. * * --------------------------------------------------------------------- * REACHABILITY (read this before testing anything below) * --------------------------------------------------------------------- * * A syscall number being wired in arch/wasm32/kernel/syscall_table.c is * now SUFFICIENT for a guest to reach it, and that is a change — read * this whole section before testing anything below, because most of the * warnings that used to live here were about the arrangement it * replaces. * * WHAT IT WAS. The host forwarded syscalls to the kernel from a per-nr * ALLOWLIST in hardwarejs/src/worker.mjs. A number absent from that * list fell through to a host-side responder * (hardwarejs/src/kernelSpawnHandler.ts) that answered WITHOUT * consulting vmlinux. Usually that answer was -ENOSYS — but not always, * and the exception was load-bearing: nr 14 (rt_sigprocmask) was * answered 0 with nothing recorded, so current->blocked stayed empty * for the life of every process and the kernel interrupted guests for * signals they had blocked. TWICE an entry in this list described a * kernel handler no guest could reach, and both times it read as a * decision about behaviour when it was a decision about nothing. * * WHAT IT IS. The default is inverted. The host asks the kernel's own * table which numbers it implements — wasm32_syscall_implemented(), * exported from arch/wasm32/kernel/syscall_table.c, swept once per * Worker — and routes those to the kernel. A number the host answers * anyway must be listed in worker.mjs HOST_ANSWERED with a reason. * Wiring a row in sys_call_table is now the whole of making it * reachable; forgetting a host-side edit is no longer a thing that can * happen. * * MEASURE THE ROUTE ANYWAY. The rule removed the failure mode where * silence meant the host won; it did not remove HOST_ANSWERED, and an * entry that describes kernel behaviour for a number listed there is * describing something no guest sees. The divtest gate still prints a * per-number route witness on every run, for exactly that reason. * * MEASURED 2026-08-03: * * nr name route entry * 14 rt_sigprocmask K (the mask has one owner) * 15 rt_sigreturn K D-SIGRETURN * 127 rt_sigpending K — * 128 rt_sigtimedwait K — * 130 rt_sigsuspend K — * 131 sigaltstack K D-ALTSTACK * 203 sched_setaffinity K D-AFFINITY * 204 sched_getaffinity K D-AFFINITY * 309 getcpu K D-AFFINITY * * --------------------------------------------------------------------- * D-PREEMPT — how long your thread can run before it yields the CPU * (no syscall number: this is a property of every guest * instruction, not of a call) * --------------------------------------------------------------------- * * NOTE ON SHAPE: this entry states a CONTRACT as well as a divergence. * The other entries here tell you what a call returns; this one tells * you a number you may design against. It is written that way because * the question it answers — "can my thread be preempted, and within * what?" — is one a guest author has to answer before writing a * compute loop, and until now the honest answer was that nobody had * written it down. * * LINUX PROPERTY * Linux preempts a running thread whether or not the thread * cooperates. A timer interrupt arrives on a schedule the thread * cannot influence, the CPU enters the kernel mid-instruction-stream, * and scheduler_tick() may set TIF_NEED_RESCHED; the thread is off * the CPU at the next return to user mode. This rests on an * architectural fact: the hardware can take control away. A thread * that executes `for (;;) ;` still lets every other thread run, and * the bound on how long it holds the CPU is a TIME — one tick, and * with CONFIG_PREEMPT the reschedule can happen inside the kernel too. * * WHY IT DOES NOT TRANSFER * WebAssembly has no interrupts. There is no instruction, no host * call, and no engine facility that takes control away from running * wasm code at a point the code did not choose. A wasm function that * loops without calling out cannot be stopped by anything except * tearing down the whole instance. This is a property of the * instruction set, not of this port or of any engine: the answer does * not change with a newer browser. * * So there is no timer tick to hang a bound on, and a bound stated in * milliseconds would be a bound the substrate cannot enforce. * * WHAT WE DO INSTEAD * The compiler puts the preemption points in. Every loop back-edge in * a preemptible image carries a checkpoint that decrements a slice * budget and, when the budget runs out, suspends the coroutine so the * runtime can hand the CPU to someone else and refill it * (brintium/pass/coroutinize/CoroutinizePass.cpp, the M6 * budgeted safepoints; the runtime side is the pumps in * hardwarejs/src/worker.mjs and the dispatcher in * arch/wasm32/kernel/hwjs_coro.c). A loop the compiler can PROVE * terminates within the exemption threshold carries no checkpoint, * because it yields by ending. * * Because the mechanism counts iterations rather than time, the * contract is stated in iterations. That is not a hedge — it is the * quantity the port can actually guarantee, and converting it to * milliseconds is arithmetic you can do better than we can, because * you know what your loop body costs. * * ---- THE BOUND ---- * * YOUR THREAD YIELDS THE CPU AFTER AT MOST 65536 ITERATIONS OF ANY * LOOP. * * More precisely, of the two cases: * * - a loop the compiler could not prove terminates (the common * case: `while (cond)`, `for (i = 0; i < n; i++)` with n a * runtime value, anything with a call in the condition) yields * every 16384 iterations. That is the runtime's slice budget, * and it is refilled on every resume. * * - a loop the compiler PROVED terminates in at most 65536 * iterations carries no checkpoint and yields by finishing. 65536 * is therefore the worst case of the two, and the number to * design against. * * On the reference host, with a loop body doing a strided * read-modify-write over 256 KiB plus an integer mix — measured 1.19 * ns per iteration, checkpoint included — those are 0.019 ms and * 0.078 ms of uninterrupted execution. For a loop body of cost C, the * bound is 65536 x C. A body that itself takes a millisecond makes * the worst case a minute; that is arithmetic, not a surprise, and it * is the reason the contract is quoted in iterations first. * * ---- WHAT IT DEPENDS ON ---- * * Four conditions. All four are enforced by something that fails, not * by convention, and each names what does the enforcing: * * 1. YOUR IMAGE IS PREEMPTIBLE. Every image this port ships is built * preemptible by default and attests it: the pass censuses every * function in the merged module and stamps a verdict, and wasmld * REFUSES to link an image that does not attest what the link * asked for. You do not opt in, and you cannot silently lose it. * (The one exception is stated in full under NOT COVERED below.) * * 2. YOUR LOOP IS A LOOP THE COMPILER CAN SEE. A back-edge in the * compiled function is what carries the checkpoint. Straight-line * code, however long, has no back-edge — and a "loop" made of * mutual recursion is bounded by the stack, not by this. If you * hand-roll a jump table interpreter, its dispatch back-edge is a * back-edge and is covered. * * 3. THE BOUND IS NOT CONDITIONAL ON WHICH DRIVE RUNS YOUR IMAGE. * This port has two runtime drives (flat and nested). Until * recently only one of them acted on a checkpoint: the other * counted the yield and re-entered without refilling the budget or * surrendering the thread, so the bound above held for images that * happened to link flat and was false for the rest, and every * instrument reported both as preemptible. Both drives now call * the same code (hardwarejs/src/worker.mjs * serviceCooperativeBreath), and the image itself refuses to * continue if whoever resumed it did not refill the budget * (__hwjs_budget_not_refilled, naming the function whose * checkpoint could not yield). A third drive cannot reintroduce * the split quietly. * * 4. NOTHING ELSE IS PINNING THE THREAD. The bound is on YOUR loop * releasing the CPU. It is not a scheduling guarantee about when * you get it back: if a co-resident task holds it, or a host * service is in flight, you wait behind them exactly as you would * on Linux. * * ---- NOT COVERED — the kernel ---- * * Everything above is about GUEST images. vmlinux itself ships with * ZERO checkpoints: every kernel translation unit compiles with them * disabled (distros/common/linux-6.12/scripts/cc-wasm.sh), so a * CPU-bound stretch of KERNEL code is not preemptible on any bound at * all. This is stated rather than papered over because a guest cannot * tell from the outside. * * The reason is not "nobody got to it". TWO conditions stand between * this kernel and armed checkpoints. Both are stated here because a * reader who saw only the first would conclude, wrongly, that closing * it is sufficient. * * (1) THE PLACER CARVES. In the kernel's build mode the placer * CARVES back-edges whose latch is dominated by a may-suspend * call — the shape of every kernel wait loop — leaving them with * neither a checkpoint nor a proof that they yield. cc-wasm.sh * REFUSES to compile an armed kernel TU whose compile reports a * carved edge, so this is a condition with a mechanism and not a * preference, and distros/common/test-kernel-arming-gate.sh * FIRES that refusal on a real kernel TU on every run rather than * taking its existence on trust. * * WHAT THAT CARVE COUNT ACTUALLY IS, corrected 2026-08-05. This * entry, cc-wasm.sh and the artifact's own provenance section all * used to report the shipped kernel's carve figure as ZERO, and * that zero was quoted as the measurement the arming decision was * waiting on. It measured nothing: no shipped kernel TU is armed, * so the placer never runs, no back-edge is ever classified, and * the 0 came from a shell default over an empty match. Armed, on * this pin, real kernel TUs carve in quantity — mm/page_alloc.o * 28 of 99 back-edges, kernel/sched/core.o 15 of 42, * kernel/exit.o 8 of 14. The condition is not met and has never * been met. The artifact now reports `n/a` where it cannot * measure, and the gate above refuses a build that regresses to * reporting `0`. * * The DEFECT under the carve — a reschedule hook that requeued a * task which was trying to block, and reached it through the * VOLUNTARY schedule() so that a budget expiry landing between a * task's prepare_to_wait() and its own schedule() blocked it at a * point its author never chose — is FIXED (2026-08-05, * arch/wasm32/kernel/hwjs_coro.c __hwjs_safepoint_reschedule). A * budget expiry now declines for a task in a sleeping state and * otherwise preempts through __schedule(SM_PREEMPT), which is * where Linux puts the same rule. * * (2) THERE IS NO ATOMIC-SECTION GUARD, and this one is new as of * 2026-08-05. Armed, the placer puts checkpoints on the * back-edges of the rq-lock acquisition itself * (raw_spin_rq_lock_nested, raw_spin_rq_trylock, __task_rq_lock, * task_rq_lock). A budget expiry there reaches __schedule, which * takes the very lock being spun for: on a single cooperative * dispatcher that is a self-deadlock, and the same shape holds * for a checkpoint anywhere inside any lock-held region. Linux's * mechanism for exactly this is preempt_count — should_resched() * declines a preemption whose preempt_count is non-zero, and * spin_lock() raises it — and this kernel is CONFIG_PREEMPT_NONE * with CONFIG_PREEMPT_COUNT unset, so preempt_count() is a * compile-time 0 and no guard exists. The arch half is now in * place: because the hook preempts through __cond_resched(), * enabling CONFIG_PREEMPT_COUNT would make this kernel INHERIT * Linux's own guard rather than invent one. * * In practice a guest does not observe this today, because the * kernel's own dispatcher yields at every syscall park and the kernel * spends its time servicing rather than computing. A guest CAN * observe it if it drives the kernel into a long syscall-free * computation. If you find one, that is a defect to report, not a * behaviour to design around. * * REJECTED * A bound expressed in milliseconds. It would require the runtime to * interrupt the guest on a clock, and the substrate cannot: see WHY * IT DOES NOT TRANSFER. Quoting one anyway would have been a promise * that reads exactly like Linux's and is not enforced by anything. * * A per-drive bound (or a per-drive attestation recording which drive * an image runs under). That enriches a divergence instead of * removing one: it would have made "checkpointed" mean two different * things and asked every guest author to find out which one applied * to them. The drives were made to agree instead. * * MEASURED * brintium/pass/coroutinize/sp_bound.mjs (run by run-coro.sh * beside it). The load-bearing assertion is the * ITERATION count and contains no timing: N iterations at the shipped * budget must take at least ceil(N/budget) slices, and fewer is the * promise broken. The exemption term is read out of the compile's own * SAFEPOINT-CENSUS k_exempt= rather than out of this file, so the two * places the number lives cannot disagree silently, and * bounded_exempt.mjs pins the shipped 65536 from both sides with a * pair of loops whose max trip counts straddle it by one. * * The millisecond figures quoted above are re-measured by the same * gate on every run and asserted against a ceiling, so they cannot go * stale unnoticed either. * * AND FROM THE GUEST SIDE. * distros/linux-6.12-musl-busybox/tools/run-preempt-gate.mjs. The * entries in this list are otherwise observed by * run-divergence-gate.mjs, which EXECUTES each of them under busybox * on the production vmlinux — because twice an entry here described a * handler no guest could reach, and a contract only its own compiler * can see is the same failure in a different costume. So this entry * is executed too: the shipped static busybox image, the production * vmlinux, and a pool of exactly ONE CPU Worker so that pid 1's shell * and the `while :; do :; done` it forks have one lane between them. * The shell answering WHILE the spinner spins is the observation, and * it is made from the OTHER process's vantage rather than from the * spinner's. * * Its RED arm is what makes that mean anything: the same image and * the same shell, with the runtime's cooperative yield disabled * (HWJS_NO_SP_YIELD), must STARVE. If the shell answers in both arms, * something other than preemption was letting it run and the gate * reports itself vacuous rather than green. Both arms run in one * invocation, in separate processes, because the yield knob is read * once per process and an inherited one would quietly make the second * arm a copy of the first. * * What the guest-side arm does NOT do is re-derive the number: 65536 * is an iteration count, and a guest observing wall-clock progress * cannot see iterations. The number stays proved where it can be — * sp_bound.mjs and bounded_exempt.mjs, above. The two vantages answer * different questions on purpose. * * --------------------------------------------------------------------- * D-AFFINITY — sched_setaffinity (203), sched_getaffinity (204), * getcpu (309) * --------------------------------------------------------------------- * * NOTE ON SHAPE: this entry has no "WHY IT DOES NOT TRANSFER" section, * and its absence is the point. For the case that matters — a task * pinning ITSELF — the property does transfer: the migration is built * and the syscall behaves as Linux's does. What remains divergent is * narrower than the entry used to be, and it is listed under WHAT STILL * REFUSES with the specific reason for each. This entry stays in * DIVERGENCES because those residuals are real, not because the headline * behaviour differs. * * LINUX PROPERTY * sched_setaffinity() does not merely record a mask; it makes the mask * true. If the caller is running on a CPU the new mask excludes, * affine_move_task() migrates it onto a permitted CPU before the * syscall returns. That is why the standard idiom * * sched_setaffinity(0, sizeof set, &set); /+ pin to CPU N +/ * ... use a CPU-local resource indexed by N ... * * is safe on Linux with no barrier in between: by the time the call * returns, the caller really is on N. * * WHAT WE DO * The same thing, by a different mechanism, for the caller. * * sched_setaffinity(0 /+ or self +/, mask): * - mask contains the caller's current CPU -> record it, return 0. * - mask excludes it -> MIGRATE the caller onto the first CPU in the * mask, then record it and return 0. The call does not return * until the caller is inside the mask, which is upstream's whole * contract. * - the migration could not be completed -> -EAGAIN, and the task * stays exactly where it was. See "WHAT STILL REFUSES" below for * the two ways that happens. * - empty mask -> -EINVAL, as upstream. * * sched_getaffinity() reports what sched_setaffinity() accepted, and * always includes the task's own CPU. It deliberately does not * intersect with cpu_active_mask the way upstream does: only CPU 0 is * ever marked active on this port (arch/wasm32/kernel/setup.c) while * process Workers genuinely run as CPUs 1..n-1, so intersecting would * report {0} to a task provably executing on CPU 3. * * getcpu() is wired, and reports the per-Instance __wasm32_cpu_id * global — the same value raw_smp_processor_id() reads, i.e. this * arch's definition of "which CPU am I". node is 0: one node, which is * the truth rather than a stub. It is wired BECAUSE of the above: an * affinity contract that cannot be checked from inside the guest is a * claim, not a contract. * * HOW THE MIGRATION WORKS, and why it is not affine_move_task * None of upstream's machinery — migration threads, stop_one_cpu() — * exists here, and none of it could: the state a move must carry that * is NOT in memory is two per-Instance wasm globals (__stack_pointer, * __tls_base) and a per-Worker function table, and nothing inside the * kernel can read another Instance's globals or instantiate a module. * Those are host operations. So the work is split at the only seam * that exists: * * kernel decides a move is required, names the destination CPU in * thread.migrate_to, and returns -ERESTARTRESCHED with the * syscall's own coroutine chain PRESERVED (the ordinary * block-park path; arch/wasm32/kernel/entry.c). * libc parks on that sentinel and re-issues the same syscall — * musl's __wasm32_syscall_park_restart, which every raw * syscall veneer already goes through. No special case was * added to any libc for this. * host services the park. That is the ONE point at which the task * is movable, and the -517 exists to put it there. * kernel on the re-issue, the preserved chain resumes, re-reads * raw_smp_processor_id(), finds itself inside the mask and * returns 0. * * The park is this port's stop_one_cpu(): both are "stop running, let * the mover work, resume". This one is cheaper because a syscall IS a * park boundary here — the task was going to stop anyway. * * The re-read after the park is what makes the answer honest. It reads * the __wasm32_cpu_id global of whatever Instance is driving the task * NOW, which is the destination Worker's if the move happened and the * source's if it did not. Nothing in the kernel takes the host's word * for it. * * WHAT THE HOST ACTUALLY MOVES (hardwarejs/src/worker.mjs, requestMigrate * and the migrate-resume entry; kernelSpawnHandler.ts, the 'migrate' * handler) * The destination gets the SAME WebAssembly.Memory object, the same * ctrl SAB, the same task_struct address, and the module bytes. It * binds `current` to that address rather than allocating a task, * replays the module graph from the placement record the fork path * already produces, restores the two globals, and re-enters the saved * coroutine leaf. The source then stops driving. * * Everything not in that list survives because it never moved: the * coroutine frames are at absolute offsets in a shared arena, the fd * table and the signal state hang off the task_struct in shared kernel * memory, and the user address space is the identical SAB. An open * FUSE fd and a pending signal crossing a migration intact is a * consequence of the design rather than a feature of it — measured * once anyway, in the gate named below. * * The one thing that DID need building beyond the hand-off is the * arena's lane bookkeeping. Kernel arena chunks carry a carving-lane * tag and __hwjs_frame_free REFUSES a cross-lane free, on the stated * grounds that a chain never migrates. A migrated task's preserved * syscall frames are carved on the source lane and torn down on the * destination's, so the hand-off RETAGS exactly that task's live * chunks (__hwjs_frame_migrate_lane, bounded by a per-chunk owner tag * so a co-resident peer's frames keep theirs) and moves the per-lane * census by the number of chunks it actually moved. The guard is not * weakened; the retag records that the chunks changed hands, which is * what happened. * * THE HAND-OFF IS TWO-PHASE, AND CANNOT LOSE THE TASK * A 4-word shared protocol block carries OFFERED -> CLAIMED -> BOUND, * with ABORTED reachable from either non-terminal state by any party * that CASes from the value it observed. BOUND is written by exactly * one writer — the destination — after every fallible step (place, * claim, compile, instantiate, replay, bind, pid-check, globals). * * The source releases the task IF AND ONLY IF it observes BOUND. Until * then it has released nothing: the task is still resident on it and * still drivable, and an abort costs one re-entry of the drive. * * So "the destination dies between source-released and * destination-bound" is not a window that is detected and recovered * from; it is unreachable, because "source released" is DEFINED as * "observed the commit". A destination that dies before its CAS leaves * the source waiting on a deadline, after which the source aborts and * resumes a task it never stopped owning. A destination that dies * after its CAS is not a migration failure at all — it is a pool * Worker dying with a resident on it, which this changes in no way. * * What IS detected rather than prevented is a destination that claims * and then neither binds nor dies. Both the host and the source hold * bounded deadlines; the report names the phase, both CPUs and the * pid, and distinguishes "no lane ever claimed the offer" from "a lane * claimed it and never committed". The RED arm of the gate below * forces exactly that state and asserts the process survives it. * * WHAT STILL REFUSES, and why each is truthful rather than provisional * * 1. MOVING ANOTHER TASK — sched_setaffinity(pid != self, mask) with a * mask excluding that task's CPU is -EINVAL. * * This is a real limit, not an unbuilt feature. The two globals a * move must carry are readable only from the OS thread whose * Instance owns them, so the moving task's own host driver has to * participate. For the caller that is free — it is already parked. * For another task it means asking a foreign Worker to migrate * itself at its next park and blocking the caller until it does, * which is a different syscall shape (asynchronous, and unbounded * when the target is inside an unsafepointed loop and reaches no * park at all). Buildable; not built; refused rather than faked. * * 2. A LIBC THAT DOES NOT ABSORB -517 AT RAW VENEERS — glibc today. * Its guest gets -EAGAIN after the kernel's attempt bound instead * of a move. * * The reason is the libc's park ABI, not the substrate: without the * veneer park the -517 is answered by the host's in-place * block-restart loop, which re-issues the syscall from inside the * same slice and therefore never reaches the park the move needs. * Propagating -517 to such a libc anyway would leak it to userland * as a bogus errno, which is worse than a truthful refusal. * * 3. A TASK THAT CANNOT REACH A PARK. Unreachable for the caller by * construction — issuing a syscall is reaching a park — and it is * the whole content of case 1 for anyone else. A task spinning in a * loop with no safepoint makes no syscalls, so it never asks. * * -EAGAIN, not -EINVAL, for every failed move. -EINVAL says "that mask * is unacceptable", which is no longer true of any mask a possible CPU * appears in. -EAGAIN says "the move did not happen, ask again", which * is what occurred. The bound on asking lives in the kernel * (thread.migrate_fail vs WASM32_MIGRATE_MAX_FAIL) so that a host * without the migration service degrades to a handful of park round * trips and a truthful refusal rather than an unbounded restart loop. * * REJECTED * Recording the mask and reporting it back while letting the task keep * running where it is. The task's real CPU would keep being the truth, * so a guest that pinned itself and then indexed a per-CPU array would * silently race the real owner of that slot. This is also why the * acceptance path is checked by re-reading the CPU rather than by * trusting the migration to have worked, and why getcpu is wired: a * silent race is the worst available outcome, and the only defence * against shipping one is making the claim checkable. * * OUT OF SCOPE, DELIBERATELY: THREADED PROCESSES * Everything above is about a process whose address space has ONE * user-RT lane. Migrating one lane of a shared address space while its * siblings run is a materially different problem: the migrating lane's * module-graph replay would race a sibling's dlopen, and the user * arena's per-lane structures would be read by a lane that is not at * rest — which is precisely why fork's barrier quantifies over ALL * lanes and this hand-off needs only one. Thread execution on this * substrate is refused today anyway (worker.mjs refuses a CLONE_VM * clone on a non-lane-stamped image), so the case is not reachable. * It is named here because "migration works" must not be read as * covering it, and because the all-lanes barrier shape is the evidence * that it is a different problem rather than a bigger one. * * MEASURED * distros/linux-6.12-musl-bash-coreutils/tools/run-migrate-gate.mjs * (probe: tools/migrate-probe/migtest.c). GREEN arm: a guest reads its * CPU, pins itself to a different one, getcpu reports the new one, an * fd it opened before the move still reads the same bytes, a signal it * raised-while-blocked before the move is delivered after it, and it * moves back — with the host transcript showing a committed * Worker-to-Worker hand-off and the arena retag moving the chunks. * RED arm (MIGRATE_RED=1): the destination claims and abandons; the * half-migrated case is reported by name, sched_setaffinity answers * -EAGAIN, and the process lives. * * --------------------------------------------------------------------- * D-SIGRETURN — rt_sigreturn (15) * --------------------------------------------------------------------- * * STATUS: BUILT, 2026-08-03. This entry used to record a refusal. The * refusal named the exact condition under which it would stop being * right, and that condition arrived, so the entry now records what a * guest sees from a real rt_sigreturn and what is still different about * it. The history is kept below, because the useful part of it is that * a documented re-check fired. * * LINUX PROPERTY * rt_sigreturn means "discard the current context and resume the * machine context saved in the signal frame the kernel pushed onto the * user stack". It does not return to its caller. * * It exists because of a constraint on Linux's DELIVERY path, not * because of anything about signals. To run a handler the kernel * OVERWRITES the interrupted context's register file — pc and sp now * name the handler. The interrupted context is destroyed as a running * thing and survives only as bytes in a frame. Something has to put it * back; the return path is a register-file restore and cannot execute * code; so putting it back must be a syscall. * * The mask restore rides along on that: the frame carries uc_sigmask, * and rt_sigreturn does set_current_blocked(&uc_sigmask). Which value * the frame carries is decided at DELIVERY by sigmask_to_save() — * normally current->blocked, but current->saved_sigmask when * TIF_RESTORE_SIGMASK is set, which is how sigsuspend()'s temporary * mask survives exactly as long as the handler and no longer. * * WHAT THIS PORT DOES * The context half has nothing to do here and still does not. A * handler is invoked as an ORDINARY NESTED CALL by the userland * dispatch trampoline — musl's src/signal/wasm32/ * __wasm_signal_dispatch.c, glibc's sysdeps/unix/sysv/linux/wasm32/ * wasm-signal-park.c — which a guest reaches on a syscall return. The * interrupted context is the trampoline's own caller; it is never * overwritten, stays live for the whole time the handler runs, and * resumes when the handler RETURNS. * * The MASK half now does. current->blocked is the only blocked mask on * this port (nr 14 routes to vmlinux; the per-Worker region holds a * kernel-written publication of it — see the ONE OWNER block in * arch/wasm32/kernel/signal.c). A trampoline cannot restore a mask it * does not own, so after the handler returns it calls nr 15, and the * kernel puts the mask back: saved_sigmask if TIF_RESTORE_SIGMASK is * set (consuming it), otherwise the mask the trampoline saved before * the handler. That is sigmask_to_save() + restore_sigcontext's mask * restore, split across the same two moments Linux splits them across. * * THE REMAINING DIVERGENCE, and it is the only one * Upstream rt_sigreturn takes NO arguments: it finds uc_sigmask by * walking to the signal frame at the user stack pointer. There is no * kernel-built frame here and no task_pt_regs to find one from, so * this port's nr 15 takes the mask as an argument: * * rt_sigreturn(const sigset_t *uc_sigmask, size_t setsize) * * Same value, handed over instead of fetched. A guest that calls * rt_sigreturn(2) directly — nothing in either libc does; neither port * uses a sa_restorer — would therefore need the argument, where on * x86_64 it would need a frame at sp. Both are "you must be the code * the kernel handed control to"; the shape of the proof differs. * sigsetsize is validated exactly like every other rt_ signal call, * and SIGKILL/SIGSTOP are stripped by set_current_blocked, as upstream. * * WHAT THE OLD ENTRY SAID, AND WHY THE HISTORY IS KEPT * It refused to build this, correctly, on the ground that the only * state a sigreturn would restore here was the mask, and the mask was * NOT the kernel's: nr 14 was answered by the host with 0 and no * recorded state, so current->blocked was permanently empty and the * trampoline owned the mask end to end and put it back from its own * frame. Two mechanisms for one transition is worse than one, because * two can disagree. * * Before that, an even older entry said rt_sigreturn was UNBUILDABLE * here — "a wasm call stack cannot be resumed from a saved point" — * which was false: hwjs-cc's SJLJ lowering is a working non-local * control transfer and musl's sigsetjmp is built on it. That sentence * is the reason this list's preamble warns about impossibilities * asserted where decisions were meant. * * The 2026-08-02 entry then wrote down the re-check: "if mask * authority moves into the kernel — 14 starts routing to vmlinux and * current->blocked becomes real — then handler entry installs a mask * the kernel owns, handler exit must tell the kernel to put it back, * and that call is rt_sigreturn under its own name. Build it then." * That is what this entry records. The lesson worth carrying is not * about signals: a divergence entry that names its own reversal * condition is one a later reader can act on without re-deriving the * argument. * * --------------------------------------------------------------------- * D-ALTSTACK — sigaltstack (131), and SA_ONSTACK in rt_sigaction (13) * --------------------------------------------------------------------- * * LINUX PROPERTY * sigaltstack() nominates a separate stack, and a handler installed * with SA_ONSTACK runs on it. The point is not tidiness: the reason * the mechanism exists is to let a SIGSEGV handler run after the * normal stack has overflowed. That takes THREE properties together, * and it is worth separating them because only the first transfers: * * 1. the guard page below the stack FAULTS; * 2. the fault becomes a signal the process can CATCH; * 3. the faulting context is STILL INTACT while the handler runs — * the frames below the overflow are live. That is what makes an * alternate stack necessary rather than merely tidy: the handler * cannot be given the stack it just exhausted, because that stack * is still holding the thing it may return into. * * WHY THE PURPOSE DOES NOT TRANSFER * Property 1 transfers. Properties 2 and 3 do not, and 3 alone is * fatal to the mechanism. * * THE FAULT EXISTS — this is a correction. The entry previously said * an overflow "writes over whatever is adjacent in linear memory * instead of trapping", citing asm/thread_info.h. That citation is * about the KERNEL stack: a kmalloc'd region inside env.kernel_memory * with live kernel data below it, where the sentence is true. It says * nothing about sigaltstack, which is about the USER stack — and the * user stack is laid out the other way round. It is the LOWEST region * of user linear memory: measured on a production-linked image, * __stack_pointer initialises to 0x100000 against `-z stack-size` of * 1 MiB, so the stack occupies [0, 1 MiB) and every data segment * starts above it. NOTHING is adjacent below it. An overflow drives * the stack pointer past zero, it wraps to ~4 GiB, and wasm bounds- * checks every linear-memory access against a memory whose maximum is * 1 GiB — so it TRAPS. The unmapped address space above the memory is * the guard page, and it is 3 GiB wide. * * THE FAULT IS NOT CATCHABLE, and this one IS an instruction-set fact. * A wasm trap is not a wasm exception: it is reported to the embedder, * and no in-module construct intercepts it (the exception proposal's * catch_all catches thrown tags, not traps). It unwinds every wasm * frame of the instance to the host boundary. This port reports the * resulting death as SIGILL — hardwarejs/src/worker.mjs, the * run-terminal-trap arm, notifyChildExitOnce(4, signaled) — which is a * wstatus the PARENT reads about a process that is already gone. * Nothing is delivered to the faulting process, because there is no * longer a faulting process to deliver to. * * SO THERE IS NOTHING TO RESCUE. Property 3 is the whole service an * alternate stack renders, and the trap has already discarded the * faulting context before anything could run. A fault handler on this * substrate would necessarily begin with the entire 1 MiB free and * nothing to preserve, which makes a 64 KiB alternate stack strictly * WORSE than the ordinary one rather than a rescue. * * Note what this does not claim. It does not claim we cannot detect a * stack overflow — we detect one today, deterministically, and the * probe below executes it. It claims the detection cannot be turned * into a signal a handler survives, and that this does not change if * the fault is made louder or moved earlier. Any future overflow work * (a software canary, an explicit sp check, moving the trap to the * prologue) lands in the same place: the loudest available report of * an unrecoverable event. Also, separately: the kernel here has no * view of the guest's stack pointer at all — task_pt_regs() is a NULL * cast in arch/wasm32/include/asm/processor.h — so it could not switch * stacks even if it had a reason to. * * WHAT WE DO INSTEAD — a deliberate decision to accept and do nothing * Accepting the call and having it change no behaviour is the CORRECT * behaviour here, not a gap in an implementation. It is recorded as a * decision, in those terms, on purpose. * * sigaltstack() stores and reports faithfully: ss_sp, ss_size and the * flags round-trip, SS_DISABLE is reported when the stack is disabled, * SS_AUTODISARM round-trips, a too-small stack gets -ENOMEM and a bad * ss_flags mode gets -EINVAL, exactly as upstream * (arch/wasm32/kernel/sys_wasm32.c, wasm32_sys_sigaltstack). * SA_ONSTACK is accepted by rt_sigaction, which stores it in sa_flags * unvalidated as upstream does, and has no effect: the userland * dispatch trampoline that actually invokes handlers never reads it, * so handlers run on the normal stack. A guest that nominates a stack * gets Linux's answer to every question it can ask ABOUT that * nomination; it simply never runs on it, because running on it would * buy nothing. * * Two upstream behaviours are absent as a consequence, both because * nothing ever executes on the alternate stack. SS_ONSTACK is never * reported, and the -EPERM that upstream returns for changing the * alternate stack while running on it never occurs. Reporting * SS_ONSTACK would be the fabrication; never reporting it is the * faithful consequence of SA_ONSTACK having no effect. * * Until 2026-08-02 none of the paragraph above was true of anything a * guest could see. 131 was absent from the host routing allowlist, so * the kernel handler never ran and a guest got -ENOSYS — the tree was * doing precisely what the REJECTED paragraph below rejects, while * this entry described the opposite. Routing it * (hardwarejs/src/worker.mjs, the arm beside the affinity family) is * what turned the entry from a claim into a description. * * REJECTED: refusing sigaltstack outright. It is probed by autoconf * and by language runtimes at startup, so refusing would break builds * and abort runtimes, and it would buy no safety — the crash the * mechanism guards against cannot be caught on this substrate whether * we accept the call or refuse it. * * MEASURED * distros/linux-6.12-musl-busybox/tools/run-divergence-gate.mjs * (probe: tools/divergence-probe/divtest.c). It observes every entry * in this list by EXECUTING it under busybox on the production * vmlinux, prints the per-number route witness the REACHABILITY * section quotes, and scores an unreachable number BLOCKED rather than * passing — a gate that greens an arm it never reached proves nothing. * * The arm that settles THIS entry runs as a second invocation * (`divtest guard`), separately and last, because it is trying to kill * itself and must not be able to take the other arms' verdict with it. * A forked child installs a handler for every fault signal (SIGILL * SIGTRAP SIGABRT SIGBUS SIGFPE SIGSEGV SIGSYS SIGSTKFLT SIGXCPU) on a * 64 KiB alternate stack with SA_ONSTACK, then recurses with a 4 KiB * frame per level against a 1 MiB stack. Observed: the child dies * SIGNALLED with SIGILL, NONE of the handlers runs, the host-side * witness for the same death is "memory access out of bounds", and the * parent survives. A handler that DID run is scored a FAILURE, and so * is a recursion that returns — the first would refute the catchability * claim, the second the fault claim. Either finding retires this entry. * * --------------------------------------------------------------------- * D-CREDS — changing who you are: setuid (105), setgid (106), * setreuid/setregid (113/114), setgroups (116), * setresuid/setresgid (117/119), setfsuid/setfsgid (122/123) * --------------------------------------------------------------------- * * LINUX PROPERTY * A process changes its uid/gid and the system then treats it as that * user: file access is decided against the new identity, capabilities * are dropped on the 0 -> non-0 transition, and set-user-ID binaries * are how an unprivileged process reaches privileged operations. The * whole point is the SECOND half. `setuid()` returning 0 is worth * nothing on its own; what a program relies on is that afterwards it * is REFUSED things. * * WHAT WE DO INSTEAD * None of these numbers has a table row, so each returns -ENOSYS. A * guest that writes the ordinary * * if (setuid(uid) != 0) { perror("setuid"); exit(1); } * * stops, which is the honest outcome. getuid/geteuid/getgid/getegid * and capget ARE wired and tell the truth: every process is uid 0 with * a full capability set, for its whole life. capset is wired too, so * capabilities can be dropped; identity cannot be changed. * * WHY THIS IS A REFUSAL AND NOT AN OVERSIGHT * The enforcement a changed uid would have to bind to is not there, * and it is not there in a way that would make wiring these ACTIVELY * DANGEROUS rather than merely incomplete: * * 1. The DAC layer runs but is inert. virtio_fs forces * default_permissions=1, so fuse_permission() does call * generic_permission() — the checks are real and upstream. Every * one of them is short-circuited by the CAP_DAC_OVERRIDE / * CAP_DAC_READ_SEARCH tests, because every process holds * CAP_FULL_SET and there is no way to leave uid 0. * * 2. Guest uids do not name anything. Guest files are served over * FUSE/virtiofs from a host directory by DirFsView, which reports * the host's lstat uid/gid verbatim and accepts-and-ignores guest * chown. So whether guest uid 1000 owns a file depends on which * host account is running the harness. At uid 0 that ambiguity is * invisible; the moment a process could become non-root it would * become load-bearing, and the answers would be ARBITRARY rather * than absent — which is worse, because arbitrary answers look * like enforcement. * * 3. exec cannot raise privilege. The wasm32 user execve is serviced * outside do_execve (worker.mjs intercepts it and calls * wasm32_user_exec_load), so fs/exec.c's search_binary_handler, * and with it bprm_fill_uid(), never runs for a user exec. * S_ISUID is read into the FUSE attr and does nothing. * * Wiring setuid on top of that would let a guest believe it had * dropped privilege while keeping root's access to every file. That is * the same shape as the chroot that did not confine, which this port * has already fixed once. * * THE COUPLING IS ENFORCED, NOT PROMISED * "Do not wire these until the enforcement lands" is a convention, and * this tree has watched conventions of that shape rot into live * defects. So the build performs it: * distros/common/linux-6.12/scripts/hwjs-cred-enforcement-check.py * refuses the kernel link if any of the numbers above acquires a table * row while (a) binfmt_wasm.c still does not honour S_ISUID and (b) no * D-UIDMAP entry defines the guest<->host uid mapping. It runs from * hwjs-pubcheck, an order-prerequisite of every kernel link target, and * carries a nine-case two-sided self-test. Retiring this entry means * satisfying that check, not editing this comment. * * NOT PROVEN HERE, and named rather than left implicit: there is no * guest-side gate asserting the three facts above from inside a * running guest — that -ENOSYS is what a guest actually observes for * each number, that capget reports the full set, and that a mode-000 * file on the guest root opens anyway. The build-time coupling stops * the dangerous state being REACHED; it does not observe the current * state from the guest's side. That gate belongs next to * run-cred-gate.mjs and is not written. * * ===================================================================== * END DIVERGENCES * ===================================================================== */ #define __NR_read 0 #define __NR_write 1 #define __NR_open 2 #define __NR_close 3 #define __NR_stat 4 #define __NR_fstat 5 #define __NR_lstat 6 #define __NR_poll 7 #define __NR_lseek 8 #define __NR_mmap 9 #define __NR_mprotect 10 #define __NR_munmap 11 #define __NR_brk 12 #define __NR_rt_sigaction 13 #define __NR_rt_sigprocmask 14 #define __NR_rt_sigreturn 15 #define __NR_ioctl 16 #define __NR_pread64 17 #define __NR_pwrite64 18 #define __NR_readv 19 #define __NR_writev 20 #define __NR_access 21 #define __NR_pipe 22 #define __NR_select 23 #define __NR_sched_yield 24 #define __NR_mremap 25 #define __NR_msync 26 #define __NR_mincore 27 #define __NR_madvise 28 #define __NR_shmget 29 #define __NR_shmat 30 #define __NR_shmctl 31 #define __NR_dup 32 #define __NR_dup2 33 #define __NR_pause 34 #define __NR_nanosleep 35 #define __NR_getitimer 36 #define __NR_alarm 37 #define __NR_setitimer 38 #define __NR_getpid 39 #define __NR_sendfile 40 #define __NR_socket 41 #define __NR_connect 42 #define __NR_accept 43 #define __NR_sendto 44 #define __NR_recvfrom 45 #define __NR_sendmsg 46 #define __NR_recvmsg 47 #define __NR_shutdown 48 #define __NR_bind 49 #define __NR_listen 50 #define __NR_getsockname 51 #define __NR_getpeername 52 #define __NR_socketpair 53 #define __NR_setsockopt 54 #define __NR_getsockopt 55 #define __NR_clone 56 #define __NR_fork 57 #define __NR_vfork 58 #define __NR_execve 59 #define __NR_exit 60 #define __NR_wait4 61 #define __NR_kill 62 #define __NR_uname 63 #define __NR_semget 64 #define __NR_semop 65 #define __NR_semctl 66 #define __NR_shmdt 67 #define __NR_msgget 68 #define __NR_msgsnd 69 #define __NR_msgrcv 70 #define __NR_msgctl 71 #define __NR_fcntl 72 #define __NR_flock 73 #define __NR_fsync 74 #define __NR_fdatasync 75 #define __NR_truncate 76 #define __NR_ftruncate 77 #define __NR_getdents 78 #define __NR_getcwd 79 #define __NR_chdir 80 #define __NR_fchdir 81 #define __NR_rename 82 #define __NR_mkdir 83 #define __NR_rmdir 84 #define __NR_creat 85 #define __NR_link 86 #define __NR_unlink 87 #define __NR_symlink 88 #define __NR_readlink 89 #define __NR_chmod 90 #define __NR_fchmod 91 #define __NR_chown 92 #define __NR_fchown 93 #define __NR_lchown 94 #define __NR_umask 95 #define __NR_gettimeofday 96 #define __NR_getrlimit 97 #define __NR_getrusage 98 #define __NR_sysinfo 99 #define __NR_times 100 #define __NR_ptrace 101 #define __NR_getuid 102 #define __NR_syslog 103 #define __NR_getgid 104 #define __NR_setuid 105 #define __NR_setgid 106 #define __NR_geteuid 107 #define __NR_getegid 108 #define __NR_setpgid 109 #define __NR_getppid 110 #define __NR_getpgrp 111 #define __NR_setsid 112 #define __NR_setreuid 113 #define __NR_setregid 114 #define __NR_getgroups 115 #define __NR_setgroups 116 #define __NR_setresuid 117 #define __NR_getresuid 118 #define __NR_setresgid 119 #define __NR_getresgid 120 #define __NR_getpgid 121 #define __NR_setfsuid 122 #define __NR_setfsgid 123 #define __NR_getsid 124 #define __NR_capget 125 #define __NR_capset 126 #define __NR_rt_sigpending 127 #define __NR_rt_sigtimedwait 128 #define __NR_rt_sigqueueinfo 129 #define __NR_rt_sigsuspend 130 #define __NR_sigaltstack 131 #define __NR_utime 132 #define __NR_mknod 133 #define __NR_uselib 134 #define __NR_personality 135 #define __NR_ustat 136 #define __NR_statfs 137 #define __NR_fstatfs 138 #define __NR_sysfs 139 #define __NR_getpriority 140 #define __NR_setpriority 141 #define __NR_sched_setparam 142 #define __NR_sched_getparam 143 #define __NR_sched_setscheduler 144 #define __NR_sched_getscheduler 145 #define __NR_sched_get_priority_max 146 #define __NR_sched_get_priority_min 147 #define __NR_sched_rr_get_interval 148 #define __NR_mlock 149 #define __NR_munlock 150 #define __NR_mlockall 151 #define __NR_munlockall 152 #define __NR_vhangup 153 #define __NR_modify_ldt 154 #define __NR_pivot_root 155 #define __NR__sysctl 156 #define __NR_prctl 157 #define __NR_arch_prctl 158 #define __NR_adjtimex 159 #define __NR_setrlimit 160 #define __NR_chroot 161 #define __NR_sync 162 #define __NR_acct 163 #define __NR_settimeofday 164 #define __NR_mount 165 #define __NR_umount2 166 #define __NR_swapon 167 #define __NR_swapoff 168 #define __NR_reboot 169 #define __NR_sethostname 170 #define __NR_setdomainname 171 #define __NR_iopl 172 #define __NR_ioperm 173 #define __NR_create_module 174 #define __NR_init_module 175 #define __NR_delete_module 176 #define __NR_quotactl 179 #define __NR_gettid 186 #define __NR_readahead 187 #define __NR_setxattr 188 #define __NR_lsetxattr 189 #define __NR_fsetxattr 190 #define __NR_getxattr 191 #define __NR_lgetxattr 192 #define __NR_fgetxattr 193 #define __NR_listxattr 194 #define __NR_llistxattr 195 #define __NR_flistxattr 196 #define __NR_removexattr 197 #define __NR_lremovexattr 198 #define __NR_fremovexattr 199 #define __NR_tkill 200 #define __NR_time 201 #define __NR_futex 202 #define __NR_sched_setaffinity 203 #define __NR_sched_getaffinity 204 #define __NR_io_setup 206 #define __NR_io_destroy 207 #define __NR_io_getevents 208 #define __NR_io_submit 209 #define __NR_io_cancel 210 #define __NR_lookup_dcookie 212 #define __NR_epoll_create 213 #define __NR_remap_file_pages 216 #define __NR_getdents64 217 #define __NR_set_tid_address 218 #define __NR_restart_syscall 219 #define __NR_semtimedop 220 #define __NR_fadvise64 221 #define __NR_timer_create 222 #define __NR_timer_settime 223 #define __NR_timer_gettime 224 #define __NR_timer_getoverrun 225 #define __NR_timer_delete 226 #define __NR_clock_settime 227 #define __NR_clock_gettime 228 #define __NR_clock_getres 229 #define __NR_clock_nanosleep 230 #define __NR_exit_group 231 #define __NR_epoll_wait 232 #define __NR_epoll_ctl 233 #define __NR_tgkill 234 #define __NR_utimes 235 #define __NR_mbind 237 #define __NR_set_mempolicy 238 #define __NR_get_mempolicy 239 #define __NR_mq_open 240 #define __NR_mq_unlink 241 #define __NR_mq_timedsend 242 #define __NR_mq_timedreceive 243 #define __NR_mq_notify 244 #define __NR_mq_getsetattr 245 #define __NR_kexec_load 246 #define __NR_waitid 247 #define __NR_add_key 248 #define __NR_request_key 249 #define __NR_keyctl 250 #define __NR_ioprio_set 251 #define __NR_ioprio_get 252 #define __NR_inotify_init 253 #define __NR_inotify_add_watch 254 #define __NR_inotify_rm_watch 255 #define __NR_migrate_pages 256 #define __NR_openat 257 #define __NR_mkdirat 258 #define __NR_mknodat 259 #define __NR_fchownat 260 #define __NR_futimesat 261 #define __NR_newfstatat 262 #define __NR_unlinkat 263 #define __NR_renameat 264 #define __NR_linkat 265 #define __NR_symlinkat 266 #define __NR_readlinkat 267 #define __NR_fchmodat 268 #define __NR_faccessat 269 #define __NR_pselect6 270 #define __NR_ppoll 271 #define __NR_unshare 272 #define __NR_set_robust_list 273 #define __NR_get_robust_list 274 #define __NR_splice 275 #define __NR_tee 276 #define __NR_sync_file_range 277 #define __NR_vmsplice 278 #define __NR_move_pages 279 #define __NR_utimensat 280 #define __NR_epoll_pwait 281 #define __NR_signalfd 282 #define __NR_timerfd_create 283 #define __NR_eventfd 284 #define __NR_fallocate 285 #define __NR_timerfd_settime 286 #define __NR_timerfd_gettime 287 #define __NR_accept4 288 #define __NR_signalfd4 289 #define __NR_eventfd2 290 #define __NR_epoll_create1 291 #define __NR_dup3 292 #define __NR_pipe2 293 #define __NR_inotify_init1 294 #define __NR_preadv 295 #define __NR_pwritev 296 #define __NR_rt_tgsigqueueinfo 297 #define __NR_perf_event_open 298 #define __NR_recvmmsg 299 #define __NR_fanotify_init 300 #define __NR_fanotify_mark 301 #define __NR_prlimit64 302 #define __NR_name_to_handle_at 303 #define __NR_open_by_handle_at 304 #define __NR_clock_adjtime 305 #define __NR_syncfs 306 #define __NR_sendmmsg 307 #define __NR_setns 308 #define __NR_getcpu 309 #define __NR_process_vm_readv 310 #define __NR_process_vm_writev 311 #define __NR_kcmp 312 #define __NR_finit_module 313 #define __NR_sched_setattr 314 #define __NR_sched_getattr 315 #define __NR_renameat2 316 #define __NR_seccomp 317 #define __NR_getrandom 318 #define __NR_memfd_create 319 #define __NR_kexec_file_load 320 #define __NR_bpf 321 #define __NR_execveat 322 #define __NR_userfaultfd 323 #define __NR_membarrier 324 #define __NR_mlock2 325 #define __NR_copy_file_range 326 #define __NR_preadv2 327 #define __NR_pwritev2 328 #define __NR_pkey_mprotect 329 #define __NR_pkey_alloc 330 #define __NR_pkey_free 331 #define __NR_statx 332 #define __NR_io_pgetevents 333 #define __NR_rseq 334 #define __NR_pidfd_send_signal 424 #define __NR_io_uring_setup 425 #define __NR_io_uring_enter 426 #define __NR_io_uring_register 427 #define __NR_open_tree 428 #define __NR_move_mount 429 #define __NR_fsopen 430 #define __NR_fsconfig 431 #define __NR_fsmount 432 #define __NR_fspick 433 #define __NR_pidfd_open 434 #define __NR_clone3 435 #define __NR_close_range 436 #define __NR_openat2 437 #define __NR_pidfd_getfd 438 #define __NR_faccessat2 439 #define __NR_process_madvise 440 #define __NR_epoll_pwait2 441 #define __NR_mount_setattr 442 #define __NR_quotactl_fd 443 #define __NR_landlock_create_ruleset 444 #define __NR_landlock_add_rule 445 #define __NR_landlock_restrict_self 446 #define __NR_memfd_secret 447 #define __NR_process_mrelease 448 #define __NR_futex_waitv 449 #define __NR_set_mempolicy_home_node 450 #define __NR_cachestat 451 #define __NR_fchmodat2 452 #define __NR_timer_settime64 223 #define __NR_timer_gettime64 224 #define __NR_clock_settime64 227 #define __NR_clock_gettime64 228 #define __NR_timerfd_settime64 286 #define __NR_timerfd_gettime64 287 #define __NR_clock_adjtime64 305 /* wasm32-extension numbers (see header comment). */ #define __NR_wasm_spawn_image 1024 #define __NR_wasm_exit_by_signal 1027 #define __NR_wasm_sigconsume 1028 #define __NR_wasm_exec_load_begin 1044 #define __NR_wasm_exec_load_step 1045 #define __NR_wasm_libc_stage 1046 #define __NR_wasm_dlopen_load 1047 #define __NR_wasm_needed_stage 1048 #endif /* _ASM_WASM32_UNISTD_H */