Skip to content

Commit ec41d2b

Browse files
committed
Fix race condition: poll proc_get_status() until process exits
The previous approach called proc_get_status() once before proc_close(), but the process could still be running at that point, causing the signal detection to be skipped entirely. Now polls proc_get_status() until the process exits, then reads the definitive signaled/termsig fields. proc_close() is called only to free the resource.
1 parent 6b2b451 commit ec41d2b

File tree

1 file changed

+14
-5
lines changed

1 file changed

+14
-5
lines changed

src/XdebugHandler.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,28 @@ private function doRestart(array $command): void
299299

300300
$process = proc_open($cmd, [], $pipes);
301301
if (is_resource($process)) {
302-
// Use proc_get_status to reliably detect signal deaths, because
303-
// proc_close returns the raw signal number on non-Windows, making
304-
// it indistinguishable from a normal exit code (php/php-src#21292).
302+
// Poll proc_get_status until the process exits, so we can
303+
// reliably read the signaled/termsig fields. We can't use
304+
// proc_close alone because it returns the raw signal number
305+
// on non-Windows, indistinguishable from a normal exit code.
306+
// See https://github.com/php/php-src/issues/21292
305307
$status = proc_get_status($process);
306-
$exitCode = proc_close($process);
308+
while ($status['running']) {
309+
usleep(10_000);
310+
$status = proc_get_status($process);
311+
}
307312

308-
if (!$status['running'] && $status['signaled']) {
313+
if ($status['signaled']) {
309314
$exitCode = 128 + $status['termsig'];
310315
$this->notify(Status::ERROR, sprintf(
311316
'Restarted process was killed by signal %d',
312317
$status['termsig']
313318
));
319+
} else {
320+
$exitCode = $status['exitcode'];
314321
}
322+
323+
proc_close($process);
315324
}
316325

317326
if (!isset($exitCode)) {

0 commit comments

Comments
 (0)