Skip to content

Commit 36d6fcd

Browse files
Document child fork interrupt handling
Assisted-By: devx/3236e566-7538-432e-a30a-2bdf37265ed4
1 parent 750e024 commit 36d6fcd

2 files changed

Lines changed: 9 additions & 3 deletions

File tree

lib/async/container/forked.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,19 @@ def exec(*arguments, ready: true, **options)
101101
def self.fork(**options)
102102
# $stderr.puts fork: caller
103103
self.new(**options) do |process|
104+
# Fork from a dedicated thread so the child does not inherit the
105+
# parent fiber scheduler or the current caller's fiber stack. Only
106+
# this short-lived thread is copied into the child process.
104107
::Thread.new do
105108
::Process.fork do
106-
# We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
107109
Signal.trap(:INT){::Thread.current.raise(Interrupt)}
108110
Signal.trap(:TERM){::Thread.current.raise(Interrupt)} # Same as SIGINT.
109111
Signal.trap(:HUP){::Thread.current.raise(Restart)}
110112

111-
# This could be a configuration option:
113+
# CRuby inherits the `Thread.handle_interrupt` mask stack across
114+
# Thread.new, so reset signal delivery in the child before running
115+
# user code. This ensures the signal traps above are delivered
116+
# promptly even if the parent was masking SignalException.
112117
::Thread.handle_interrupt(SignalException => :immediate) do
113118
yield Instance.for(process)
114119
rescue Interrupt

lib/async/container/threaded.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ def exec(*arguments, ready: true, **options)
114114
def self.fork(**options)
115115
self.new(**options) do |thread|
116116
::Thread.new do
117-
# This could be a configuration option (see forked implementation too):
117+
# CRuby inherits the `Thread.handle_interrupt` mask stack across
118+
# Thread.new, so reset signal delivery before running user code.
118119
::Thread.handle_interrupt(SignalException => :immediate) do
119120
yield Instance.for(thread)
120121
end

0 commit comments

Comments
 (0)