summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Timmermans <fawaka@gmail.com>2012-05-22 16:58:26 +0200
committerLeon Timmermans <fawaka@gmail.com>2012-05-25 22:42:50 +0200
commiteb3d0a5826dc4202bd1ef751f86b4fa666f52d84 (patch)
tree6da988c2ffdd84e8e3c6b1b9af89b71ece132f7d
parent4ea2708986710e9739b5a8ac2ccef0c3a2d896f4 (diff)
downloadperl-eb3d0a5826dc4202bd1ef751f86b4fa666f52d84.tar.gz
Block signals during fork (fixes RT#82580)
-rw-r--r--pod/perldelta.pod6
-rw-r--r--pp_sys.c21
2 files changed, 27 insertions, 0 deletions
diff --git a/pod/perldelta.pod b/pod/perldelta.pod
index 99b7641b8d..026afbcef6 100644
--- a/pod/perldelta.pod
+++ b/pod/perldelta.pod
@@ -638,6 +638,12 @@ C<CORE::GLOBAL> override had op checking performed twice. The checking
is always idempotent for pure Perl code, but the double checking can
matter when custom call checkers are involved.
+=item *
+
+A race condition used to exist around fork that could cause a signal sent to
+the parent to be handled by both parent and child. Signals are now blocked
+briefly around fork to prevent this from happening [perl #82580].
+
=back
=head1 Known Problems
diff --git a/pp_sys.c b/pp_sys.c
index 02b50eacf3..65d527a56c 100644
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -4021,10 +4021,31 @@ PP(pp_fork)
#ifdef HAS_FORK
dVAR; dSP; dTARGET;
Pid_t childpid;
+#if defined(HAS_SIGPROCMASK) && !defined(PERL_MICRO)
+ sigset_t oldmask, newmask;
+#endif
EXTEND(SP, 1);
PERL_FLUSHALL_FOR_CHILD;
+#if defined(HAS_SIGPROCMASK) && !defined(PERL_MICRO)
+ sigfillset(&newmask);
+ sigprocmask(SIG_SETMASK, &newmask, &oldmask);
+#endif
childpid = PerlProc_fork();
+ if (childpid == 0) {
+ int sig;
+ PL_sig_pending = 0;
+ if (PL_psig_pend)
+ for (sig = 1; sig < SIG_SIZE; sig++)
+ PL_psig_pend[sig] = 0;
+ }
+#if defined(HAS_SIGPROCMASK) && !defined(PERL_MICRO)
+ {
+ dSAVE_ERRNO;
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ RESTORE_ERRNO;
+ }
+#endif
if (childpid < 0)
RETSETUNDEF;
if (!childpid) {