Make advisory file locks kernel-owned and portable across hosts#961
Open
brandonpayton wants to merge 1 commit into
Open
Make advisory file locks kernel-owned and portable across hosts#961brandonpayton wants to merge 1 commit into
brandonpayton wants to merge 1 commit into
Conversation
Move machine-wide advisory lock state, POSIX range semantics, ownership, and bounded capacity into ProcessTable using a file-sorted high-water Vec. Add stable FileId and OfdId lifetimes, exact host file identity, Rust wake events, and remove the SharedLockTable host path. Bump ABI 39 to 40 and fork state 11 to 12, expose ENOLCK, and update generated bindings, integration coverage, benchmarks, and platform documentation.
Phase B-1 matrix build status —
|
| Package | Arch | Status | Sha |
|---|---|---|---|
| icu | wasm32 | built | 6073f6b9 |
| libcurl | wasm32 | built | 8ba4d3cb |
| libcxx | wasm32 | built | e9099a6a |
| libcxx | wasm64 | built | 6595ad36 |
| libiconv | wasm32 | built | d8e5251f |
| libpng | wasm32 | built | 8bea219e |
| libxml2 | wasm32 | built | 56a278e0 |
| libzip | wasm32 | built | d5f68040 |
| openssl | wasm32 | built | b2bef84f |
| openssl | wasm64 | built | 6e6fdce4 |
| sqlite | wasm32 | built | a761b76d |
| sqlite | wasm64 | built | bd1cbd6e |
| zlib | wasm32 | built | 8dce6292 |
| zlib | wasm64 | built | 867c02ca |
| bc | wasm32 | built | 2871d1de |
| bzip2 | wasm32 | built | 350db8d7 |
| coreutils | wasm32 | built | 973d4a19 |
| curl | wasm32 | built | b69c824b |
| dash | wasm32 | built | 6943b388 |
| diffutils | wasm32 | built | c71e703a |
| dinit | wasm32 | built | 673211df |
| fbdoom | wasm32 | built | c5f9f084 |
| file | wasm32 | built | dc3390ee |
| findutils | wasm32 | built | c8a3a4d5 |
| gawk | wasm32 | built | 61f5bfdf |
| git | wasm32 | built | 16269c4c |
| grep | wasm32 | built | be6909b2 |
| gzip | wasm32 | built | 05ef3c19 |
| hello | wasm32 | built | ffa8c082 |
| kandelo-sdk | wasm32 | built | 4634c890 |
| kernel | wasm32 | built | 0826b047 |
| less | wasm32 | built | 2ed18735 |
| lsof | wasm32 | built | ec360d50 |
| m4 | wasm32 | built | b0233bb6 |
| make | wasm32 | built | 81f6e5ae |
| mariadb | wasm32 | built | 64c0be1a |
| mariadb | wasm64 | built | fdddd569 |
| modeset | wasm32 | built | 3d213441 |
| msmtpd | wasm32 | built | 08a878d8 |
| nano | wasm32 | built | b7d0c527 |
| ncurses | wasm32 | built | 33640b6b |
| netcat | wasm32 | built | 7074e3fb |
| nginx | wasm32 | built | b5e91b44 |
| php | wasm32 | built | 45ced3b0 |
| posix-utils-lite | wasm32 | built | d1809280 |
| ruby | wasm32 | built | d58eeef7 |
| sed | wasm32 | built | dd96947f |
| spidermonkey | wasm32 | built | 4c6728bb |
| tar | wasm32 | built | 32097203 |
| tcl | wasm32 | built | b11a80f5 |
| unzip | wasm32 | built | cffbfa3f |
| userspace | wasm32 | built | 331a1dda |
| vim | wasm32 | built | efbacd81 |
| wget | wasm32 | built | b09ddfee |
| xz | wasm32 | built | 1f72f887 |
| zip | wasm32 | built | e8461b64 |
| zstd | wasm32 | built | a0da68ae |
| bash | wasm32 | built | 23aa8595 |
| mariadb-test | wasm32 | built | 79a5e42d |
| mariadb-vfs | wasm32 | built | 505ba75c |
| mariadb-vfs | wasm64 | built | 142d55c8 |
| nethack | wasm32 | built | b5ecf4cc |
| node | wasm32 | built | e6710e9b |
| spidermonkey-node | wasm32 | built | 3a1bdc78 |
| vim-browser-bundle | wasm32 | built | 8695e8fd |
| nethack-browser-bundle | wasm32 | built | 4d417811 |
| rootfs | wasm32 | built | 34e50c21 |
| shell | wasm32 | built | 9421bed8 |
| lamp | wasm32 | built | e6b7d061 |
| node-vfs | wasm32 | built | 3ee3f064 |
| wordpress | wasm32 | built | eb967d1d |
Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Kandelo currently stores advisory file locks—the cooperative byte-range locks used by databases and other multi-process programs—in a fixed TypeScript
SharedArrayBuffertable. That makes JavaScript, rather than the kernel, responsible for lock ownership, range replacement, and capacity errors. It can misidentify the same open file after a hard link, rename, or unlink, and a native WebAssembly host would have to reimplement the JavaScript lock service.This affects guest programs that coordinate file access across processes, especially SQLite-style workloads, and it lets Node and browser hosts diverge on behavior that should be one Portable Operating System Interface (POSIX) kernel contract. Moving the authoritative state into Rust gives every host the same file identity, ownership, lifecycle, range, blocking, and exhaustion rules while keeping failures truthful and bounded.
What changed
AdvisoryLockManagertoProcessTable. It starts empty and uses a geometrically growing, non-shrinkingVec<LockRecord>sorted by file identity and range, with binary file selection and a hard limit of 4096 normalized records.ENOLCKfailure.OfdId, preserve it through dup/fork/exec/SCM_RIGHTS, and release OFD/flock()locks only on the true machine-wide final reference. Process-lock close, exec, exit, signal-exit, and crash cleanup remain PID/FileId based.fstatvalues. Node uses bigint-native stat data, VFS device IDs are backend-qualified, and OPFS assigns session inode tokens unified withisSameEntry()and retained through rename/unlink.F_SETLKWchannels; it does not store or inspect lock state, andENOLCKnever enters the retry path.host_fcntl_lock,SharedLockTable, its runtime tests/export/registration, and crash spinlock-reset cleanup. Add Rust manager/lifecycle tests plus real kernel-Wasm Node and Chromium/OPFS coverage, targeted benchmark workloads, and contract documentation.ABI and public API impact
ENOLCK(37) and distinguish it from lock conflicts (EAGAIN).host_fcntl_lockimport and public host-packageSharedLockTable,LockInfo, andWasmPosixKernel.registerSharedLockTable()APIs without a compatibility shim.StatResult.dev/inotonumber | bigint; native backends should provide exact bigint values.Validation
bash scripts/dev-shell.sh bash scripts/check-abi-version.shbash scripts/dev-shell.sh bash build.shbash scripts/dev-shell.sh bash scripts/ci-run-test-suite.sh cargo-kernelbash scripts/dev-shell.sh bash scripts/ci-run-test-suite.sh vitestmainexceeded its 5-second timeout. The focused retry below passed.bash scripts/dev-shell.sh bash -lc 'cd host && npx vitest run ../tests/package-system/wasm-artifact-guards.test.ts'bash scripts/dev-shell.sh bash -lc 'export KANDELO_PLAYWRIGHT_PORT=55401; cd apps/browser-demos; npx playwright test test/opfs-advisory-lock.spec.ts test/opfs-identity.spec.ts --project=chromium'bash scripts/dev-shell.sh bash scripts/ci-run-test-suite.sh libcbash scripts/dev-shell.sh bash scripts/ci-run-test-suite.sh posixbash scripts/dev-shell.sh bash scripts/ci-run-test-suite.sh sortixmanydb.test, Node and Chromiumgit diff --checkandgit diff origin/main...HEAD --checkTargeted current-branch advisory-lock measurements were run for three rounds with:
npx tsx benchmarks/run.ts --suite=syscall-io --rounds=3npx tsx benchmarks/run.ts --host=browser --suite=syscall-io --rounds=3Node medians were 14.46/11.63/14.10/11.83 µs per operation for many-file acquire/conflict/replace/unlock and 11.97/9.27/13.24/8.94 µs for dense-file operations. Browser medians were 15.75/7.87/15.75/15.75 µs and 11.72/11.72/11.72/11.72 µs respectively. There is no ABI 39 baseline, so this PR makes no performance-improvement or no-regression claim.
Not completed
./run.sh browserverification were not completed. The focused Chromium/OPFS tests above did run against the rebuilt ABI 40 kernel.cargo fmt --checkstill reports broad pre-existing formatting drift; changed files were reviewed andgit diff --checkis clean.Remaining documented gaps
OfdIdlock identity.close()EINTR handling and the Linuxclose_range()extension remain incomplete.ENOLCK; it never falls back to a pathname hash.