Kqueue.cpp deliberately leaves EVFILT_WRITE with NOTE_LOWAT below 1 unimplemented through NotImplemented_nid_no_patch, so LowWaterMarks no longer asserts that it throws. A later implementation of that path would otherwise fail the test.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
A socket EVFILT_READ knote whose NOTE_LOWAT mark is below 1 is now always ready and reports the bytes in the receive buffer, 0 when it is empty, because FreeBSD 11.4 filt_soread returns kn_data >= kn_sdata and the bytes available are never negative. This holds for level-triggered and EV_CLEAR knotes and when EV_ADD changes the mark of an existing knote. A listening socket ignores the mark, as filt_solisten does. An EVFILT_WRITE mark below 1 still throws.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
NOTE_FORK is a valid EVFILT_PROC note that Kqueue.cpp leaves unimplemented, so ProcessExitOnSelf no longer pins that adding it, alone or with NOTE_EXIT, throws, and the unused NoteFork constant goes. Whoever implements NOTE_FORK would otherwise have to edit the test; the libkernel debt entry still records that notes other than NOTE_EXIT throw.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
An EV_ADD of EVFILT_PROC on the calling process with NOTE_EXIT or no notes is now accepted instead of throwing, as FreeBSD 11.4 filt_procattach accepts it: the knote gets EV_CLEAR and does not fire while the process runs, and EV_ADD, EV_ENABLE, EV_DISABLE, EV_DELETE and EV_FORCEONESHOT then act on it as on other knotes. EVFILT_PROC on another process or with notes other than NOTE_EXIT still throws.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
dup2 from a guest socket notified the event queues only when the
replaced descriptor was itself a guest socket. A kqueue replaced this
way stayed registered, so kevent on the number that now names the
socket still returned the old queue's events, and knotes registered on
a replaced pipe or file stayed attached. FreeBSD 11.4's kern_dup closes
the replaced file through closefp, whose knote_fdclose drops every
knote on the descriptor, as the other dup2 paths here already do.
Fixes#11429
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The staging buffer was sized by the guest's nevents, so a request for
INT_MAX events allocated about 64 GiB before the queue reported how many
were pending. It's now bounded at 1024 events; kevent may return fewer
than requested, and events left in the queue come back on the next call.
The test covers an INT_MAX request and a 1030-event queue, and moves away
from the end of StandardInput and the start of main, where #9575 and
#10014 also add tests.
kevent read the changelist and the timeout and wrote the eventlist in
place, so a non-null pointer into unmapped or read-only memory crashed
the host. It now copies the timeout in first, as FreeBSD's sys_kevent
does, copies each change in with GuestCopyIn_nid_no_patch and copies
EV_ERROR entries out one at a time. Triggered events are collected by
the same single queue call as before into a host buffer (on the stack
up to 64 events) and copied out with GuestCopyOut_nid_no_patch, so
level-triggered events are still reported once per call. Any failed
copy returns EFAULT.
On a multi-core Linux machine the race test passed with the split reads it
is meant to catch, and caught them only when the process ran on one CPU.
It now pins itself to its first allowed CPU on Linux. Windows already
catches the split reads unpinned, and pinning there hides them, so it
stays unpinned.
A cleared kqueue watch read the watched queue's triggered count and its
activation counter under two separate locks, so an activation between the
reads was marked seen without making the watch active, and the wakeup was
lost. SnapshotTriggered now returns both under one lock. Every poll of an
active watch also rechecks the count, as kqueue_scan reruns filt_kqueue:
it drops when the watched queue empties and reports the current count.
EV_ADD and EV_ENABLE of an existing watch re-arm it. A separate
guest_kqueue_cleared_race test triggers the watched queue from another
thread while the watching queue waits.
FreeBSD re-evaluates a kqueue's EVFILT_READ note from kqueue_wakeup,
which runs whenever the watched kqueue queues a note, so an EV_CLEAR
note fires again only after such an activation. The equeue now counts
activations, and the EV_CLEAR note fires when the count moves while
notes are queued.
FreeBSD 11.4 dofileread returns 0 for uio_resid == 0 before it calls
fo_read, so read(kq, buf, 0) is 0 and only a non-empty read reaches the
kqueue's EOPNOTSUPP. dofilewrite has no such shortcut, so a zero-length
write stays EOPNOTSUPP. guest_kqueue gets both cases.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Culprit #7049; failing run 40193493248 (linux guest_kqueue aborted after 6 s inside VnodeOneshotWatchStops).
Watch threads of the previous test close their inotify fds after Stop(), so the baseline count could drop below the
final one and the exact equality never held.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A kqueue's file operations (kern_event.c kqueueops) refuse read and write with EOPNOTSUPP through invfo_rdwr, and a kqueue is not seekable, has no vnode for fsync, and is refused by flock. The host placeholder behind a kqueue descriptor is a null device on every host, so read returned end of file, write EBADF, lseek 0, fsync EBADF and flock 0. These calls now fail with EOPNOTSUPP, EOPNOTSUPP, ESPIPE, EINVAL (fsync and fdatasync) and EOPNOTSUPP.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
- a timer change with EV_ADD unset and data 0 keeps the period; one that set
fflags was silently ignored, where FreeBSD 11's kqueue_register copies it
onto the note: it now throws with the other re-adds, waiting for the
measured rules
- EV_ENABLE on a disabled timer reports the expiries missed while disabled in
one step and keeps the note's phase, as FreeBSD 11's filt_timerexpire counts
a disabled note and keeps its p_nexttime; TimerDisableEnableRearm pins it
(5 serial runs and 3 rounds of 8 parallel copies pass)
- the next-wait abort from the review round was observed before main's
5cbc46029b wait refactor and does not reproduce
- RecycleBinDeleteWatchedFile now runs on Windows: its call moves out of the
#ifndef _WIN32 block so the $Extend$Deleted$ path is exercised
- InotifyWatchCount and the two leak assertions gate on __linux__ (macOS has
no /proc; the count was always 0 and the assertion vacuous)
- DisableAndEnable, Dispatch, ForceOneshot and StressTest drop with their
main() calls: they belong to the superseded #6510 feature, and StressTest
asserts strict arrival order across 4 threads with 1-2 ms sleeps (CI flake risk)
Carries the additive pieces of #6510 onto main after its feature was
superseded by #5847: the deleteEventFunc invocation when an EV_ONESHOT
note retires in CollectTriggered, the Windows $Deleted path detection
in FileEvent (IsDeleted transitions), the relaxed timer-modify and
SetVnodeNotes guards, and the compatible kevent tests.
In payload processes on a PS5 (firmware 12.70), re-adding an existing
periodic EVFILT_TIMER with EV_ADD, fflags 0 and a positive period kept
the armed expiry and the expirations already counted, and applied the
new period after that expiry, as FreeBSD 11.0 does. EV_ONESHOT in the
re-add left the timer periodic. Here such a re-add threw; it now does
the same. Re-adding a one-shot or disabled timer, a re-add with nonzero
fflags, a period of 0 or less, a period that overflows the armed expiry
or flags other than EV_ONESHOT, and the other changes to an existing
timer except EV_DELETE still throw.
There, EV_ADD failed with EPERM for EVFILT_AIO, EVFILT_LIO and
EVFILT_SENDFILE at every ident and flag set tried, and EV_DELETE and
EV_ENABLE of them without EV_ADD failed with ENOENT. EVFILT_PROCDESC
failed with EBADF on a descriptor that is not open and with EINVAL on
every kind of open descriptor tried, and EV_DELETE of it on a socket
failed with ENOENT. These filters threw here; they now answer the same
way. EV_ADD of EVFILT_PROCDESC fails with EINVAL on the kinds of
descriptor tried and on shared memory, and throws on other kinds and on
descriptors 0 to 2 that are not sockets or kqueues; a change without
EV_ADD fails with ENOENT, after the descriptor check for
EVFILT_PROCDESC.
A new kevent measurements debt entry, which the kqueue and kevent entry
points to, records these measurements and the answers for NOTE_LOWAT
marks and EVFILT_READ on another kqueue, which still throw here. The
kqueue and kevent entry also stops listing a NOTE_NSECONDS period above
one second with a fraction among the cases that throw, since d71a1c577
made it work.
When the process starts with descriptor 0 closed, open returns 0, dup2(0, 0)
succeeds and closing the temporary descriptor then closes descriptor 0 again,
so the standard input case returned early at its EBADF branch. Skip the dup2
and the close when the temporary descriptor already is 0, on both platform
branches, and check the replacement for an initially open and an initially
closed standard input.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The case expects an EVFILT_WRITE change on descriptor 0 to throw because
descriptor 0 is neither a socket nor the write end of a pipe. When the test
is started with a pipe as standard input the guest cannot tell the ends of a
Windows pipe apart, the change is accepted and the test aborts at that
check. Point descriptor 0 at the null device first so the result no longer
depends on how the test was started.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Follow-up to #8596. nikowolf123 showed in review that an EV_CLEAR EVFILT_WRITE knote with a NOTE_LOWAT mark above 1 on a Linux TCP socket can make kevent wait forever: PollEdge disarms the EPOLLET knote while the free space is below the mark, and Linux TCP wakes EPOLLOUT only after a send or poll found the socket not writable (tcp_check_space), where FreeBSD 11's tcp_input.c calls sowwakeup on every ACK that frees send space. AddDescriptorKnote and ModifyKnote now throw NotImplemented for exactly that combination, a test requires the throw and the combinations that stay supported, and the libkernel debt entry keeps the POLLOUT gate and the stream-only write mark as open gaps.
FreeBSD 11.4 kqueue_scan (sys/kern/kern_event.c) puts a reported level
knote back at the tail of the queue and takes an EV_CLEAR or EV_DISPATCH
knote off it, and knote_enqueue queues that one at the tail when it fires
again. kevent moved a reported knote to the tail only while it stayed
triggered, so a level socket or pipe knote and a re-fired EV_CLEAR or
EV_DISPATCH knote kept their place and could starve later knotes when
nevents is smaller than the number of ready ones. Now every reported
knote that is not deleted moves to the tail.
kevent threw NotImplemented for EVFILT_WRITE with NOTE_LOWAT above 1 on a socket, although the socket readiness check already reports free send-buffer space (SO_SNDBUF less SIOCOUTQ on Linux). The write event now fires once that space reaches the mark, as FreeBSD 11's filt_sowrite compares sbspace with kn_sdata, and stays silent while the space is below it. The debt entry no longer says a write mark is limited to 1. Reference: https://github.com/freebsd/freebsd-src/blob/release/11.0.0/sys/kern/uipc_socket.c