Skip to content

[PHP] fix: preserve syscall widths, seek state, and select signals#758

Merged
brandonpayton merged 5 commits into
integration/kd-6nz-php-phpt-platform-fixesfrom
gascity/kd-6nz/kd-ja1-pr717-abi-docs-residual-split
Jul 11, 2026
Merged

[PHP] fix: preserve syscall widths, seek state, and select signals#758
brandonpayton merged 5 commits into
integration/kd-6nz-php-phpt-platform-fixesfrom
gascity/kd-6nz/kd-ja1-pr717-abi-docs-residual-split

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jun 20, 2026

Copy link
Copy Markdown
Member

Purpose

The original #758 tail combined unrelated ABI, syscall, networking, and build
changes. Review found that only part of that range was safe to retain.

This reviewed replacement preserves three platform invariants needed by
ordinary Unix software:

  • wasm32 cancellation-point syscalls carry 64-bit offsets and lengths;
  • failed or overflowing seeks leave the open-file-description offset unchanged;
  • caught signals interrupt a would-block select() or pselect() without
    discarding an already-ready result.

It also retires one Sortix XFAIL after #756's shared-mapping work made that exact
test pass on both Node and Chromium.

Changes

Cancellation-point syscall arguments

The original two __syscall_cp commits did not actually widen the compiled
function signature: they introduced a type name that the relevant musl
declarations did not consume.

This replacement:

  • gives musl separate architecture-selectable types for the cancellation-point
    syscall number and argument slots;
  • keeps public variadic syscall() arguments as wasm32 long/i32;
  • makes the non-variadic wasm32 __syscall_cp signature
    (i32, i64 x 6) -> i32;
  • aligns the Kandelo glue declaration with that signature; and
  • adds documentation and a guest fixture using pread() above 4 GiB, where
    truncation would read from the wrong offset.

Seek error invariants

The original negative-lseek repair was expanded across the actual kernel and
Node/browser VFS paths.

The reviewed implementation:

  • rejects negative resulting offsets with EINVAL;
  • rejects arithmetic or JavaScript safe-integer overflow with EOVERFLOW;
  • preserves the existing offset when validation fails;
  • uses exact signed-i64 transport for OPFS channel arguments and results;
  • resets the OPFS proxy channel after result consumption; and
  • covers Node host files, HostFS, OPFS, SharedFS, and kernel-owned directory,
    procfs, synthetic-file, framebuffer, and memfd seek paths.

Focused backend, kernel, guest, and real-Chromium OPFS coverage was added, and
docs/posix-status.md records the observable error contract.

Signal-interrupted select

The host retry loop now returns EINTR only when a caught signal interrupts a
would-block select() or pselect() outcome. It also:

  • handles the no-fd sleep path;
  • binds delivery to the exact channel thread;
  • preserves a concurrently ready result;
  • leaves ignored-signal waits parked;
  • retains default-signal termination behavior; and
  • restores the temporary pselect() mask before returning.

Focused outcome tests and a real guest fixture cover select(), pselect(),
mask restoration, ignored signals, ready results, and default termination.

Sortix XFAIL

The basic/pthread/pthread_condattr_setpshared XFAIL was removed from both Node
and browser runners. #756's anonymous shared-mapping coherence is sufficient
for this test because its shared state crosses condition-variable syscalls.

The documentation states the remaining boundary: this is syscall-boundary
coherence, not immediately shared physical memory or cross-process futex
visibility.

Changes intentionally not retained

  • AF_NETLINK / NETLINK_ROUTE: dropped. The source commit does not compile,
    and its loopback-only model, receive semantics, address handling, protocol
    acceptance, and fork/exec state are not a safe netlink contract. The missing
    feature remains visible instead of exposing a misleading partial
    implementation.
  • times(2): dropped. The proposed implementation returned elapsed ticks
    while fabricating every process and waited-child CPU field as zero. Kandelo
    continues to return ENOSYS until it has authoritative CPU accounting.
  • bzip2 dev-shell change: dropped as redundant with tooling already carried
    by the aggregate base, including its newer ORAS dependency.
  • No stale ABI snapshot, generated binding, netlink, Times, or flake changes
    from the original range are retained.

