Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't close pipes used for signal handlers in MT #8465

Merged

Conversation

waj
Copy link
Member

@waj waj commented Nov 12, 2019

This should fix #8375

In MT mode, fork is disabled and the event loop is not reinitialized. In other words, fork only works to run a process (i.e: do an exec) right away, without any context switch or IO operations in between.

@bcardiff bcardiff added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib:system labels Nov 12, 2019
@bcardiff bcardiff added this to the 0.32.0 milestone Nov 12, 2019
@ysbaddaden
Copy link
Contributor

ysbaddaden commented Nov 12, 2019

Whatever that fork is disabled in MT: we still fork/exec to run executables, and we must reset signals to SIG_DFL and close the IO pipe in the forked process before calling exec.

@bcardiff
Copy link
Member

@ysbaddaden you mean to extract these lines e5b401f#diff-d7e78211632011c14cdae00909be40ddR239-R241 without the pipe close, right?

It would be good to have at least a manual spec to ensure the behavior of signals is not broken. Otherwise it is doing changes in the dark. Do you have some use case/example to stress that signals are handled as expected?

@ysbaddaden
Copy link
Contributor

ysbaddaden commented Nov 13, 2019

Actually, not closing the reader part of the pipe fixes #8375 for me. I don't know why, but it's okayish: even if the child process receives a signal it won't write it to the pipe (the writer part is closed) and the reader file descriptor will be closed by exec since IO.pipe already set CLOEXEC on it.

diff --git a/src/signal.cr b/src/signal.cr
index f4c094f25..1737b85a0 100644
--- a/src/signal.cr
+++ b/src/signal.cr
@@ -242,7 +242,7 @@ module Crystal::Signal
       LibC.signal(signal, LibC::SIG_DFL) if signal.set?
     end
   ensure
-    @@pipe.each(&.close)
+    writer.close
   end
 
   private def self.reader

NOTE: we disable signals for the current thread (sigmask) for reasons explained in comments and in d195adf, 979a528 and e5b401f. We must reenable signals prior to exec (otherwise the exec'd process would have disabled signals by default, which is unexpected) and should reset signal handlers before that, so we don't handle signals in the forked process (until exec).

@waj
Copy link
Member Author

waj commented Nov 13, 2019

@ysbaddaden The signals are still being reset and the pipes have close_on_exec set by default. I just checked that subprocesses doesn't have extra file descriptors opened when they run.

@waj
Copy link
Member Author

waj commented Nov 13, 2019

Correction... @ysbaddaden you're right, we need to reenable the signals. I'll move the fix into the Signal class.

This was actually a leftover in this commit:
crystal-lang@f544b22
@waj waj force-pushed the fix/8375-dont-run-after-forks-in-mt branch from de22eb7 to f55e681 Compare November 13, 2019 14:40
@waj waj changed the title Don't run "after fork" callbacks in MT Don't close pipes used for signal handlers in MT Nov 13, 2019
@bcardiff bcardiff requested a review from ysbaddaden November 13, 2019 14:47
@ysbaddaden
Copy link
Contributor

ysbaddaden commented Nov 13, 2019

Yes.

The sigset is updated before changing the signal handler so I think we don't even need to ever close the pipe (even without MT). LLVM could reorder instructions and cause the signal handler to be set before the sigset, but the likelihood for a thread to fork while another adds a signal handler and the forked child to receive a signal (sending it to the parent) before exec is very very tiny —and impossible with a single thread anyway.

@bcardiff bcardiff merged commit f32ab9a into crystal-lang:master Nov 14, 2019
@waj waj deleted the fix/8375-dont-run-after-forks-in-mt branch February 12, 2020 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib:system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multiple Faulty Behaviors when using Process inside spawn in MT enabled program
4 participants