Repository navigation
Conversation
std.os.linux.clock_gettime finds the vDSO through an auxiliary vector that Zig 0.17.0 records only in its own startup code, so under libc's every update_now was a clock_gettime syscall. kqueue already reads posix.system's clock. Assisted-by: Claude Opus 5.5
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.
On Linux with libc linked, every
update_now()on epoll and io_uring is aclock_gettimesyscall, where it should be a vDSO call.Both backends call
std.os.linux.clock_gettime, which uses the vDSO oncestd.os.linux.getauxval(AT_SYSINFO_EHDR)finds it. On Zig 0.17.0 thatgetauxvalreads an auxiliary-vector pointer that only Zig's own_startrecords, so under libc's startup it finds nothing and every read falls back to the syscall (ziglang/zig#36203, fixed after 0.17.0). That covers every program using the C API, and libxev's own tests.kqueue already reads
posix.system.clock_gettime: libc's when libc is linked, andstd.os.linux's otherwise, where Zig's startup does record the vector. This does the same in epoll and io_uring.We hit this in a game server on quic-zig (Linux aarch64 in a VM, epoll, glibc linked, 512 clients).
perf statcounted 1,584clock_gettimesyscalls a second, all fromupdate_now, against 950epoll_pwait: a quarter of the process's syscalls. With this changeupdate_nowmakes none.Test
"epoll, io_uring: loop time is read without a syscall where libc's clock is": a thread installs a seccomp filter, on itself alone, that fails
clock_gettimesyscalls withEPERM. It then callsupdate_now()on an epoll loop and an io_uring loop, and checks that each one's time lies between two libc reads taken around the calls. It is skipped if the filter can't tell the two paths apart (libc's read refused too, orstd.os.linux's not refused), and runs only where libc is linked, which is howzig build testbuilds on Linux.Reverting either backend's change makes it fail. io_uring's had a second problem: it passed
std.os.linux's raw return value toposix.errno, which under libc only treats -1 as a failure, so a failed read was taken as a success and the uninitializedtimespecstored. Withposix.systemthe two agree again.zig build test, 59 passed (the test is Linux-only)zig build -Demit-example -Demit-bench, andzig buildfor every target in the CI matrixCI on
mainfails until #250 moves the workflow to Zig 0.17, so this PR's checks will fail the same way until then.🤖 Generated with Claude Code
https://claude.ai/code/session_015YcSvZdqwMncezgbb64ihg