@@ -77,6 +77,7 @@ class Process implements \IteratorAggregate
77
77
private bool $ tty = false ;
78
78
private bool $ pty ;
79
79
private array $ options = ['suppress_errors ' => true , 'bypass_shell ' => true ];
80
+ private array $ ignoredSignals = [];
80
81
81
82
private WindowsPipes |UnixPipes $ processPipes ;
82
83
@@ -346,9 +347,23 @@ public function start(?callable $callback = null, array $env = []): void
346
347
347
348
return true ;
348
349
});
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
+
349
359
try {
350
360
$ process = @proc_open ($ commandline , $ descriptors , $ this ->processPipes ->pipes , $ this ->cwd , $ envPairs , $ this ->options );
351
361
} 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
+
352
367
restore_error_handler ();
353
368
}
354
369
@@ -1206,6 +1221,20 @@ public function setOptions(array $options): void
1206
1221
}
1207
1222
}
1208
1223
1224
+ /**
1225
+ * Define 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
+
1209
1238
/**
1210
1239
* Returns whether TTY is supported on the current operating system.
1211
1240
*/
@@ -1455,6 +1484,11 @@ private function resetProcessData(): void
1455
1484
*/
1456
1485
private function doSignal (int $ signal , bool $ throwException ): bool
1457
1486
{
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
+
1458
1492
if (null === $ pid = $ this ->getPid ()) {
1459
1493
if ($ throwException ) {
1460
1494
throw new LogicException ('Cannot send signal on a non running process. ' );
0 commit comments