1#include <cx/net/queue.cxh>
2#include <cx/platform/unix.h>
4// FreeBSD-only completion emulation over kqueue, the counterpart to NetQueueEpoll on Linux and IOCP
5// on Windows. Structurally identical to NetQueueEpoll -- one ingest thread feeds the base class's
6// dispatch pool -- but kevent() registers read and write interest as two independent filters per fd
7// rather than one combined interest struct, and there is no recvmmsg equivalent on FreeBSD, so the
8// datagram ingest path is the same unbatched per-packet loop NetQueueSelect uses.
9class NetQueueKqueue extends NetQueue
11 int kq; ///< kqueue instance, created with kqueue()
13 /// @brief Handle -> socket, each entry holding a strong reference
15 /// Same role as NetQueueEpoll's fdmap: maintained incrementally by addSocket/removeSocket
16 /// alongside the kevent() calls that keep the kernel's interest list in sync, and consulted at
17 /// dispatch time rather than trusting a kevent's udata directly, so a stale event referencing an
18 /// fd that has since been closed and reused resolves to nothing instead of the wrong socket. Not
19 /// rebuilt wholesale per pass (unlike NetQueueSelect's), so it can be mutated from an application
20 /// thread (removeSocket, via netsocketClose) at the same time the ingest thread is reading it --
21 /// every access goes through fdmapLock rather than relying on the queue's own socket-table lock.
22 hashtable[uint64,object] fdmap;
24 /// @brief Guards fdmap against the ingest thread and an application/worker thread racing on it
27 /// @brief Dedicated kevent-wait loop thread in threaded mode (NULL in polled mode)
29 /// Same split as NetQueueEpoll/NetQueueSelect: this thread only ingests, filling the runqueue
30 /// via netqueue_submit; the base class's N dispatch workers drain it. In polled mode this stays
31 /// NULL and tick() runs kevent() on the caller's thread.
32 object[Thread] ingest;
34 /// @brief Self-pipe read/write ends, used to interrupt a blocked kevent()
36 /// Registered on kq once at creation with EVFILT_READ and never removed. addSocket/shutdown
37 /// write a byte to wake a parked ingest thread the same way NetSelectSet's wake pipe does.
41 factory create(NetQueueConfig *conf);
43 /// kevent() EV_ADD the new socket's interest immediately; no rebuild to wake for.
46 /// kevent() EV_DELETE the socket's interest immediately.
47 override removeSocket;
49 /// Stop the ingest thread before the base tears the queue down.