Module: CZTop::Socket::FdWait

Included in:
Readable, Writable
Defined in:
lib/cztop/socket/fd_wait.rb

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

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.

Parameters:

  • remaining (Float, nil) (defaults to: nil)

    seconds until caller's deadline, or nil for no deadline



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.

Parameters:

  • check (Symbol)

    :readable? or :writable?

  • timeout (Numeric, nil)

    timeout in seconds

Returns:

  • (true)

Raises:

  • (IO::TimeoutError)


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