@@ -77,6 +77,7 @@ class Process implements \IteratorAggregate
7777 private bool $ tty = false ;
7878 private bool $ pty ;
7979 private array $ options = ['suppress_errors ' => true , 'bypass_shell ' => true ];
80+ private array $ ignoredSignals = [];
8081
8182 private WindowsPipes |UnixPipes $ processPipes ;
8283
@@ -346,9 +347,23 @@ public function start(?callable $callback = null, array $env = []): void
346347
347348 return true ;
348349 });
350+
351+ $ oldMask = [];
352+
353+ if (\function_exists ('pcntl_sigprocmask ' )) {
354+ // we block signals we want to ignore, as proc_open will use fork / posix_spawn which will copy the signal mask this allow to block
355+ // signals in the child process
356+ pcntl_sigprocmask (\SIG_BLOCK , $ this ->ignoredSignals , $ oldMask );
357+ }
358+
349359 try {
350360 $ process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ this ->options );
351361 } finally {
362+ if (\function_exists ('pcntl_sigprocmask ' )) {
363+ // we restore the signal mask here to avoid any side effects
364+ pcntl_sigprocmask (\SIG_SETMASK , $ oldMask );
365+ }
366+
352367 restore_error_handler ();
353368 }
354369
@@ -1206,6 +1221,20 @@ public function setOptions(array $options): void
12061221 }
12071222 }
12081223
1224+ /**
1225+ * Defines a list of posix signals that will not be propagated to the process.
1226+ *
1227+ * @param list<\SIG*> $signals
1228+ */
1229+ public function setIgnoredSignals (array $ signals ): void
1230+ {
1231+ if ($ this ->isRunning ()) {
1232+ throw new RuntimeException ('Setting ignored signals while the process is running is not possible. ' );
1233+ }
1234+
1235+ $ this ->ignoredSignals = $ signals ;
1236+ }
1237+
12091238 /**
12101239 * Returns whether TTY is supported on the current operating system.
12111240 */
@@ -1455,6 +1484,11 @@ private function resetProcessData(): void
14551484 */
14561485 private function doSignal (int $ signal , bool $ throwException ): bool
14571486 {
1487+ // Signal seems to be send when sigchild is enable, this allow blocking the signal correctly in this case
1488+ if ($ this ->isSigchildEnabled () && \in_array ($ signal , $ this ->ignoredSignals )) {
1489+ return false ;
1490+ }
1491+
14581492 if (null === $ pid = $ this ->getPid ()) {
14591493 if ($ throwException ) {
14601494 throw new LogicException ('Cannot send signal on a non running process. ' );
0 commit comments