mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 21:33:09 +00:00
Fixed cases where first command in chain would stay blocked
I hadn't realized that the for loop is called multiple times for a given "single input" (anything that doesn't include semicolons, etc) to fish, and so processes were being blocked but blocked_pid was lost by the time that the next job (which was reading from the last process in the previous job) came around. Now using a static variable to store the last blocked PID. AFAICT, this main job control loop is always executed from the same process and thread, so this shouldn't need to be wrapped in atomics/mutexes, etc.
This commit is contained in:
parent
cafd856831
commit
fb13b370e2
1 changed files with 23 additions and 14 deletions
37
src/exec.cpp
37
src/exec.cpp
|
@ -493,7 +493,7 @@ 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.
|
||||||
int last_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) {
|
||||||
if (exec_error) {
|
if (exec_error) {
|
||||||
|
@ -511,6 +511,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
|
|
||||||
// See if we need a pipe.
|
// See if we need a pipe.
|
||||||
const bool pipes_to_next_command = !p->is_last_in_job;
|
const bool pipes_to_next_command = !p->is_last_in_job;
|
||||||
|
bool command_blocked = false;
|
||||||
|
|
||||||
//these semaphores will be used to make sure the first process lives long enough for the
|
//these semaphores will be used to make sure the first process lives long enough for the
|
||||||
//next process in the chain to open its handles, process group, etc.
|
//next process in the chain to open its handles, process group, etc.
|
||||||
|
@ -1067,20 +1068,27 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// This is the child process.
|
// This is the child process.
|
||||||
p->pid = getpid();
|
p->pid = getpid();
|
||||||
|
// the process will be resumed by the shell when the next command in the
|
||||||
|
// chain is started
|
||||||
|
setup_child_process(j, p, process_net_io_chain);
|
||||||
|
|
||||||
// start child processes that are part of a job in a stopped state
|
// start child processes that are part of a job in a stopped state
|
||||||
// to ensure that they are still running when the next command in the
|
// to ensure that they are still running when the next command in the
|
||||||
// chain is started.
|
// chain is started.
|
||||||
if (pipes_to_next_command) {
|
if (pipes_to_next_command) {
|
||||||
debug(3, L"Blocking process %d waiting for next command in chain.\n", p->pid);
|
|
||||||
kill(p->pid, SIGSTOP);
|
kill(p->pid, SIGSTOP);
|
||||||
}
|
}
|
||||||
// the process will be resumed by the shell when the next command in the
|
|
||||||
// chain is started
|
|
||||||
setup_child_process(j, p, process_net_io_chain);
|
|
||||||
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...
|
||||||
DIE("safe_launch_process should not have returned");
|
DIE("safe_launch_process should not have returned");
|
||||||
} else {
|
} else {
|
||||||
|
if (pipes_to_next_command) {
|
||||||
|
//it actually blocked itself after forking above, but print in here for output
|
||||||
|
//synchronization and so we can assign blocked_pid in the correct address space
|
||||||
|
debug(2, L"Blocking process %d waiting for next command in chain.\n", pid);
|
||||||
|
command_blocked = true;
|
||||||
|
}
|
||||||
debug(2, L"Fork #%d, pid %d: external command '%s' from '%ls'",
|
debug(2, L"Fork #%d, pid %d: external command '%s' from '%ls'",
|
||||||
g_fork_count, pid, p->argv0(), file ? file : L"<no file>");
|
g_fork_count, pid, p->argv0(), file ? file : L"<no file>");
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
|
@ -1104,6 +1112,16 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blocked_pid != -1) {
|
||||||
|
//now that next command in the chain has been started, unblock the previous command
|
||||||
|
debug(2, L"Unblocking process %d.\n", blocked_pid);
|
||||||
|
kill(blocked_pid, SIGCONT);
|
||||||
|
blocked_pid = -1;
|
||||||
|
}
|
||||||
|
if (command_blocked) {
|
||||||
|
blocked_pid = p->pid;
|
||||||
|
}
|
||||||
|
|
||||||
// Close the pipe the current process uses to read from the previous process_t.
|
// Close the pipe the current process uses to read from the previous process_t.
|
||||||
if (pipe_current_read >= 0) {
|
if (pipe_current_read >= 0) {
|
||||||
exec_close(pipe_current_read);
|
exec_close(pipe_current_read);
|
||||||
|
@ -1115,15 +1133,6 @@ void exec_job(parser_t &parser, job_t *j) {
|
||||||
exec_close(pipe_current_write);
|
exec_close(pipe_current_write);
|
||||||
pipe_current_write = -1;
|
pipe_current_write = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//now that next command in the chain has been started, unblock the previous command
|
|
||||||
if (last_pid != -1) {
|
|
||||||
debug(3, L"Unblocking process %d.\n", last_pid);
|
|
||||||
kill(last_pid, SIGCONT);
|
|
||||||
}
|
|
||||||
if (pid != 0) {
|
|
||||||
last_pid = pid;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up any file descriptors we left open.
|
// Clean up any file descriptors we left open.
|
||||||
|
|
Loading…
Reference in a new issue