mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-12-01 15:14:26 +08:00
OS X EINVAL compatibility for waitpid
The return value on OS X is more along the lines of the documented waitpid behavior; EINVAL is returned if the group no longer exists.
This commit is contained in:
parent
8e63386203
commit
628db65504
|
@ -1163,7 +1163,14 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
//but we only need to call set_child_group for the first process in the group.
|
//but we only need to call set_child_group for the first process in the group.
|
||||||
//If needs_keepalive is set, this has already been called for the keepalive process
|
//If needs_keepalive is set, this has already been called for the keepalive process
|
||||||
pid_t pid_status{};
|
pid_t pid_status{};
|
||||||
if (waitpid(p->pid, &pid_status, WUNTRACED) == -1) {
|
int result;
|
||||||
|
while ((result = waitpid(p->pid, &pid_status, WUNTRACED)) == -1 && errno == EINTR) {
|
||||||
|
//This could be a superfluous interrupt or Ctrl+C at the terminal
|
||||||
|
//In all cases, it is OK to retry since the forking code above is specifically designed
|
||||||
|
//to never, ever hang/block in a child process before the SIGSTOP call is reached.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (result == -1) {
|
||||||
exec_error = true;
|
exec_error = true;
|
||||||
debug(1, L"waitpid(%d) call in unblock_pid failed:!\n", p->pid);
|
debug(1, L"waitpid(%d) call in unblock_pid failed:!\n", p->pid);
|
||||||
wperror(L"waitpid");
|
wperror(L"waitpid");
|
||||||
|
|
23
src/proc.cpp
23
src/proc.cpp
|
@ -819,22 +819,33 @@ bool terminal_give_to_job(job_t *j, int cont) {
|
||||||
//thing is that we can guarantee the process isn't going to exit while we wait (which would cause us to
|
//thing is that we can guarantee the process isn't going to exit while we wait (which would cause us to
|
||||||
//possibly block indefinitely).
|
//possibly block indefinitely).
|
||||||
|
|
||||||
|
auto pgroupTerminated = [&j]() {
|
||||||
|
//everyone in the process group has exited
|
||||||
|
//The only way that can happen is if the very last process in the group terminated, and didn't need
|
||||||
|
//to access the terminal, otherwise it would have hung waiting for terminal IO. We can ignore this.
|
||||||
|
debug(3, L"terminal_give_to_job(): tcsetpgrp called but process group %d has terminated.\n", j->pgid);
|
||||||
|
};
|
||||||
|
|
||||||
while (tcsetpgrp(STDIN_FILENO, j->pgid) != 0) {
|
while (tcsetpgrp(STDIN_FILENO, j->pgid) != 0) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
//always retry on EINTR
|
//always retry on EINTR
|
||||||
}
|
}
|
||||||
|
else if (errno == EINVAL) {
|
||||||
|
//OS X returns EINVAL if the process group no longer lives. Probably other OSes, too.
|
||||||
|
//See comments in pgroupTerminated() above.
|
||||||
|
pgroupTerminated();
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (errno == EPERM) {
|
else if (errno == EPERM) {
|
||||||
//so long as this isn't because the process group is dead
|
//retry so long as this isn't because the process group is dead
|
||||||
int wait_result = waitpid(-1 * j->pgid, &wait_result, WNOHANG);
|
int wait_result = waitpid(-1 * j->pgid, &wait_result, WNOHANG);
|
||||||
if (wait_result == -1) {
|
if (wait_result == -1) {
|
||||||
//everyone in the process group has exited
|
|
||||||
//The only way that can happen is if the very last process in the group terminated, and didn't need
|
|
||||||
//to access the terminal, otherwise it would have hung waiting for terminal IO. We can ignore this.
|
|
||||||
//Note that -1 is technically an "error" for waitpid in the sense that an invalid argument was specified
|
//Note that -1 is technically an "error" for waitpid in the sense that an invalid argument was specified
|
||||||
//because no such process group exists any longer.
|
//because no such process group exists any longer. This is the observed behavior on Linux 4.4.0.
|
||||||
//a "success" result would mean processes from the group still exist but is still running in some state
|
//a "success" result would mean processes from the group still exist but is still running in some state
|
||||||
//or the other.
|
//or the other.
|
||||||
debug(3, L"terminal_give_to_job(): tcsetpgrp called but process group %d has terminated.\n", j->pgid);
|
//See comments in pgroupTerminated() above.
|
||||||
|
pgroupTerminated();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
debug(2, L"terminal_give_to_job(): EPERM.\n", j->pgid);
|
debug(2, L"terminal_give_to_job(): EPERM.\n", j->pgid);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user