summaryrefslogtreecommitdiff
path: root/code/snippets/signals_chld_nohang.rb
diff options
context:
space:
mode:
Diffstat (limited to 'code/snippets/signals_chld_nohang.rb')
-rw-r--r--code/snippets/signals_chld_nohang.rb42
1 files changed, 42 insertions, 0 deletions
diff --git a/code/snippets/signals_chld_nohang.rb b/code/snippets/signals_chld_nohang.rb
new file mode 100644
index 0000000..621a70c
--- /dev/null
+++ b/code/snippets/signals_chld_nohang.rb
@@ -0,0 +1,42 @@
+child_processes = 3
+dead_processes = 0
+# We fork 3 child processes.
+child_processes.times do
+ fork do
+ # They sleep for 3 seconds.
+ sleep 3
+ end
+end
+
+# Sync $stdout so the call to #puts in the CHLD handler isn't
+# buffered. Can cause a ThreadError if a signal handler is
+# interrupted after calling #puts. Always a good idea to do
+# this if your handlers will be doing IO.
+$stdout.sync = true
+
+# Our parent process will be busy doing some intense mathematics.
+# But still wants to know when one of its children exits.
+
+# By trapping the :CHLD signal our process will be notified by the kernel
+# when one of its children exits.
+trap(:CHLD) do
+ # Since Process.wait queues up any data that it has for us we can ask for it
+ # here, since we know that one of our child processes has exited.
+
+ # We loop over a non-blocking Process.wait to ensure that any dead child
+ # processes are accounted for.
+ begin
+ while pid = Process.wait(-1, Process::WNOHANG)
+ puts pid
+ dead_processes += 1
+ end
+ rescue Errno::ECHILD
+ end
+end
+
+loop do
+ # We exit ourself once all the child processes are accounted for.
+ exit if dead_processes == child_processes
+
+ sleep 1
+end