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

proc_get_status exitcode is -1 after setting SIGCHLD #11871

Closed
campbsb opened this issue Aug 4, 2023 · 6 comments
Closed

proc_get_status exitcode is -1 after setting SIGCHLD #11871

campbsb opened this issue Aug 4, 2023 · 6 comments

Comments

@campbsb
Copy link

campbsb commented Aug 4, 2023

Description

After setting SIGCHLD, proc_get_status() returns unreliable exitcode values

On both el7 PHP 8.1.21 and el8 PHP 8.1.22, setting SIGCHLD to SIG_IGN results in proc_get_status returning exitcode -1. See https://stackoverflow.com/questions/71354900/php-proc-get-status-exitcode-is-always-1-after-pcntl-fork

On el8 PHP 8.1.22, setting SIGCHLD to a signal handler results in proc_get_status returning exitcode -1, but el7 PHP 8.1.21 works correctly.

#!/usr/bin/env php
<?php

function handleSIGCHLD($signo) {
}

//pcntl_signal(SIGCHLD, 'handleSIGCHLD');
pcntl_signal(SIGCHLD, SIG_IGN);

$proc = proc_open("/usr/bin/sleep 1", [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes);
do {
    $status = proc_get_status($proc);
    if (! $status['running'])
        break;
    usleep(300000);
} while (true);
echo "Exitcode: $status[exitcode]", PHP_EOL;

PHP Version

PHP 8.1.21 and PHP 8.8.22

Operating System

RHEL 8.8

@dicode-nl
Copy link

@campbsb see #11863, I think this is related due to the signal handler "eating" the process data already.

@dicode-nl
Copy link

dicode-nl commented Aug 4, 2023

@campbsb actually it's unrelated but by-design.

POSIX says about SIG_IGN

If a process sets the action for the SIGCHLD signal to SIG_IGN, the behavior is unspecified,
except as specified under "Consequences of Process Termination" in the description of the _Exit() function (see XSH _Exit).

and "Consequences of Process Termination"

If the parent process of the calling process has set its SA_NOCLDWAIT flag or has set the action for the SIGCHLD signal to SIG_IGN:

The process' status information (see Status Information), if any, shall be discarded.

The lifetime of the calling process shall end immediately. If SA_NOCLDWAIT is set, it is implementation-defined whether a SIGCHLD signal is sent to the parent process.

If a thread in the parent process of the calling process is blocked in wait(), waitpid(), or waitid(), and the parent process has no remaining child processes in the set of waited-for children, the wait(), waitid(), or waitpid() function shall fail and set errno to [ECHILD].

This is also observed in traces of your test script, where 119283 is the PHP process, 119284 the executed command

[pid 119283] wait4(119284, 0x7ffc898ee144, WNOHANG|WSTOPPED, NULL) = 0
[pid 119283] nanosleep({tv_sec=0, tv_nsec=300000000}, NULL) = 0
[pid 119283] wait4(119284, 0x7ffc898ee144, WNOHANG|WSTOPPED, NULL) = 0
[pid 119283] nanosleep({tv_sec=0, tv_nsec=300000000}, NULL) = 0
[pid 119283] wait4(119284, 0x7ffc898ee144, WNOHANG|WSTOPPED, NULL) = 0
[pid 119283] nanosleep({tv_sec=0, tv_nsec=300000000}, <unfinished ...>
[pid 119284] <... nanosleep resumed>NULL) = 0
[pid 119284] close(1) = 0
[pid 119284] close(2) = 0
[pid 119284] exit_group(0) = ?
[pid 119284] +++ exited with 0 +++
[pid 119283] <... nanosleep resumed>NULL) = 0
[pid 119283] wait4(119284, 0x7ffc898ee144, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
[pid 119283] write(1, "Exitcode: -1", 12) = 12
[pid 119283] write(1, "\n", 1

At first, there are children running and the PHP process is waiting for the child to exit. As soon as the child exits, the process' status information is discarded and the next call to wait4 in the parent returns ECHILD.

@campbsb
Copy link
Author

campbsb commented Aug 6, 2023

Here are traces for when an empty signal handler is set, starting from the end of the nanosleeps, up until we write out the exitcode:

Under RHEL7 PHP 8.1.21:

wait4(14747, 0x7ffc5f402234, WNOHANG|WSTOPPED, NULL) = 0
nanosleep({tv_sec=0, tv_nsec=300000000}, NULL) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=14747, si_uid=1554, si_status=0, si_utime=0, si_stime=0} ---
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
wait4(14747, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 14747
write(1, "Exitcode: 0", 11)             = 11

Under RHEL8 PHP 8.1.22:

wait4(126914, 0x7ffcd99dc284, WNOHANG|WSTOPPED, NULL) = 0
nanosleep({tv_sec=0, tv_nsec=300000000}, NULL) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=126914, si_uid=50353, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 126914
wait4(-1, 0x7ffcd99dbae4, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
rt_sigreturn({mask=[]})                 = -1 EINTR (Interrupted system call)
wait4(126914, 0x7ffcd99dc284, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes)
write(1, "Exitcode: -1", 12)            = 12

It seems an additional wait4() call has slipped in there.

@nielsdos
Copy link
Member

nielsdos commented Aug 6, 2023

Can you try the latest 8.1 development branch? Since this problem appeared in 8.1.22 this might be related to the change mentioned above. That change has been reverted in the current development branch.

@campbsb
Copy link
Author

campbsb commented Aug 7, 2023

Thanks @nielsdos - testing shows the issue with setting a signal handler is resolved by your reversion in the 8.1.23-dev branch.

@nielsdos
Copy link
Member

nielsdos commented Aug 7, 2023

Thanks @nielsdos - testing shows the issue with setting a signal handler is resolved by your reversion in the 8.1.23-dev branch.

Ok in that case I'm going to close this as resolved.
If you do re-encounter this problem somehow, just drop a message here and I'll re-open. Thanks.

@nielsdos nielsdos closed this as completed Aug 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants