@@ -36,17 +36,12 @@ and a thread is stuck with a pending signal forever… (I have actually not
3636observed another behavior on macOS.)
3737
3838**On Linux**, the system sends the signal to _all_ threads and assigns the
39- thread as soon as one is ready to handle the signal, but when the signal is
40- allowed to go through via `sigsuspend`, it seems the `libdispatch` catches it _a
41- second time_! (I’m not sure why though.) Furthermore, `libdispatch` overrides
42- the sigaction for a given signal when said signal is registered for monitoring.
43-
44- So to make things work in Linux with this strategy, we’d have to detect the
45- signals received in `libdispatch` because of the call to `sigsuspend`, and also
46- “save” the sigaction somehow and reset it to the original non-overridden by
47- libdispatch value, before calling `sigsuspend` (basically, we’re getting closer
48- to the Unsig strategy…). We’d get a lot of race conditions (AFAICT). I really
49- don’t think this work is worth the trouble. Just use the `Unsig` strategy.
39+ thread as soon as one is ready to handle the signal, so this strategy works.
40+ However, contrary to what the man page says, it seems `libdispatch` _does_
41+ modify the sigaction when a signal source is installed. It seems saving the
42+ sigaction prior to registering the signal source, then setting it back after the
43+ registration of the source fixes the issue though, so we did that. This solution
44+ seems weak though, and might break in the future.
5045
5146- Important: An important side-effect of this technique is if a bootstrapped
5247signal is then sent to a specific thread, the signal will be blocked. Forever.
@@ -245,6 +240,10 @@ public enum SigactionDelayer_Block {
245240 if let ds = blockedSignals [ signal] {
246241 blockedSignal = ds
247242 } else {
243+ #if os(Linux)
244+ let currentSigaction = try Sigaction ( signal: signal)
245+ #endif
246+
248247 try executeOnThread ( . block( signal) )
249248
250249 let dispatchSourceSignal = DispatchSource . makeSignalSource ( signal: signal. rawValue, queue: signalProcessingQueue)
@@ -255,6 +254,17 @@ public enum SigactionDelayer_Block {
255254 dispatchSourceSignal. setEventHandler { processSignalsOnQueue ( signal: signal, count: dispatchSourceSignal. data) }
256255 dispatchSourceSignal. activate ( )
257256
257+ #if os(Linux)
258+ /* On Linux, the sigaction must be reset after a dispatch source signal
259+ * is registerd because libdispatch _does_ modify the sigaction.
260+ * https://github.com/apple/swift-corelibs-libdispatch/pull/560 */
261+ do { try currentSigaction. install ( on: signal) }
262+ catch {
263+ dispatchSourceSignal. cancel ( )
264+ throw error
265+ }
266+ #endif
267+
258268 blockedSignal = BlockedSignal ( dispatchSource: dispatchSourceSignal)
259269 }
260270
0 commit comments