Module: Evilution::Parallel::WorkQueue::WorkerRegistry
- Defined in:
- lib/evilution/parallel/work_queue/worker_registry.rb
Overview
Process-global registry of live worker process-group ids (pgids).
EV-jwao / GH #1332: EV-cnx8 made each Worker its own process-group leader so a stuck worker’s whole subtree can be group-killed. Side effect: a terminal Ctrl-C delivers SIGINT only to the parent’s foreground group, so workers (now in their own groups) no longer receive it – and the parent’s fatal-signal death skips work_queue#map’s ‘ensure cleanup_workers`, leaking any worker that was actively running a (possibly blocking) mutation at interrupt time.
Runner#install_signal_handler reads this registry from inside the trap and forwards INT/TERM to each worker group before re-raising to DEFAULT.
Signal-safety: under MRI a trap handler runs on the main thread between VM instructions, so it must not acquire a Mutex (the main thread may hold it -> deadlock). register/unregister therefore swap @pgids for a freshly built frozen array via a single atomic reference assignment (copy-on-write). The trap reads the current reference once and iterates that complete, immutable snapshot – no torn reads, no lock.
Class Attribute Summary collapse
-
.pgids ⇒ Object
readonly
Frozen snapshot.
Class Method Summary collapse
Class Attribute Details
.pgids ⇒ Object (readonly)
Frozen snapshot. Safe to read from a signal handler.
28 29 30 |
# File 'lib/evilution/parallel/work_queue/worker_registry.rb', line 28 def pgids @pgids end |
Class Method Details
.register(pgid) ⇒ Object
30 31 32 |
# File 'lib/evilution/parallel/work_queue/worker_registry.rb', line 30 def register(pgid) @pgids = (@pgids + [pgid]).freeze end |
.signal_all(sig) ⇒ Object
38 39 40 41 42 43 44 45 |
# File 'lib/evilution/parallel/work_queue/worker_registry.rb', line 38 def signal_all(sig) @pgids.each do |pgid| Process.kill(sig, -pgid) rescue Errno::ESRCH # Group already gone (worker + subtree reaped) -- nothing to signal. nil end end |
.unregister(pgid) ⇒ Object
34 35 36 |
# File 'lib/evilution/parallel/work_queue/worker_registry.rb', line 34 def unregister(pgid) @pgids = @pgids.reject { |existing| existing == pgid }.freeze end |