Eliminate the global jobs() function

All job lists are attached to a parser now.
This commit is contained in:
ridiculousfish 2019-05-04 22:12:31 -07:00
parent afff93bdb2
commit 8a8b2513b5
17 changed files with 79 additions and 117 deletions

View file

@ -12,6 +12,7 @@
#include "common.h" #include "common.h"
#include "fallback.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep
#include "io.h" #include "io.h"
#include "parser.h"
#include "proc.h" #include "proc.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
@ -28,9 +29,9 @@ static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
streams.err.append_format(_(L"Send job %d '%ls' to background\n"), j->job_id, streams.err.append_format(_(L"Send job %d '%ls' to background\n"), j->job_id,
j->command_wcstr()); j->command_wcstr());
j->promote(); parser.job_promote(j);
j->set_flag(job_flag_t::FOREGROUND, false); j->set_flag(job_flag_t::FOREGROUND, false);
j->continue_job(true, j->is_stopped()); j->continue_job(parser, true, j->is_stopped());
return STATUS_CMD_OK; return STATUS_CMD_OK;
} }
@ -52,7 +53,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (optind == argc) { if (optind == argc) {
// No jobs were specified so use the most recent (i.e., last) job. // No jobs were specified so use the most recent (i.e., last) job.
job_t *job = nullptr; job_t *job = nullptr;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) { if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) {
job = j.get(); job = j.get();
break; break;

View file

@ -61,7 +61,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Foreground jobs can be disowned. // Foreground jobs can be disowned.
// Even jobs that aren't under job control can be disowned! // Even jobs that aren't under job control can be disowned!
job_t *job = nullptr; job_t *job = nullptr;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->is_constructed() && (!j->is_completed())) { if (j->is_constructed() && (!j->is_completed())) {
job = j.get(); job = j.get();
break; break;

View file

@ -38,7 +38,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
// Select last constructed job (i.e. first job in the job queue) that can be brought // Select last constructed job (i.e. first job in the job queue) that can be brought
// to the foreground. // to the foreground.
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->is_constructed() && (!j->is_completed()) && if (j->is_constructed() && (!j->is_completed()) &&
((j->is_stopped() || (!j->is_foreground())) && ((j->is_stopped() || (!j->is_foreground())) &&
j->get_flag(job_flag_t::JOB_CONTROL))) { j->get_flag(job_flag_t::JOB_CONTROL))) {
@ -103,9 +103,9 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft); if (!ft.empty()) parser.vars().set_one(L"_", ENV_EXPORT, ft);
reader_write_title(job->command(), parser); reader_write_title(job->command(), parser);
job->promote(); parser.job_promote(job);
job->set_flag(job_flag_t::FOREGROUND, true); job->set_flag(job_flag_t::FOREGROUND, true);
job->continue_job(true, job->is_stopped()); job->continue_job(parser, true, job->is_stopped());
return STATUS_CMD_OK; return STATUS_CMD_OK;
} }

View file

@ -9,6 +9,7 @@
#include "common.h" #include "common.h"
#include "fallback.h" // IWYU pragma: keep #include "fallback.h" // IWYU pragma: keep
#include "io.h" #include "io.h"
#include "parser.h"
#include "proc.h" #include "proc.h"
#include "wgetopt.h" #include "wgetopt.h"
#include "wutil.h" // IWYU pragma: keep #include "wutil.h" // IWYU pragma: keep
@ -170,7 +171,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
if (print_last) { if (print_last) {
// Ignore unconstructed jobs, i.e. ourself. // Ignore unconstructed jobs, i.e. ourself.
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->is_visible()) { if (j->is_visible()) {
builtin_jobs_print(j.get(), mode, !streams.out_is_redirected, streams); builtin_jobs_print(j.get(), mode, !streams.out_is_redirected, streams);
return STATUS_CMD_ERROR; return STATUS_CMD_ERROR;
@ -212,7 +213,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
} }
} }
} else { } else {
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
// Ignore unconstructed jobs, i.e. ourself. // Ignore unconstructed jobs, i.e. ourself.
if (j->is_visible()) { if (j->is_visible()) {
builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected, builtin_jobs_print(j.get(), mode, !found && !streams.out_is_redirected,

View file

@ -5,6 +5,7 @@
#include "builtin.h" #include "builtin.h"
#include "builtin_wait.h" #include "builtin_wait.h"
#include "common.h" #include "common.h"
#include "parser.h"
#include "proc.h" #include "proc.h"
#include "reader.h" #include "reader.h"
#include "wgetopt.h" #include "wgetopt.h"
@ -15,8 +16,8 @@
/// Return the job id to which the process with pid belongs. /// Return the job id to which the process with pid belongs.
/// If a specified process has already finished but the job hasn't, parser_t::job_get_from_pid() /// If a specified process has already finished but the job hasn't, parser_t::job_get_from_pid()
/// doesn't work properly, so use this function in wait command. /// doesn't work properly, so use this function in wait command.
static job_id_t get_job_id_from_pid(pid_t pid) { static job_id_t get_job_id_from_pid(pid_t pid, const parser_t &parser) {
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->pgid == pid) { if (j->pgid == pid) {
return j->job_id; return j->job_id;
} }
@ -30,8 +31,8 @@ static job_id_t get_job_id_from_pid(pid_t pid) {
return 0; return 0;
} }
static bool all_jobs_finished() { static bool all_jobs_finished(const parser_t &parser) {
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
// If any job is not completed, return false. // If any job is not completed, return false.
// If there are stopped jobs, they are ignored. // If there are stopped jobs, they are ignored.
if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) { if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) {
@ -41,14 +42,14 @@ static bool all_jobs_finished() {
return true; return true;
} }
static bool any_jobs_finished(size_t jobs_len) { static bool any_jobs_finished(size_t jobs_len, const parser_t &parser) {
bool no_jobs_running = true; bool no_jobs_running = true;
// If any job is removed from list, return true. // If any job is removed from list, return true.
if (jobs_len != jobs().size()) { if (jobs_len != parser.jobs().size()) {
return true; return true;
} }
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
// If any job is completed, return true. // If any job is completed, return true.
if (j->is_constructed() && (j->is_completed() || j->is_stopped())) { if (j->is_constructed() && (j->is_completed() || j->is_stopped())) {
return true; return true;
@ -65,9 +66,10 @@ static bool any_jobs_finished(size_t jobs_len) {
} }
static int wait_for_backgrounds(parser_t &parser, bool any_flag) { static int wait_for_backgrounds(parser_t &parser, bool any_flag) {
size_t jobs_len = jobs().size(); size_t jobs_len = parser.jobs().size();
while ((!any_flag && !all_jobs_finished()) || (any_flag && !any_jobs_finished(jobs_len))) { while ((!any_flag && !all_jobs_finished(parser)) ||
(any_flag && !any_jobs_finished(jobs_len, parser))) {
if (reader_test_interrupted()) { if (reader_test_interrupted()) {
return 128 + SIGINT; return 128 + SIGINT;
} }
@ -137,10 +139,11 @@ static bool match_pid(const wcstring &cmd, const wchar_t *proc) {
} }
/// It should search the job list for something matching the given proc. /// It should search the job list for something matching the given proc.
static bool find_job_by_name(const wchar_t *proc, std::vector<job_id_t> &ids) { static bool find_job_by_name(const wchar_t *proc, std::vector<job_id_t> &ids,
const parser_t &parser) {
bool found = false; bool found = false;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (j->command_is_empty()) continue; if (j->command_is_empty()) continue;
if (match_pid(j->command(), proc)) { if (match_pid(j->command(), proc)) {
@ -219,7 +222,7 @@ int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
argv[i]); argv[i]);
continue; continue;
} }
if (job_id_t id = get_job_id_from_pid(pid)) { if (job_id_t id = get_job_id_from_pid(pid, parser)) {
waited_job_ids.push_back(id); waited_job_ids.push_back(id);
} else { } else {
streams.err.append_format( streams.err.append_format(
@ -227,7 +230,7 @@ int builtin_wait(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
} }
} else { } else {
// argument is process name // argument is process name
if (!find_job_by_name(argv[i], waited_job_ids)) { if (!find_job_by_name(argv[i], waited_job_ids, parser)) {
streams.err.append_format( streams.err.append_format(
_(L"%ls: Could not find child processes with the name '%ls'\n"), cmd, _(L"%ls: Could not find child processes with the name '%ls'\n"), cmd,
argv[i]); argv[i]);

View file

@ -1120,7 +1120,7 @@ bool exec_job(parser_t &parser, shared_ptr<job_t> j) {
return false; return false;
} }
j->continue_job(reclaim_foreground_pgrp, false); j->continue_job(parser, reclaim_foreground_pgrp, false);
return true; return true;
} }

View file

@ -491,7 +491,6 @@ int main(int argc, char **argv) {
} }
history_save_all(); history_save_all();
proc_destroy();
if (opts.print_rusage_self) { if (opts.print_rusage_self) {
print_rusage_self(stderr); print_rusage_self(stderr);
} }

View file

@ -5327,8 +5327,6 @@ int main(int argc, char **argv) {
say(L"Encountered %d errors in low-level tests", err_count); say(L"Encountered %d errors in low-level tests", err_count);
if (s_test_run_count == 0) say(L"*** No Tests Were Actually Run! ***"); if (s_test_run_count == 0) say(L"*** No Tests Were Actually Run! ***");
proc_destroy();
if (err_count != 0) { if (err_count != 0) {
return 1; return 1;
} }

View file

@ -797,7 +797,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
// Protect against exec with background processes running // Protect against exec with background processes running
if (process_type == process_type_t::exec && shell_is_interactive()) { if (process_type == process_type_t::exec && shell_is_interactive()) {
bool have_bg = false; bool have_bg = false;
for (const auto &bg : jobs()) { for (const auto &bg : parser->jobs()) {
// The assumption here is that if it is a foreground job, // The assumption here is that if it is a foreground job,
// it's related to us. // it's related to us.
// This stops us from asking if we're doing `exec` inside a function. // This stops us from asking if we're doing `exec` inside a function.
@ -811,11 +811,11 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
uint64_t current_run_count = reader_run_count(); uint64_t current_run_count = reader_run_count();
uint64_t &last_exec_run_count = parser->libdata().last_exec_run_counter; uint64_t &last_exec_run_count = parser->libdata().last_exec_run_counter;
if (isatty(STDIN_FILENO) && current_run_count - 1 != last_exec_run_count) { if (isatty(STDIN_FILENO) && current_run_count - 1 != last_exec_run_count) {
reader_bg_job_warning(); reader_bg_job_warning(*parser);
last_exec_run_count = current_run_count; last_exec_run_count = current_run_count;
return parse_execution_errored; return parse_execution_errored;
} else { } else {
hup_background_jobs(); hup_background_jobs(*parser);
} }
} }
} }
@ -1142,10 +1142,10 @@ parse_execution_result_t parse_execution_context_t::populate_job_from_job_node(
return result; return result;
} }
static bool remove_job(job_t *job) { static bool remove_job(parser_t &parser, job_t *job) {
for (auto j = jobs().begin(); j != jobs().end(); ++j) { for (auto j = parser.jobs().begin(); j != parser.jobs().end(); ++j) {
if (j->get() == job) { if (j->get() == job) {
jobs().erase(j); parser.jobs().erase(j);
return true; return true;
} }
} }
@ -1276,7 +1276,7 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t<g::job> jo
// Actually execute the job. // Actually execute the job.
if (!exec_job(*this->parser, job)) { if (!exec_job(*this->parser, job)) {
remove_job(job.get()); remove_job(*this->parser, job.get());
} }
// Update universal vaiables on external conmmands. // Update universal vaiables on external conmmands.

View file

@ -571,24 +571,24 @@ wcstring parser_t::current_line() {
void parser_t::job_add(shared_ptr<job_t> job) { void parser_t::job_add(shared_ptr<job_t> job) {
assert(job != NULL); assert(job != NULL);
assert(!job->processes.empty()); assert(!job->processes.empty());
this->my_job_list.push_front(std::move(job)); job_list.push_front(std::move(job));
} }
void parser_t::job_promote(job_t *job) { void parser_t::job_promote(job_t *job) {
job_list_t::iterator loc; job_list_t::iterator loc;
for (loc = my_job_list.begin(); loc != my_job_list.end(); ++loc) { for (loc = job_list.begin(); loc != job_list.end(); ++loc) {
if (loc->get() == job) { if (loc->get() == job) {
break; break;
} }
} }
assert(loc != my_job_list.end()); assert(loc != job_list.end());
// Move the job to the beginning. // Move the job to the beginning.
std::rotate(my_job_list.begin(), loc, my_job_list.end()); std::rotate(job_list.begin(), loc, job_list.end());
} }
job_t *parser_t::job_get(job_id_t id) { job_t *parser_t::job_get(job_id_t id) {
for (const auto &job : my_job_list) { for (const auto &job : job_list) {
if (id <= 0 || job->job_id == id) return job.get(); if (id <= 0 || job->job_id == id) return job.get();
} }
return NULL; return NULL;

View file

@ -172,7 +172,7 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
/// List of called functions, used to help prevent infinite recursion. /// List of called functions, used to help prevent infinite recursion.
wcstring_list_t forbidden_function; wcstring_list_t forbidden_function;
/// The jobs associated with this parser. /// The jobs associated with this parser.
job_list_t my_job_list; job_list_t job_list;
/// The list of blocks /// The list of blocks
std::vector<std::unique_ptr<block_t>> block_stack; std::vector<std::unique_ptr<block_t>> block_stack;
/// The 'depth' of the fish call stack. /// The 'depth' of the fish call stack.
@ -274,7 +274,8 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
size_t block_count() const { return block_stack.size(); } size_t block_count() const { return block_stack.size(); }
/// Get the list of jobs. /// Get the list of jobs.
job_list_t &job_list() { return my_job_list; } job_list_t &jobs() { return job_list; }
const job_list_t &jobs() const { return job_list; }
/// Get the variables. /// Get the variables.
env_stack_t &vars() { return variables; } env_stack_t &vars() { return variables; }

View file

@ -55,16 +55,6 @@ static owning_lock<statuses_t> last_statuses{statuses_t::just(0)};
/// The signals that signify crashes to us. /// The signals that signify crashes to us.
static const int crashsignals[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS}; static const int crashsignals[] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS};
bool job_list_is_empty() {
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_list().empty();
}
job_list_t &jobs() {
ASSERT_IS_MAIN_THREAD();
return parser_t::principal_parser().job_list();
}
bool is_interactive_session = false; bool is_interactive_session = false;
bool is_subshell = false; bool is_subshell = false;
bool is_block = false; bool is_block = false;
@ -96,18 +86,6 @@ static std::vector<int> interactive_stack;
void proc_init() { proc_push_interactive(0); } void proc_init() { proc_push_interactive(0); }
void job_t::promote() {
ASSERT_IS_MAIN_THREAD();
parser_t::principal_parser().job_promote(this);
}
void proc_destroy() {
for (const auto &job : jobs()) {
debug(2, L"freeing leaked job %ls", job->command_wcstr());
}
jobs().clear();
}
void proc_set_last_statuses(statuses_t s) { void proc_set_last_statuses(statuses_t s) {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
*last_statuses.acquire() = std::move(s); *last_statuses.acquire() = std::move(s);
@ -332,7 +310,7 @@ void add_disowned_pgid(pid_t pgid) {
/// See if any reapable processes have exited, and mark them accordingly. /// See if any reapable processes have exited, and mark them accordingly.
/// \param block_ok if no reapable processes have exited, block until one is (or until we receive a /// \param block_ok if no reapable processes have exited, block until one is (or until we receive a
/// signal). /// signal).
static void process_mark_finished_children(bool block_ok) { static void process_mark_finished_children(parser_t &parser, bool block_ok) {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
// Get the exit and signal generations of all reapable processes. // Get the exit and signal generations of all reapable processes.
@ -342,7 +320,7 @@ static void process_mark_finished_children(bool block_ok) {
topic_set_t reaptopics{}; topic_set_t reaptopics{};
generation_list_t gens{}; generation_list_t gens{};
gens.fill(invalid_generation); gens.fill(invalid_generation);
for (const auto j : jobs()) { for (const auto &j : parser.jobs()) {
for (const auto &proc : j->processes) { for (const auto &proc : j->processes) {
if (auto mtopic = j->reap_topic_for_process(proc.get())) { if (auto mtopic = j->reap_topic_for_process(proc.get())) {
topic_t topic = *mtopic; topic_t topic = *mtopic;
@ -367,7 +345,7 @@ static void process_mark_finished_children(bool block_ok) {
// We got some changes. Since we last checked we received SIGCHLD, and or HUP/INT. // We got some changes. Since we last checked we received SIGCHLD, and or HUP/INT.
// Update the hup/int generations and reap any reapable processes. // Update the hup/int generations and reap any reapable processes.
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
for (const auto &proc : j->processes) { for (const auto &proc : j->processes) {
if (auto mtopic = j->reap_topic_for_process(proc.get())) { if (auto mtopic = j->reap_topic_for_process(proc.get())) {
// Update the signal hup/int gen. // Update the signal hup/int gen.
@ -575,15 +553,15 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
const bool interactive = allow_interactive && cur_term != NULL; const bool interactive = allow_interactive && cur_term != NULL;
// Remove all disowned jobs. // Remove all disowned jobs.
remove_disowned_jobs(jobs()); remove_disowned_jobs(parser.jobs());
// Accumulate exit events into a new list, which we fire after the list manipulation is // Accumulate exit events into a new list, which we fire after the list manipulation is
// complete. // complete.
std::vector<event_t> exit_events; std::vector<event_t> exit_events;
// Print status messages for completed or stopped jobs. // Print status messages for completed or stopped jobs.
const bool only_one_job = jobs().size() == 1; const bool only_one_job = parser.jobs().size() == 1;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
// Skip unconstructed jobs. // Skip unconstructed jobs.
if (!j->is_constructed()) { if (!j->is_constructed()) {
continue; continue;
@ -625,7 +603,8 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
// Do this before calling out to user code in the event handler below, to ensure an event // Do this before calling out to user code in the event handler below, to ensure an event
// handler doesn't remove jobs on our behalf. // handler doesn't remove jobs on our behalf.
auto is_complete = [](const shared_ptr<job_t> &j) { return j->is_completed(); }; auto is_complete = [](const shared_ptr<job_t> &j) { return j->is_completed(); };
jobs().erase(std::remove_if(jobs().begin(), jobs().end(), is_complete), jobs().end()); auto &jobs = parser.jobs();
jobs.erase(std::remove_if(jobs.begin(), jobs.end(), is_complete), jobs.end());
// Post pending exit events. // Post pending exit events.
for (const auto &evt : exit_events) { for (const auto &evt : exit_events) {
@ -641,7 +620,7 @@ static bool process_clean_after_marking(parser_t &parser, bool allow_interactive
bool job_reap(parser_t &parser, bool allow_interactive) { bool job_reap(parser_t &parser, bool allow_interactive) {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
process_mark_finished_children(false); process_mark_finished_children(parser, false);
// Preserve the exit status. // Preserve the exit status.
auto saved_statuses = proc_get_last_statuses(); auto saved_statuses = proc_get_last_statuses();
@ -693,8 +672,8 @@ unsigned long proc_get_jiffies(process_t *p) {
} }
/// Update the CPU time for all jobs. /// Update the CPU time for all jobs.
void proc_update_jiffies() { void proc_update_jiffies(parser_t &parser) {
for (const auto &job : jobs()) { for (const auto &job : parser.jobs()) {
for (process_ptr_t &p : job->processes) { for (process_ptr_t &p : job->processes) {
gettimeofday(&p->last_time, 0); gettimeofday(&p->last_time, 0);
p->last_jiffies = proc_get_jiffies(p.get()); p->last_jiffies = proc_get_jiffies(p.get());
@ -858,9 +837,9 @@ return false;
return true; return true;
} }
void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) { void job_t::continue_job(parser_t &parser, bool reclaim_foreground_pgrp, bool send_sigcont) {
// Put job first in the job list. // Put job first in the job list.
promote(); parser.job_promote(this);
set_flag(job_flag_t::NOTIFIED, false); set_flag(job_flag_t::NOTIFIED, false);
debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", send_sigcont ? L"Continue" : L"Start", job_id, debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", send_sigcont ? L"Continue" : L"Start", job_id,
@ -909,7 +888,7 @@ void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) {
if (is_foreground()) { if (is_foreground()) {
// Wait for the status of our own job to change. // Wait for the status of our own job to change.
while (!reader_exit_forced() && !is_stopped() && !is_completed()) { while (!reader_exit_forced() && !is_stopped() && !is_completed()) {
process_mark_finished_children(true); process_mark_finished_children(parser, true);
} }
} }
} }
@ -924,10 +903,10 @@ void job_t::continue_job(bool reclaim_foreground_pgrp, bool send_sigcont) {
} }
} }
void proc_sanity_check() { void proc_sanity_check(const parser_t &parser) {
const job_t *fg_job = NULL; const job_t *fg_job = NULL;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (!j->is_constructed()) continue; if (!j->is_constructed()) continue;
// More than one foreground job? // More than one foreground job?
@ -979,12 +958,13 @@ void proc_pop_interactive() {
void proc_wait_any(parser_t &parser) { void proc_wait_any(parser_t &parser) {
ASSERT_IS_MAIN_THREAD(); ASSERT_IS_MAIN_THREAD();
process_mark_finished_children(true /* block_ok */); process_mark_finished_children(parser, true /* block_ok */);
process_clean_after_marking(parser, is_interactive); process_clean_after_marking(parser, is_interactive);
} }
void hup_background_jobs() { void hup_background_jobs(const parser_t &parser) {
for (const auto &j : jobs()) { // TODO: we should probably hup all jobs across all parsers here.
for (const auto &j : parser.jobs()) {
// Make sure we don't try to SIGHUP the calling builtin // Make sure we don't try to SIGHUP the calling builtin
if (j->pgid == INVALID_PID || !j->get_flag(job_flag_t::JOB_CONTROL)) { if (j->pgid == INVALID_PID || !j->get_flag(job_flag_t::JOB_CONTROL)) {
continue; continue;

View file

@ -153,6 +153,7 @@ class internal_proc_t {
/// ///
/// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is /// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is
/// the name of the shellscript function. /// the name of the shellscript function.
class parser_t;
class process_t { class process_t {
private: private:
null_terminated_array_t<wchar_t> argv_array; null_terminated_array_t<wchar_t> argv_array;
@ -406,7 +407,6 @@ class job_t {
/// \return whether this job and its parent chain are fully constructed. /// \return whether this job and its parent chain are fully constructed.
bool job_chain_is_fully_constructed() const; 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 /// 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 /// saved terminal modes and send the process group a SIGCONT signal to wake it up before we
/// block. /// block.
@ -414,10 +414,7 @@ class job_t {
/// \param reclaim_foreground_pgrp whether, when the job finishes or stops, to reclaim the /// \param reclaim_foreground_pgrp whether, when the job finishes or stops, to reclaim the
/// foreground pgrp (via tcsetpgrp). \param send_sigcont Whether SIGCONT should be sent to the /// foreground pgrp (via tcsetpgrp). \param send_sigcont Whether SIGCONT should be sent to the
/// job if it is in the foreground. /// job if it is in the foreground.
void continue_job(bool reclaim_foreground_pgrp, bool send_sigcont); void continue_job(parser_t &parser, bool reclaim_foreground_pgrp, bool send_sigcont);
/// Promotes the job to the front of the job list.
void promote();
/// Send the specified signal to all processes in this job. /// Send the specified signal to all processes in this job.
/// \return true on success, false on failure. /// \return true on success, false on failure.
@ -459,11 +456,6 @@ extern int is_event;
// List of jobs. // List of jobs.
typedef std::deque<shared_ptr<job_t>> job_list_t; typedef std::deque<shared_ptr<job_t>> job_list_t;
bool job_list_is_empty(void);
/// A helper function to more easily access the job list
job_list_t &jobs();
/// The current job control mode. /// The current job control mode.
/// ///
/// Must be one of job_control_t::all, job_control_t::interactive and job_control_t::none. /// Must be one of job_control_t::all, job_control_t::interactive and job_control_t::none.
@ -497,11 +489,11 @@ unsigned long proc_get_jiffies(process_t *p);
/// Update process time usage for all processes by calling the proc_get_jiffies function for every /// Update process time usage for all processes by calling the proc_get_jiffies function for every
/// process of every job. /// process of every job.
void proc_update_jiffies(); void proc_update_jiffies(parser_t &parser);
/// Perform a set of simple sanity checks on the job list. This includes making sure that only one /// Perform a set of simple sanity checks on the job list. This includes making sure that only one
/// job is in the foreground, that every process is in a valid state, etc. /// job is in the foreground, that every process is in a valid state, etc.
void proc_sanity_check(); void proc_sanity_check(const parser_t &parser);
/// Create a process/job exit event notification. /// Create a process/job exit event notification.
event_t proc_create_event(const wchar_t *msg, event_type_t type, pid_t pid, int status); event_t proc_create_event(const wchar_t *msg, event_type_t type, pid_t pid, int status);
@ -509,9 +501,6 @@ event_t proc_create_event(const wchar_t *msg, event_type_t type, pid_t pid, int
/// Initializations. /// Initializations.
void proc_init(); void proc_init();
/// Clean up before exiting.
void proc_destroy();
/// Set new value for is_interactive flag, saving previous value. If needed, update signal handlers. /// Set new value for is_interactive flag, saving previous value. If needed, update signal handlers.
void proc_push_interactive(int value); void proc_push_interactive(int value);
@ -528,7 +517,7 @@ void set_is_within_fish_initialization(bool flag);
bool is_within_fish_initialization(); bool is_within_fish_initialization();
/// Terminate all background jobs /// Terminate all background jobs
void hup_background_jobs(); void hup_background_jobs(const parser_t &parser);
/// Give ownership of the terminal to the specified job. /// Give ownership of the terminal to the specified job.
/// ///

View file

@ -1972,7 +1972,7 @@ void reader_run_command(parser_t &parser, const wcstring &cmd) {
parser.vars().set_one(L"_", ENV_GLOBAL, program_name); parser.vars().set_one(L"_", ENV_GLOBAL, program_name);
if (have_proc_stat) { if (have_proc_stat) {
proc_update_jiffies(); proc_update_jiffies(parser);
} }
} }
@ -2190,11 +2190,11 @@ void reader_import_history_if_necessary() {
bool shell_is_exiting() { return should_exit(); } bool shell_is_exiting() { return should_exit(); }
void reader_bg_job_warning() { void reader_bg_job_warning(const parser_t &parser) {
std::fputws(_(L"There are still jobs active:\n"), stdout); std::fputws(_(L"There are still jobs active:\n"), stdout);
std::fputws(_(L"\n PID Command\n"), stdout); std::fputws(_(L"\n PID Command\n"), stdout);
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (!j->is_completed()) { if (!j->is_completed()) {
std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr()); std::fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr());
} }
@ -2206,9 +2206,8 @@ void reader_bg_job_warning() {
/// This function is called when the main loop notices that end_loop has been set while in /// This function is called when the main loop notices that end_loop has been set while in
/// interactive mode. It checks if it is ok to exit. /// interactive mode. It checks if it is ok to exit.
static void handle_end_loop() { static void handle_end_loop(const parser_t &parser) {
if (!reader_exit_forced()) { if (!reader_exit_forced()) {
const parser_t &parser = parser_t::principal_parser();
for (size_t i = 0; i < parser.block_count(); i++) { for (size_t i = 0; i < parser.block_count(); i++) {
if (parser.block_at_index(i)->type() == BREAKPOINT) { if (parser.block_at_index(i)->type() == BREAKPOINT) {
// We're executing within a breakpoint so we do not want to terminate the shell and // We're executing within a breakpoint so we do not want to terminate the shell and
@ -2218,7 +2217,7 @@ static void handle_end_loop() {
} }
bool bg_jobs = false; bool bg_jobs = false;
for (const auto &j : jobs()) { for (const auto &j : parser.jobs()) {
if (!j->is_completed()) { if (!j->is_completed()) {
bg_jobs = true; bg_jobs = true;
break; break;
@ -2227,7 +2226,7 @@ static void handle_end_loop() {
reader_data_t *data = current_data(); reader_data_t *data = current_data();
if (!data->prev_end_loop && bg_jobs) { if (!data->prev_end_loop && bg_jobs) {
reader_bg_job_warning(); reader_bg_job_warning(parser);
reader_set_end_loop(false); reader_set_end_loop(false);
data->prev_end_loop = 1; data->prev_end_loop = 1;
return; return;
@ -2235,7 +2234,7 @@ static void handle_end_loop() {
} }
// Kill remaining jobs before exiting. // Kill remaining jobs before exiting.
hup_background_jobs(); hup_background_jobs(parser);
} }
static bool selection_is_at_top() { static bool selection_is_at_top() {
@ -2269,7 +2268,7 @@ static int read_i() {
reader_data_t *data = current_data(); reader_data_t *data = current_data();
data->prev_end_loop = 0; data->prev_end_loop = 0;
while (!shell_is_exiting() && (!sanity_check())) { while (!shell_is_exiting()) {
event_fire_generic(L"fish_prompt"); event_fire_generic(L"fish_prompt");
run_count++; run_count++;
@ -2292,7 +2291,7 @@ static int read_i() {
maybe_t<wcstring> tmp = reader_readline(0); maybe_t<wcstring> tmp = reader_readline(0);
if (shell_is_exiting()) { if (shell_is_exiting()) {
handle_end_loop(); handle_end_loop(parser);
} else if (tmp) { } else if (tmp) {
const wcstring command = tmp.acquire(); const wcstring command = tmp.acquire();
data->update_buff_pos(&data->command_line, 0); data->update_buff_pos(&data->command_line, 0);
@ -2307,7 +2306,7 @@ static int read_i() {
data->history->resolve_pending(); data->history->resolve_pending();
} }
if (shell_is_exiting()) { if (shell_is_exiting()) {
handle_end_loop(); handle_end_loop(parser);
} else { } else {
data->prev_end_loop = 0; data->prev_end_loop = 0;
} }

View file

@ -232,7 +232,7 @@ wcstring completion_apply_to_command_line(const wcstring &val_str, complete_flag
bool append_only); bool append_only);
/// Print warning with list of backgrounded jobs /// Print warning with list of backgrounded jobs
void reader_bg_job_warning(); void reader_bg_job_warning(const parser_t &parser);
/// Return the current interactive reads loop count. Useful for determining how many commands have /// Return the current interactive reads loop count. Useful for determining how many commands have
/// been executed between invocations of code. /// been executed between invocations of code.

View file

@ -20,12 +20,6 @@ void sanity_lose() {
insane = true; insane = true;
} }
bool sanity_check() {
if (!insane) reader_sanity_check();
if (!insane) proc_sanity_check();
return insane;
}
void validate_pointer(const void *ptr, const wchar_t *err, int null_ok) { void validate_pointer(const void *ptr, const wchar_t *err, int null_ok) {
// Test if the pointer data crosses a segment boundary. // Test if the pointer data crosses a segment boundary.
if ((0x00000003l & (intptr_t)ptr) != 0) { if ((0x00000003l & (intptr_t)ptr) != 0) {

View file

@ -5,9 +5,6 @@
/// Call this function to tell the program it is not in a sane state. /// Call this function to tell the program it is not in a sane state.
void sanity_lose(); void sanity_lose();
/// Perform sanity checks, return 1 if program is in a sane state 0 otherwise.
bool sanity_check();
/// Try and determine if ptr is a valid pointer. If not, loose sanity. /// Try and determine if ptr is a valid pointer. If not, loose sanity.
/// ///
/// \param ptr The pointer to validate /// \param ptr The pointer to validate