mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-24 05:38:56 +08:00
Revert "Be more judicious about when SIGSTOP is performed"
This reverts commit abf6874a2df910453948a91ac3dc767e64aff6d8. It was meant for the major branch.
This commit is contained in:
parent
607d9e6aef
commit
8a1af4a38d
55
src/exec.cpp
55
src/exec.cpp
@ -495,7 +495,6 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
//
|
//
|
||||||
// We are careful to set these to -1 when closed, so if we exit the loop abruptly, we can still
|
// We are careful to set these to -1 when closed, so if we exit the loop abruptly, we can still
|
||||||
// close them.
|
// close them.
|
||||||
bool pgrp_set = false;
|
|
||||||
static pid_t blocked_pid = -1;
|
static pid_t blocked_pid = -1;
|
||||||
int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1;
|
int pipe_current_read = -1, pipe_current_write = -1, pipe_next_read = -1;
|
||||||
for (std::unique_ptr<process_t> &unique_p : j->processes) {
|
for (std::unique_ptr<process_t> &unique_p : j->processes) {
|
||||||
@ -517,7 +516,6 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
//set to true if we end up forking for this process
|
//set to true if we end up forking for this process
|
||||||
bool child_forked = false;
|
bool child_forked = false;
|
||||||
bool child_spawned = false;
|
bool child_spawned = false;
|
||||||
// bool child_blocked = false;
|
|
||||||
|
|
||||||
// The pipes the current process write to and read from. Unfortunately these can't be just
|
// The pipes the current process write to and read from. Unfortunately these can't be just
|
||||||
// allocated on the stack, since j->io wants shared_ptr.
|
// allocated on the stack, since j->io wants shared_ptr.
|
||||||
@ -639,6 +637,10 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
|
|
||||||
switch (p->type) {
|
switch (p->type) {
|
||||||
case INTERNAL_FUNCTION: {
|
case INTERNAL_FUNCTION: {
|
||||||
|
//internal function never forks
|
||||||
|
//unblock previous (if any) to prevent hang
|
||||||
|
unblock_previous();
|
||||||
|
|
||||||
// Calls to function_get_definition might need to source a file as a part of
|
// Calls to function_get_definition might need to source a file as a part of
|
||||||
// autoloading, hence there must be no blocks.
|
// autoloading, hence there must be no blocks.
|
||||||
signal_unblock();
|
signal_unblock();
|
||||||
@ -814,12 +816,11 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
const int fg = j->get_flag(JOB_FOREGROUND);
|
const int fg = j->get_flag(JOB_FOREGROUND);
|
||||||
j->set_flag(JOB_FOREGROUND, false);
|
j->set_flag(JOB_FOREGROUND, false);
|
||||||
|
|
||||||
|
signal_unblock();
|
||||||
|
|
||||||
//main loop is performing a blocking read from previous command's output
|
//main loop is performing a blocking read from previous command's output
|
||||||
//make sure read source is not blocked
|
//make sure read source is not blocked
|
||||||
unblock_previous();
|
unblock_previous();
|
||||||
|
|
||||||
signal_unblock();
|
|
||||||
|
|
||||||
p->status = builtin_run(parser, p->get_argv(), *builtin_io_streams);
|
p->status = builtin_run(parser, p->get_argv(), *builtin_io_streams);
|
||||||
|
|
||||||
signal_block();
|
signal_block();
|
||||||
@ -887,9 +888,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
// Make child processes pause after executing setup_child_process() to give down-chain
|
// Make child processes pause after executing setup_child_process() to give down-chain
|
||||||
// commands in the job a chance to join their process group and read their pipes.
|
// commands in the job a chance to join their process group and read their pipes.
|
||||||
// The process will be resumed when the next command in the chain is started.
|
// The process will be resumed when the next command in the chain is started.
|
||||||
if (pipes_to_next_command) {
|
|
||||||
kill(p->pid, SIGSTOP);
|
kill(p->pid, SIGSTOP);
|
||||||
}
|
|
||||||
|
|
||||||
exec_write_and_exit(block_output_io_buffer->fd, buffer, count, status);
|
exec_write_and_exit(block_output_io_buffer->fd, buffer, count, status);
|
||||||
} else {
|
} else {
|
||||||
@ -898,9 +897,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
debug(2, L"Fork #%d, pid %d: internal block or function for '%ls'",
|
debug(2, L"Fork #%d, pid %d: internal block or function for '%ls'",
|
||||||
g_fork_count, pid, p->argv0());
|
g_fork_count, pid, p->argv0());
|
||||||
child_forked = true;
|
child_forked = true;
|
||||||
if (pipes_to_next_command) {
|
|
||||||
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
||||||
}
|
|
||||||
p->pid = pid;
|
p->pid = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1019,9 +1016,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
// Make child processes pause after executing setup_child_process() to give down-chain
|
// Make child processes pause after executing setup_child_process() to give down-chain
|
||||||
// commands in the job a chance to join their process group and read their pipes.
|
// commands in the job a chance to join their process group and read their pipes.
|
||||||
// The process will be resumed when the next command in the chain is started.
|
// The process will be resumed when the next command in the chain is started.
|
||||||
if (pipes_to_next_command) {
|
|
||||||
kill(p->pid, SIGSTOP);
|
kill(p->pid, SIGSTOP);
|
||||||
}
|
|
||||||
|
|
||||||
do_builtin_io(outbuff, outbuff_len, errbuff, errbuff_len);
|
do_builtin_io(outbuff, outbuff_len, errbuff, errbuff_len);
|
||||||
exit_without_destructors(p->status);
|
exit_without_destructors(p->status);
|
||||||
@ -1031,9 +1026,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
debug(2, L"Fork #%d, pid %d: internal builtin for '%ls'", g_fork_count, pid,
|
debug(2, L"Fork #%d, pid %d: internal builtin for '%ls'", g_fork_count, pid,
|
||||||
p->argv0());
|
p->argv0());
|
||||||
child_forked = true;
|
child_forked = true;
|
||||||
if (pipes_to_next_command) {
|
|
||||||
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
||||||
}
|
|
||||||
p->pid = pid;
|
p->pid = pid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1114,9 +1107,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
// Make child processes pause after executing setup_child_process() to give down-chain
|
// Make child processes pause after executing setup_child_process() to give down-chain
|
||||||
// commands in the job a chance to join their process group and read their pipes.
|
// commands in the job a chance to join their process group and read their pipes.
|
||||||
// The process will be resumed when the next command in the chain is started.
|
// The process will be resumed when the next command in the chain is started.
|
||||||
if (pipes_to_next_command) {
|
|
||||||
kill(p->pid, SIGSTOP);
|
kill(p->pid, SIGSTOP);
|
||||||
}
|
|
||||||
|
|
||||||
safe_launch_process(p, actual_cmd, argv, envv);
|
safe_launch_process(p, actual_cmd, argv, envv);
|
||||||
// safe_launch_process _never_ returns...
|
// safe_launch_process _never_ returns...
|
||||||
@ -1129,11 +1120,9 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
exec_error = true;
|
exec_error = true;
|
||||||
}
|
}
|
||||||
child_forked = true;
|
child_forked = true;
|
||||||
if (pipes_to_next_command) {
|
|
||||||
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// This is the parent process. Store away information on the child, and possibly
|
// This is the parent process. Store away information on the child, and possibly
|
||||||
// fice it control over the terminal.
|
// fice it control over the terminal.
|
||||||
@ -1148,39 +1137,35 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool child_blocked = child_forked && pipes_to_next_command; //to make things clearer below
|
if (child_spawned) {
|
||||||
if (child_blocked) {
|
//posix_spawn'd processes won't SIGSTOP
|
||||||
|
set_child_group(j, p->pid);
|
||||||
|
}
|
||||||
|
else if (child_forked) {
|
||||||
//we have to wait to ensure the child has set their progress group and is in SIGSTOP state
|
//we have to wait to ensure the child has set their progress group and is in SIGSTOP state
|
||||||
//otherwise, we can later call SIGCONT before they call SIGSTOP and they'll be blocked indefinitely.
|
//otherwise, we can later call SIGCONT before they call SIGSTOP and they'll be blocked indefinitely.
|
||||||
//The child is SIGSTOP'd and is guaranteed to have called child_set_group() at this point.
|
pid_t pid_status{};
|
||||||
|
if (waitpid(p->pid, &pid_status, WUNTRACED) != -1) {
|
||||||
|
//the child is SIGSTOP'd and is guaranteed to have called child_set_group() at this point.
|
||||||
//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{};
|
if (p->is_first_in_job) {
|
||||||
if (waitpid(p->pid, &pid_status, WUNTRACED) == -1) {
|
set_child_group(j, p->pid);
|
||||||
exec_error = true;
|
|
||||||
debug(1, L"waitpid(%d) call in unblock_pid failed:!\n", p->pid);
|
|
||||||
wperror(L"waitpid");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
//we are not unblocking the child via SIGCONT just yet to give the next process a chance to open
|
//we are not unblocking the child via SIGCONT just yet to give the next process a chance to open
|
||||||
//the pipes and join the process group. We only unblock the last process in the job chain because
|
//the pipes and join the process group. We only unblock the last process in the job chain because
|
||||||
//no one awaits it.
|
//no one awaits it.
|
||||||
}
|
}
|
||||||
//regardless of whether the child blocked or not:
|
else {
|
||||||
if (child_spawned || child_forked) {
|
debug(1, L"waitpid(%d) call in unblock_pid failed:!\n", p->pid);
|
||||||
//this should be called after waitpid if child_forked && pipes_to_next_command
|
wperror(L"waitpid");
|
||||||
//it can be called at any time if child_spawned
|
|
||||||
if (!pgrp_set) {
|
|
||||||
set_child_group(j, p->pid);
|
|
||||||
//only once per job, and only once we've executed an external command for real
|
|
||||||
pgrp_set = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//if the command we ran _before_ this one was SIGSTOP'd to let this one catch up, unblock it now.
|
//if the command we ran _before_ this one was SIGSTOP'd to let this one catch up, unblock it now.
|
||||||
//this must be after the wait_pid on the process we just started, if any.
|
//this must be after the wait_pid on the process we just started, if any.
|
||||||
unblock_previous();
|
unblock_previous();
|
||||||
|
|
||||||
if (child_blocked) {
|
if (child_forked) {
|
||||||
//store the newly-blocked command's PID so that it can be SIGCONT'd once the next process
|
//store the newly-blocked command's PID so that it can be SIGCONT'd once the next process
|
||||||
//in the chain is started. That may be in this job or in another job.
|
//in the chain is started. That may be in this job or in another job.
|
||||||
blocked_pid = p->pid;
|
blocked_pid = p->pid;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user