class

Tryst::Notifier

Inherits Reference < Object

@api private - see this file's header comment for the overall design.

Constants

POLL_INTERVAL = 1.millisecond

Polling cadence while WaitForEvent is genuinely waiting (deadline nil or non-zero): each attempt is one poll(2) call with its own timeout already 0 (see poll_once), so this #sleep - not Fiber.yield alone - is what hands control back to Crystal's scheduler between attempts, the same reasoning as Interp#mainloop's macOS poll+sleep fallback. Trade-off is the same one documented there: a floor on event latency (here, ~this interval) in exchange for the rest of the program actually running while Tcl "blocks".

Class methods

abort_unknown_state(pointer : Pointer(Void)) : NoReturn
Source
create_state_for(thread : Thread) : ThreadState
Source
install_once

Tcl_SetNotifier must run before the first Tcl_InitNotifier, which Tcl_CreateInterp triggers internally - called as the very first thing in Interp#initialize, guarded so a process that creates many Interps over its lifetime (this project's persistent test worker does) only installs once. "Extraordinarily unwise to replace a running notifier" per doc/Notifier.3 - this is a one-time, process-wide dispatch-table swap, not something to redo per Interp.

Source
known_state?(pointer : Pointer(Void)) : Bool

See NotifierMacOS.known_state?/.abort_unknown_state - the same check, for tryst_notifier_alert.

Source
poll_once(state : ThreadState) : Bool

One raw poll(2) syscall covering every registered fd plus the alert fd, timeout=0 (never blocks the OS thread itself - WaitForEvent's own loop is what waits, via #sleep between attempts). Returns true if an event was queued (a registered fd) or an alert was consumed (the cross-thread wakeup fd), matching Tcl_WaitForEvent's "found something" case - see this file's header comment for why this can't go through Crystal's own IO readiness tracking.

state.pollfds/poll_fds are rebuilt only when handlers_dirty (set by create/delete_file_handler) - the overwhelmingly common call finds the fd set unchanged since last time and reuses both buffers as-is, with no allocation. revents needs no manual reset between calls: poll(2) itself overwrites it fresh every call, never ORs onto a stale value.

Source
remove_state_for(thread : Thread) : ThreadState | Nil
Source
state_for(thread : Thread) : ThreadState | Nil
Source

Nested types