ABI disposition

The linked musl/glue __syscall_cp function type is ABI even though the current
structural snapshot does not record it. The seek and select changes also alter
observable syscall semantics.

This constituent is therefore quarantined inside Batch 2 and is not
independently ready for main. It intentionally does not mint another ABI 16.
The aggregate must assign these changes to ABI 17 in the single planned
reconciliation, regenerate all ABI evidence, and rebuild ABI-bound artifacts
before #871 can advance.

Validation

Run through the repository dev shell on the exact reviewed tree:

  • fresh wasm32 and wasm64 musl builds succeeded;
  • the rebuilt wasm32 __syscall_cp.o signature was inspected as
    (i32, i64 x 6) -> i32;
  • the canonical full bash build.sh completed;
  • focused backend/unit coverage passed: 4 files, 76 tests, with a separate
    16/16 OPFS-channel rerun;
  • host typechecking completed;
  • focused Node guest/outcome coverage passed: 4 files, 8 tests;
  • the full Rust kernel library command passed: 1,072 passed, 0 failed;
  • the full host Vitest run reported 125 files passed and 25 skipped; 1,124 tests
    passed, 2 expected failures, and 111 skipped;
  • the structural ABI snapshot/header/TypeScript check completed, while the
    semantic ABI reconciliation described above remains deliberately pending;
  • basic/pthread/pthread_condattr_setpshared passed five consecutive Node runs
    and five real-Chromium runs in fresh contexts, each with exit 0 and empty
    stdout/stderr;
  • the direct two-worker OPFS Playwright regression passed in Chromium;
  • three real-Chromium guest programs covering cancellation-point offsets,
    invalid seeks, and signal-interrupted select exited 0 with their expected
    output and no collected browser/network errors;
  • ./run.sh browser reached Vite after all package/image checks reported
    [OK]; after building the PHPT runner's separate generated VFS prerequisite,
    a fresh Chromium page reached Ready in 1.388 seconds and ran a real PHP
    smoke script to exit 0 with exact output and no collected browser/network
    errors.

The full libc suite was also run: 302 pass, 20 XFAIL, 1 flaky-pass, and 1 fail
out of 324. The sole failure is the inherited regression/raise-race aggregate
blocker; this PR does not claim a passing libc suite. Full PHPT, POSIX, full
Sortix, and performance suites were not run here and remain aggregate work.

The direct OPFS test exercises the real two-worker backend. BrowserKernel does
not currently wire OPFS as a guest mount, so guest-through-BrowserKernel OPFS
coverage is not claimed.

Provenance and recommendation

This is a reviewed replacement for the original unique #758 range
62a57714e..771abb8e7, rebuilt as five linear commits on exact Batch 2 tip
98fac9d5f. Its reviewed tree is dccd87f0c.

Recommendation: accept into #871, where it remains quarantined for the
aggregate ABI 16 -> 17 reconciliation and inherited raise-race repair. Do not
land it independently or merge the aggregate before those repairs and the full
aggregate gate.

@github-actions

Copy link
Copy Markdown

Phase B-1 matrix build status — pr-758-staging

ABI v16. 66 built, 1 failed, 67 total.

