diff --git a/src/proc.cpp b/src/proc.cpp index 0c1bb9d87..6821e5b70 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -213,6 +213,15 @@ bool job_t::is_completed() const { return true; } +bool job_t::job_chain_is_fully_constructed() const { + const job_t *cursor = this; + while (cursor) { + if (!cursor->is_constructed()) return false; + cursor = cursor->get_parent().get(); + } + return true; +} + void job_t::set_flag(job_flag_t flag, bool set) { this->flags.set(flag, set); } bool job_t::get_flag(job_flag_t flag) const { return this->flags.get(flag); } @@ -397,12 +406,10 @@ static bool process_mark_finished_children(bool block_on_fg) { } if (j != job_fg && j->is_foreground() && !j->is_stopped() && !j->is_completed()) { - // Ignore jobs created via function evaluation in this sanity check - if (!job_fg || - (!job_fg->get_flag(job_flag_t::NESTED) && !j->get_flag(job_flag_t::NESTED))) { - assert(job_fg == nullptr && - "More than one active, fully-constructed foreground job!"); - } + // Ensure that we don't have multiple fully constructed foreground jobs. + assert((!job_fg || !job_fg->job_chain_is_fully_constructed() || + !j->job_chain_is_fully_constructed()) && + "More than one active, fully-constructed foreground job!"); job_fg = j; } @@ -427,7 +434,7 @@ static bool process_mark_finished_children(bool block_on_fg) { options &= ~WNOHANG; } - bool wait_by_process = j->get_flag(job_flag_t::WAIT_BY_PROCESS); + bool wait_by_process = !j->job_chain_is_fully_constructed(); process_list_t::iterator process = j->processes.begin(); // waitpid(2) returns 1 process each time, we need to keep calling it until we've reaped all // children of the pgrp in question or else we can't reset the dirty_state flag. In all diff --git a/src/proc.h b/src/proc.h index 53f615c5a..614375f11 100644 --- a/src/proc.h +++ b/src/proc.h @@ -250,6 +250,12 @@ class job_t { /// The job is in a stopped state bool is_stopped() const; + /// \return the parent job, or nullptr. + const std::shared_ptr get_parent() const { return parent_job; } + + /// \return whether this job and its parent chain are fully constructed. + bool job_chain_is_fully_constructed() const; + // (This function would just be called `continue` but that's obviously a reserved keyword) /// Resume a (possibly) stopped job. Puts job in the foreground. If cont is true, restore the /// saved terminal modes and send the process group a SIGCONT signal to wake it up before we