Module: CZTop::Socket::FdWait
Overview
Shared FD polling infrastructure for ZMQ sockets.
ZMQ uses a single edge-triggered FD for both read/write signaling. This module provides the low-level wait loop that checks socket readiness and polls the FD.
Constant Summary collapse
- FD_TIMEOUT =
Because ZMQ sockets are edge-triggered, there's a small chance that we miss an edge (race condition). To avoid blocking forever, all waiting on the ZMQ FD is done with this timeout or less.
The race condition exists between the calls to ZsockOptions#readable?/ZsockOptions#writable? and waiting for the ZMQ FD. If the socket becomes readable/writable during that time, waiting for the FD could block forever without a timeout.
0.25- JIFFY =
ZMQ's edge-triggered FD can signal readiness before the socket is actually ready. This small sleep avoids busy-looping in that case.
0.001
Instance Method Summary collapse
-
#wait_for_fd_signal(remaining = nil) ⇒ Object
Waits for the ZMQ file descriptor to signal readiness.
-
#wait_for_socket_state(check, timeout) ⇒ true
Shared implementation for Readable#wait_readable and Writable#wait_writable.
Instance Method Details
#wait_for_fd_signal(remaining = nil) ⇒ Object
Waits for the ZMQ file descriptor to signal readiness.
ZMQ sockets use a single FD for signaling (always via readability, even
for write-readiness). The FD is edge-triggered, so there is a race
between checking socket state and waiting on the FD. To avoid blocking
forever on a missed edge, the wait is capped at remaining seconds or
FD_TIMEOUT, whichever is smaller.
39 40 41 42 43 |
# File 'lib/cztop/socket/fd_wait.rb', line 39 def wait_for_fd_signal(remaining = nil) @fd_io ||= to_io wait = remaining ? [remaining, FD_TIMEOUT].min : FD_TIMEOUT @fd_io.wait_readable(wait) end |
#wait_for_socket_state(check, timeout) ⇒ true
Shared implementation for Readable#wait_readable and Writable#wait_writable.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/cztop/socket/fd_wait.rb', line 52 def wait_for_socket_state(check, timeout) return true if __send__(check) deadline = now + timeout if timeout loop do remaining = deadline ? deadline - now : nil raise ::IO::TimeoutError if remaining&.negative? wait_for_fd_signal(remaining) break if __send__(check) sleep JIFFY break if __send__(check) end true end |