Package Arch Status Sha
libcurl wasm32 built 7681d83e
libcxx wasm32 built bc611e79
libcxx wasm64 built 13b44e91
libiconv wasm32 built 7ab27539
libiconv wasm64 built e93ae499
libpng wasm32 built 6bc920a8
libxml2 wasm32 built d4c9058c
libxml2 wasm64 built 5a1d8232
openssl wasm32 built aa079458
openssl wasm64 built 854d0c55
sqlite wasm32 built 3454b49c
sqlite wasm64 built 8f9815d6
zlib wasm32 built 6d8fb690
zlib wasm64 built f16d95d0
bc wasm32 built 8b0c1643
bzip2 wasm32 built 1f6e2077
coreutils wasm32 built 54a37d22
curl wasm32 built 98ea65cc
dash wasm32 built 74c03877
diffutils wasm32 built cb1a04a2
dinit wasm32 built 57c118a9
fbdoom wasm32 built f4de8ba7
file wasm32 built 0e4aa41d
findutils wasm32 built 3cb34c0f
gawk wasm32 built bf2b2063
git wasm32 built 715a3eb4
grep wasm32 built d827f874
gzip wasm32 built fe69834f
kandelo-sdk wasm32 built c1611bea
kernel wasm32 failed
less wasm32 built 726316e9
lsof wasm32 built e2e3144f
m4 wasm32 built ca8b04d0
make wasm32 built 16d8c49e
mariadb wasm32 built 97f87d99
mariadb wasm64 built 866f7f94
modeset wasm32 built da0bbc75
msmtpd wasm32 built 4a1fcf42
nano wasm32 built 8eb8257d
ncurses wasm32 built 612fd198
netcat wasm32 built cb77d79c
nginx wasm32 built 2ea21097
php wasm32 built 2613d1bf
posix-utils-lite wasm32 built 05879c12
sed wasm32 built 6bcfa662
spidermonkey wasm32 built 606e8208
tar wasm32 built c1c79aa1
tcl wasm32 built 4a89bd4e
unzip wasm32 built 04614a87
userspace wasm32 built b01e7798
vim wasm32 built e84c337f
wget wasm32 built 220ffc60
xz wasm32 built 000f3cb2
zip wasm32 built 8336e9dc
zstd wasm32 built 455fb39e
bash wasm32 built 7f2c434e
mariadb-test wasm32 built 3606a24a
mariadb-vfs wasm32 built a8127840
mariadb-vfs wasm64 built f6545787
nethack wasm32 built c149e580
node wasm32 built 41ad042f
spidermonkey-node wasm32 built 4a07ed07
vim-browser-bundle wasm32 built 5147de2e
nethack-browser-bundle wasm32 built 549dfd86
rootfs wasm32 built 73f5971f
shell wasm32 built 855fd738
node-vfs wasm32 built ed0025a6

Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.

Kandelo Agent and others added 5 commits July 11, 2026 10:27
Teach the musl build to use a separate non-variadic cancellation-point argument type while leaving the public variadic syscall argument type unchanged.
Use i64 slots for wasm32 non-variadic cancellation-point calls while retaining the public variadic syscall calling convention. Align the linked glue signature, cover an offset above 4 GiB, and document the sysroot ABI boundary.
Reject negative resulting offsets in both Node host-file backends before mutating their open-file-description cursor, with shared backend coverage and an authoritative POSIX-status note.
Return EINTR only when a caught signal interrupts a would-block select or pselect outcome, including select’s no-fd sleep path. Bind the exact channel thread, preserve ready results, retain default-death handling, and cover pselect mask restoration in a real guest.
@brandonpayton
brandonpayton force-pushed the gascity/kd-6nz/kd-ja1-pr717-abi-docs-residual-split branch from 771abb8 to 55ecc91 Compare July 11, 2026 14:43
@brandonpayton brandonpayton changed the title [PHP] fix: split ABI syscall and residual runtime fixes [PHP] fix: preserve syscall widths, seek state, and select signals Jul 11, 2026
@brandonpayton
brandonpayton changed the base branch from integration/kd-6nz-php-phpt-host-browser-base to integration/kd-6nz-php-phpt-platform-fixes July 11, 2026 14:43
@brandonpayton
brandonpayton merged commit dbeafa7 into integration/kd-6nz-php-phpt-platform-fixes Jul 11, 2026
@brandonpayton
brandonpayton deleted the gascity/kd-6nz/kd-ja1-pr717-abi-docs-residual-split branch July 11, 2026 14:44
brandonpayton added a commit that referenced this pull request Jul 13, 2026
The linked cancellation-point function type, 64-bit syscall argument slots, lseek state and errno behavior, and select/pselect blocking and caught-signal handling change existing ABI contracts. Advance ABI 28 to 29 and regenerate ABI evidence atomically.

Source-PR: #758

Folded-Reconstruction: architecture-specific cancellation-slot build support 825712d55.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant