mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-14 17:07:44 +00:00
Clean up job flags, status helpers, and instance helper methods
* Convert JOB_* enums to scoped enums * Convert standalone job_is_* functions to member functions * Convert standalone job_{promote, signal, continue} to member functions * Convert standolen job_get{,_from_pid} to `job_t` static functions * Reduce usage of JOB_* enums outside of proc.cpp by using new `job_t::is_foo()` const helper methods instead. This patch is only a refactor and should not change any functionality or behavior (both observed and unobserved).
This commit is contained in:
parent
e753581df7
commit
f9118d964e
14 changed files with 196 additions and 191 deletions
|
@ -18,7 +18,7 @@
|
|||
/// Helper function for builtin_bg().
|
||||
static int send_to_bg(parser_t &parser, io_streams_t &streams, job_t *j) {
|
||||
assert(j != NULL);
|
||||
if (!j->get_flag(JOB_CONTROL)) {
|
||||
if (!j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
streams.err.append_format(
|
||||
_(L"%ls: Can't put job %d, '%ls' to background because it is not under job control\n"),
|
||||
L"bg", j->job_id, j->command_wcstr());
|
||||
|
@ -28,9 +28,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,
|
||||
j->command_wcstr());
|
||||
job_promote(j);
|
||||
j->set_flag(JOB_FOREGROUND, false);
|
||||
job_continue(j, job_is_stopped(j));
|
||||
j->promote();
|
||||
j->set_flag(job_flag_t::FOREGROUND, false);
|
||||
j->continue_job(j->is_stopped());
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
job_t *j;
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (job_is_stopped(j) && j->get_flag(JOB_CONTROL) && (!job_is_completed(j))) {
|
||||
if (j->is_stopped() && j->get_flag(job_flag_t::JOB_CONTROL) && (!j->is_completed())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ int builtin_bg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
// Background all existing jobs that match the pids.
|
||||
// Non-existent jobs aren't an error, but information about them is useful.
|
||||
for (auto p : pids) {
|
||||
if (job_t *j = job_get_from_pid(p)) {
|
||||
if (job_t *j = job_t::from_pid(p)) {
|
||||
retval |= send_to_bg(parser, streams, j);
|
||||
} else {
|
||||
streams.err.append_format(_(L"%ls: Could not find job '%d'\n"), cmd, p);
|
||||
|
|
|
@ -24,7 +24,7 @@ static int disown_job(const wchar_t *cmd, parser_t &parser, io_streams_t &stream
|
|||
}
|
||||
|
||||
// Stopped disowned jobs must be manually signaled; explain how to do so.
|
||||
if (job_is_stopped(j)) {
|
||||
if (j->is_stopped()) {
|
||||
killpg(j->pgid, SIGCONT);
|
||||
const wchar_t *fmt =
|
||||
_(L"%ls: job %d ('%ls') was stopped and has been signalled to continue.\n");
|
||||
|
@ -58,7 +58,7 @@ int builtin_disown(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
// Even jobs that aren't under job control can be disowned!
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (j->get_flag(JOB_CONSTRUCTED) && (!job_is_completed(j))) {
|
||||
if (j->is_constructed() && (!j->is_completed())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
// the foreground.
|
||||
job_iterator_t jobs;
|
||||
while ((j = jobs.next())) {
|
||||
if (j->get_flag(JOB_CONSTRUCTED) && (!job_is_completed(j)) &&
|
||||
((job_is_stopped(j) || (!j->get_flag(JOB_FOREGROUND))) &&
|
||||
j->get_flag(JOB_CONTROL))) {
|
||||
if (j->is_constructed() && (!j->is_completed()) &&
|
||||
((j->is_stopped() || (!j->is_foreground())) &&
|
||||
j->get_flag(job_flag_t::JOB_CONTROL))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
|
||||
pid = fish_wcstoi(argv[optind]);
|
||||
if (!(errno || pid < 0)) {
|
||||
j = job_get_from_pid(pid);
|
||||
j = job_t::from_pid(pid);
|
||||
if (j) found_job = 1;
|
||||
}
|
||||
|
||||
|
@ -76,11 +76,11 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
streams.err.append_format(BUILTIN_ERR_NOT_NUMBER, cmd, argv[optind]);
|
||||
builtin_print_help(parser, streams, cmd, streams.err);
|
||||
} else {
|
||||
j = job_get_from_pid(pid);
|
||||
if (!j || !j->get_flag(JOB_CONSTRUCTED) || job_is_completed(j)) {
|
||||
j = job_t::from_pid(pid);
|
||||
if (!j || !j->is_constructed() || j->is_completed()) {
|
||||
streams.err.append_format(_(L"%ls: No suitable job: %d\n"), cmd, pid);
|
||||
j = 0;
|
||||
} else if (!j->get_flag(JOB_CONTROL)) {
|
||||
} else if (!j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
streams.err.append_format(_(L"%ls: Can't put job %d, '%ls' to foreground because "
|
||||
L"it is not under job control\n"),
|
||||
cmd, pid, j->command_wcstr());
|
||||
|
@ -106,9 +106,9 @@ int builtin_fg(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
if (!ft.empty()) env_set_one(L"_", ENV_EXPORT, ft);
|
||||
reader_write_title(j->command());
|
||||
|
||||
job_promote(j);
|
||||
j->set_flag(JOB_FOREGROUND, true);
|
||||
j->promote();
|
||||
j->set_flag(job_flag_t::FOREGROUND, true);
|
||||
|
||||
job_continue(j, job_is_stopped(j));
|
||||
j->continue_job(j->is_stopped());
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ static wcstring functions_def(const wcstring &name) {
|
|||
break;
|
||||
}
|
||||
case EVENT_JOB_ID: {
|
||||
const job_t *j = job_get(next->param1.job_id);
|
||||
const job_t *j = job_t::from_job_id(next->param1.job_id);
|
||||
if (j) append_format(out, L" --on-job-exit %d", j->pgid);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ static void builtin_jobs_print(const job_t *j, int mode, int header, io_streams_
|
|||
#ifdef HAVE__PROC_SELF_STAT
|
||||
streams.out.append_format(L"%d%%\t", cpu_use(j));
|
||||
#endif
|
||||
streams.out.append(job_is_stopped(j) ? _(L"stopped") : _(L"running"));
|
||||
streams.out.append(j->is_stopped() ? _(L"stopped") : _(L"running"));
|
||||
streams.out.append(L"\t");
|
||||
streams.out.append(j->command_wcstr());
|
||||
streams.out.append(L"\n");
|
||||
|
@ -177,7 +177,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
job_iterator_t jobs;
|
||||
const job_t *j;
|
||||
while ((j = jobs.next())) {
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j)) {
|
||||
if (j->is_constructed() && !j->is_completed()) {
|
||||
builtin_jobs_print(j, mode, !streams.out_is_redirected, streams);
|
||||
return STATUS_CMD_ERROR;
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
streams.err.append_format(_(L"%ls: '%ls' is not a valid job id"), cmd, argv[i]);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
j = job_get(jobId);
|
||||
j = job_t::from_job_id(jobId);
|
||||
}
|
||||
else {
|
||||
int pid = fish_wcstoi(argv[i]);
|
||||
|
@ -205,10 +205,10 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
streams.err.append_format(_(L"%ls: '%ls' is not a valid process id\n"), cmd, argv[i]);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
j = job_get_from_pid(pid);
|
||||
j = job_t::from_pid(pid);
|
||||
}
|
||||
|
||||
if (j && !job_is_completed(j) && (j->flags & JOB_CONSTRUCTED)) {
|
||||
if (j && !j->is_completed() && j->is_constructed()) {
|
||||
builtin_jobs_print(j, mode, false, streams);
|
||||
found = 1;
|
||||
} else {
|
||||
|
@ -221,7 +221,7 @@ int builtin_jobs(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
|
|||
const job_t *j;
|
||||
while ((j = jobs.next())) {
|
||||
// Ignore unconstructed jobs, i.e. ourself.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j)) {
|
||||
if (j->is_constructed() && !j->is_completed()) {
|
||||
builtin_jobs_print(j, mode, !found && !streams.out_is_redirected, streams);
|
||||
found = 1;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ static bool all_jobs_finished() {
|
|||
while (job_t *j = jobs.next()) {
|
||||
// If any job is not completed, return false.
|
||||
// If there are stopped jobs, they are ignored.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) && !job_is_stopped(j)) {
|
||||
if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -54,11 +54,11 @@ static bool any_jobs_finished(size_t jobs_len) {
|
|||
}
|
||||
while (job_t *j = jobs.next()) {
|
||||
// If any job is completed, return true.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && (job_is_completed(j) || job_is_stopped(j))) {
|
||||
if (j->is_constructed() && (j->is_completed() || j->is_stopped())) {
|
||||
return true;
|
||||
}
|
||||
// Check for jobs running exist or not.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_stopped(j)) {
|
||||
if (j->is_constructed() && !j->is_stopped()) {
|
||||
no_jobs_running = false;
|
||||
}
|
||||
}
|
||||
|
@ -83,10 +83,10 @@ static int wait_for_backgrounds(bool any_flag) {
|
|||
|
||||
static bool all_specified_jobs_finished(const std::vector<job_id_t> &ids) {
|
||||
for (auto id : ids) {
|
||||
if (job_t *j = job_get(id)) {
|
||||
if (job_t *j = job_t::from_job_id(id)) {
|
||||
// If any specified job is not completed, return false.
|
||||
// If there are stopped jobs, they are ignored.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && !job_is_completed(j) && !job_is_stopped(j)) {
|
||||
if (j->is_constructed() && !j->is_completed() && !j->is_stopped()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -96,9 +96,9 @@ static bool all_specified_jobs_finished(const std::vector<job_id_t> &ids) {
|
|||
|
||||
static bool any_specified_jobs_finished(const std::vector<job_id_t> &ids) {
|
||||
for (auto id : ids) {
|
||||
if (job_t *j = job_get(id)) {
|
||||
if (job_t *j = job_t::from_job_id(id)) {
|
||||
// If any specified job is completed, return true.
|
||||
if ((j->flags & JOB_CONSTRUCTED) && (job_is_completed(j) || job_is_stopped(j))) {
|
||||
if (j->is_constructed() && (j->is_completed() || j->is_stopped())) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
|
26
src/enum_set.h
Normal file
26
src/enum_set.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
|
||||
template <typename T>
|
||||
class enum_set_t {
|
||||
private:
|
||||
using base_type_t = typename std::underlying_type<T>::type;
|
||||
std::bitset<8 * sizeof(base_type_t)> bitmask{0};
|
||||
static int index_of(T t) { return static_cast<base_type_t>(t); }
|
||||
|
||||
public:
|
||||
bool get(T t) const { return bitmask.test(index_of(t)); }
|
||||
|
||||
void set(T t, bool v) {
|
||||
if (v) {
|
||||
bitmask.set(index_of(t));
|
||||
} else {
|
||||
bitmask.reset(index_of(t));
|
||||
}
|
||||
}
|
||||
|
||||
void set(T t) { bitmask.set(index_of(t)); }
|
||||
|
||||
void clear(T t) { bitmask.reset(index_of(t)); }
|
||||
};
|
|
@ -129,7 +129,7 @@ wcstring event_get_desc(const event_t &e) {
|
|||
result = format_string(_(L"exit handler for process %d"), e.param1.pid);
|
||||
} else {
|
||||
// In events, PGIDs are stored as negative PIDs
|
||||
job_t *j = job_get_from_pid(-e.param1.pid);
|
||||
job_t *j = job_t::from_pid(-e.param1.pid);
|
||||
if (j)
|
||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id,
|
||||
j->command_wcstr());
|
||||
|
@ -140,7 +140,7 @@ wcstring event_get_desc(const event_t &e) {
|
|||
break;
|
||||
}
|
||||
case EVENT_JOB_ID: {
|
||||
job_t *j = job_get(e.param1.job_id);
|
||||
job_t *j = job_t::from_job_id(e.param1.job_id);
|
||||
if (j) {
|
||||
result = format_string(_(L"exit handler for job %d, '%ls'"), j->job_id,
|
||||
j->command_wcstr());
|
||||
|
@ -211,7 +211,7 @@ static wcstring event_desc_compact(const event_t &event) {
|
|||
res = format_string(L"EVENT_EXIT(pid %d)", event.param1.pid);
|
||||
} else {
|
||||
// In events, PGIDs are stored as negative PIDs
|
||||
job_t *j = job_get_from_pid(-event.param1.pid);
|
||||
job_t *j = job_t::from_pid(-event.param1.pid);
|
||||
if (j)
|
||||
res = format_string(L"EVENT_EXIT(jobid %d: \"%ls\")", j->job_id,
|
||||
j->command_wcstr());
|
||||
|
@ -221,7 +221,7 @@ static wcstring event_desc_compact(const event_t &event) {
|
|||
break;
|
||||
}
|
||||
case EVENT_JOB_ID: {
|
||||
job_t *j = job_get(event.param1.job_id);
|
||||
job_t *j = job_t::from_job_id(event.param1.job_id);
|
||||
if (j)
|
||||
res =
|
||||
format_string(L"EVENT_JOB_ID(job %d: \"%ls\")", j->job_id, j->command_wcstr());
|
||||
|
|
32
src/exec.cpp
32
src/exec.cpp
|
@ -336,10 +336,10 @@ void internal_exec_helper(parser_t &parser, parsed_source_ref_t parsed_source, t
|
|||
// foreground process group, we don't use posix_spawn if we're going to foreground the process. (If
|
||||
// we use fork(), we can call tcsetpgrp after the fork, before the exec, and avoid the race).
|
||||
static bool can_use_posix_spawn_for_job(const job_t *job, const process_t *process) {
|
||||
if (job->get_flag(JOB_CONTROL)) { //!OCLINT(collapsible if statements)
|
||||
if (job->get_flag(job_flag_t::JOB_CONTROL)) { //!OCLINT(collapsible if statements)
|
||||
// We are going to use job control; therefore when we launch this job it will get its own
|
||||
// process group ID. But will it be foregrounded?
|
||||
if (job->get_flag(JOB_TERMINAL) && job->get_flag(JOB_FOREGROUND)) {
|
||||
if (job->get_flag(job_flag_t::TERMINAL) && job->is_foreground()) {
|
||||
// It will be foregrounded, so we will call tcsetpgrp(), therefore do not use
|
||||
// posix_spawn.
|
||||
return false;
|
||||
|
@ -380,7 +380,7 @@ void internal_exec(job_t *j, const io_chain_t &&all_ios) {
|
|||
// launch_process _never_ returns.
|
||||
launch_process_nofork(j->processes.front().get());
|
||||
} else {
|
||||
j->set_flag(JOB_CONSTRUCTED, true);
|
||||
j->set_flag(job_flag_t::CONSTRUCTED, true);
|
||||
j->processes.front()->completed = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ static void on_process_created(job_t *j, pid_t child_pid) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (j->get_flag(JOB_CONTROL)) {
|
||||
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
j->pgid = child_pid;
|
||||
} else {
|
||||
j->pgid = getpgrp();
|
||||
|
@ -524,15 +524,15 @@ static bool exec_internal_builtin_proc(parser_t &parser, job_t *j, process_t *p,
|
|||
// way, the builtin does not need to know what job it is part of. It could
|
||||
// probably figure that out by walking the job list, but it seems more robust to
|
||||
// make exec handle things.
|
||||
const int fg = j->get_flag(JOB_FOREGROUND);
|
||||
j->set_flag(JOB_FOREGROUND, false);
|
||||
const int fg = j->is_foreground();
|
||||
j->set_flag(job_flag_t::FOREGROUND, false);
|
||||
|
||||
// Note this call may block for a long time, while the builtin performs I/O.
|
||||
p->status = builtin_run(parser, j->pgid, p->get_argv(), streams);
|
||||
|
||||
// Restore the fg flag, which is temporarily set to false during builtin
|
||||
// execution so as not to confuse some job-handling builtins.
|
||||
j->set_flag(JOB_FOREGROUND, fg);
|
||||
j->set_flag(job_flag_t::FOREGROUND, fg);
|
||||
|
||||
// If stdin has been redirected, close the redirection stream.
|
||||
if (close_stdin) {
|
||||
|
@ -613,7 +613,7 @@ static bool handle_builtin_output(job_t *j, process_t *p, io_chain_t *io_chain,
|
|||
debug(4, L"Set status of job %d (%ls) to %d using short circuit", j->job_id, j->preview().c_str(), p->status);
|
||||
|
||||
int status = p->status;
|
||||
proc_set_last_status(j->get_flag(JOB_NEGATE) ? (!status) : status);
|
||||
proc_set_last_status(j->get_flag(job_flag_t::NEGATE) ? (!status) : status);
|
||||
}
|
||||
} else {
|
||||
// Ok, unfortunately, we have to do a real fork. Bummer. We work hard to make
|
||||
|
@ -719,7 +719,7 @@ static bool exec_external_command(job_t *j, process_t *p, const io_chain_t &proc
|
|||
// child group has been set. See discussion here:
|
||||
// https://github.com/Microsoft/WSL/issues/2997 And confirmation that this persists
|
||||
// past glibc 2.24+ here: https://github.com/fish-shell/fish-shell/issues/4715
|
||||
if (j->get_flag(JOB_CONTROL) && getpgid(p->pid) != j->pgid) {
|
||||
if (j->get_flag(job_flag_t::JOB_CONTROL) && getpgid(p->pid) != j->pgid) {
|
||||
set_child_group(j, p->pid);
|
||||
}
|
||||
#else
|
||||
|
@ -803,7 +803,7 @@ static bool exec_block_or_func_process(parser_t &parser, job_t *j, process_t *p,
|
|||
// No buffer, so we exit directly. This means we have to manually set the exit
|
||||
// status.
|
||||
if (p->is_last_in_job) {
|
||||
proc_set_last_status(j->get_flag(JOB_NEGATE) ? (!status) : status);
|
||||
proc_set_last_status(j->get_flag(job_flag_t::NEGATE) ? (!status) : status);
|
||||
}
|
||||
p->completed = 1;
|
||||
return true;
|
||||
|
@ -828,7 +828,7 @@ static bool exec_block_or_func_process(parser_t &parser, job_t *j, process_t *p,
|
|||
}
|
||||
} else {
|
||||
if (p->is_last_in_job) {
|
||||
proc_set_last_status(j->get_flag(JOB_NEGATE) ? (!status) : status);
|
||||
proc_set_last_status(j->get_flag(job_flag_t::NEGATE) ? (!status) : status);
|
||||
}
|
||||
p->completed = 1;
|
||||
}
|
||||
|
@ -1038,7 +1038,7 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||
// and https://github.com/Microsoft/WSL/issues/2786.
|
||||
process_t keepalive;
|
||||
bool needs_keepalive = false;
|
||||
if (is_windows_subsystem_for_linux() && j->get_flag(JOB_CONTROL) && !exec_error) {
|
||||
if (is_windows_subsystem_for_linux() && j->get_flag(job_flag_t::JOB_CONTROL) && !exec_error) {
|
||||
for (const process_ptr_t &p : j->processes) {
|
||||
// but not if it's the only process
|
||||
if (j->processes.front()->type == EXTERNAL && !p->is_first_in_job) {
|
||||
|
@ -1098,18 +1098,18 @@ void exec_job(parser_t &parser, job_t *j) {
|
|||
kill(keepalive.pid, SIGKILL);
|
||||
}
|
||||
|
||||
j->set_flag(JOB_CONSTRUCTED, true);
|
||||
if (!j->get_flag(JOB_FOREGROUND)) {
|
||||
j->set_flag(job_flag_t::CONSTRUCTED, true);
|
||||
if (!j->is_foreground()) {
|
||||
proc_last_bg_pid = j->pgid;
|
||||
env_set(L"last_pid", ENV_GLOBAL, { to_string(proc_last_bg_pid) });
|
||||
}
|
||||
|
||||
if (!exec_error) {
|
||||
job_continue(j, false);
|
||||
j->continue_job(false);
|
||||
} else {
|
||||
// Mark the errored job as not in the foreground. I can't fully justify whether this is the
|
||||
// right place, but it prevents sanity_lose from complaining.
|
||||
j->set_flag(JOB_FOREGROUND, false);
|
||||
j->set_flag(job_flag_t::FOREGROUND, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -772,7 +772,7 @@ parse_execution_result_t parse_execution_context_t::populate_plain_process(
|
|||
bool have_bg = false;
|
||||
const job_t *bg = nullptr;
|
||||
while ((bg = jobs.next())) {
|
||||
if (!job_is_completed(bg)) {
|
||||
if (!bg->is_completed()) {
|
||||
have_bg = true;
|
||||
break;
|
||||
}
|
||||
|
@ -975,7 +975,7 @@ bool parse_execution_context_t::determine_io_chain(tnode_t<g::arguments_or_redir
|
|||
|
||||
parse_execution_result_t parse_execution_context_t::populate_not_process(
|
||||
job_t *job, process_t *proc, tnode_t<g::not_statement> not_statement) {
|
||||
job->set_flag(JOB_NEGATE, !job->get_flag(JOB_NEGATE));
|
||||
job->set_flag(job_flag_t::NEGATE, !job->get_flag(job_flag_t::NEGATE));
|
||||
return this->populate_job_process(job, proc,
|
||||
not_statement.require_get_child<g::statement, 1>());
|
||||
}
|
||||
|
@ -1184,15 +1184,15 @@ parse_execution_result_t parse_execution_context_t::run_1_job(tnode_t<g::job> jo
|
|||
|
||||
shared_ptr<job_t> job = std::make_shared<job_t>(acquire_job_id(), block_io);
|
||||
job->tmodes = tmodes;
|
||||
job->set_flag(JOB_CONTROL,
|
||||
job->set_flag(job_flag_t::JOB_CONTROL,
|
||||
(job_control_mode == JOB_CONTROL_ALL) ||
|
||||
((job_control_mode == JOB_CONTROL_INTERACTIVE) && shell_is_interactive()));
|
||||
|
||||
job->set_flag(JOB_FOREGROUND, !job_node_is_background(job_node));
|
||||
job->set_flag(job_flag_t::FOREGROUND, !job_node_is_background(job_node));
|
||||
|
||||
job->set_flag(JOB_TERMINAL, job->get_flag(JOB_CONTROL) && !is_event);
|
||||
job->set_flag(job_flag_t::TERMINAL, job->get_flag(job_flag_t::JOB_CONTROL) && !is_event);
|
||||
|
||||
job->set_flag(JOB_SKIP_NOTIFICATION,
|
||||
job->set_flag(job_flag_t::SKIP_NOTIFICATION,
|
||||
is_subshell || is_block || is_event || !shell_is_interactive());
|
||||
|
||||
// Tell the current block what its job is. This has to happen before we populate it (#1394).
|
||||
|
|
|
@ -64,7 +64,7 @@ static void debug_safe_int(int level, const char *format, int val) {
|
|||
/// Returns true on sucess, false on failiure.
|
||||
bool child_set_group(job_t *j, process_t *p) {
|
||||
bool retval = true;
|
||||
if (j->get_flag(JOB_CONTROL)) {
|
||||
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
if (j->pgid == INVALID_PID) {
|
||||
j->pgid = p->pid;
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ bool child_set_group(job_t *j, process_t *p) {
|
|||
/// group in the case of JOB_CONTROL, and we can give the new process group control of the terminal
|
||||
/// if it's to run in the foreground.
|
||||
bool set_child_group(job_t *j, pid_t child_pid) {
|
||||
if (j->get_flag(JOB_CONTROL)) {
|
||||
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
assert (j->pgid != INVALID_PID
|
||||
&& "set_child_group called with JOB_CONTROL before job pgid determined!");
|
||||
|
||||
|
@ -135,7 +135,7 @@ bool set_child_group(job_t *j, pid_t child_pid) {
|
|||
bool maybe_assign_terminal(const job_t *j) {
|
||||
assert(j->pgid > 1 && "maybe_assign_terminal() called on job with invalid pgid!");
|
||||
|
||||
if (j->get_flag(JOB_TERMINAL) && j->get_flag(JOB_FOREGROUND)) { //!OCLINT(early exit)
|
||||
if (j->get_flag(job_flag_t::TERMINAL) && j->is_foreground()) { //!OCLINT(early exit)
|
||||
if (tcgetpgrp(STDIN_FILENO) == j->pgid) {
|
||||
// We've already assigned the process group control of the terminal when the first
|
||||
// process in the job was started. There's no need to do so again, and on some platforms
|
||||
|
@ -338,7 +338,7 @@ bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr,
|
|||
|
||||
bool should_set_process_group_id = false;
|
||||
int desired_process_group_id = 0;
|
||||
if (j->get_flag(JOB_CONTROL)) {
|
||||
if (j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
should_set_process_group_id = true;
|
||||
|
||||
// set_child_group puts each job into its own process group
|
||||
|
|
152
src/proc.cpp
152
src/proc.cpp
|
@ -77,22 +77,6 @@ job_iterator_t::job_iterator_t() : job_list(&parser_t::principal_parser().job_li
|
|||
|
||||
size_t job_iterator_t::count() const { return this->job_list->size(); }
|
||||
|
||||
#if 0
|
||||
// This isn't used so the lint tools were complaining about its presence. I'm keeping it in the
|
||||
// source because it could be useful for debugging. However, it would probably be better to add a
|
||||
// verbose or debug option to the builtin `jobs` command.
|
||||
void print_jobs(void)
|
||||
{
|
||||
job_iterator_t jobs;
|
||||
job_t *j;
|
||||
while (j = jobs.next()) {
|
||||
fwprintf(stdout, L"%p -> %ls -> (foreground %d, complete %d, stopped %d, constructed %d)\n",
|
||||
j, j->command_wcstr(), j->get_flag(JOB_FOREGROUND), job_is_completed(j),
|
||||
job_is_stopped(j), j->get_flag(JOB_CONSTRUCTED));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_interactive_session = false;
|
||||
bool is_subshell = false;
|
||||
bool is_block = false;
|
||||
|
@ -140,9 +124,9 @@ static int job_remove(job_t *j) {
|
|||
return parser_t::principal_parser().job_remove(j);
|
||||
}
|
||||
|
||||
void job_promote(job_t *job) {
|
||||
void job_t::promote() {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
parser_t::principal_parser().job_promote(job);
|
||||
parser_t::principal_parser().job_promote(this);
|
||||
}
|
||||
|
||||
void proc_destroy() {
|
||||
|
@ -199,61 +183,49 @@ void release_job_id(job_id_t jid) {
|
|||
consumed_job_ids->resize(count + 1);
|
||||
}
|
||||
|
||||
job_t *job_get(job_id_t id) {
|
||||
job_t *job_t::from_job_id(job_id_t id) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
return parser_t::principal_parser().job_get(id);
|
||||
}
|
||||
|
||||
job_t *job_get_from_pid(int pid) {
|
||||
job_t *job_t::from_pid(pid_t pid) {
|
||||
ASSERT_IS_MAIN_THREAD();
|
||||
return parser_t::principal_parser().job_get_from_pid(pid);
|
||||
}
|
||||
|
||||
/// Return true if all processes in the job have stopped or completed.
|
||||
///
|
||||
/// \param j the job to test
|
||||
int job_is_stopped(const job_t *j) {
|
||||
for (const process_ptr_t &p : j->processes) {
|
||||
bool job_t::is_stopped() const {
|
||||
for (const process_ptr_t &p : processes) {
|
||||
if (!p->completed && !p->stopped) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Return true if the last processes in the job has completed.
|
||||
///
|
||||
/// \param j the job to test
|
||||
bool job_is_completed(const job_t *j) {
|
||||
assert(!j->processes.empty());
|
||||
bool result = true;
|
||||
for (const process_ptr_t &p : j->processes) {
|
||||
bool job_t::is_completed() const {
|
||||
assert(!processes.empty());
|
||||
for (const process_ptr_t &p : processes) {
|
||||
if (!p->completed) {
|
||||
result = false;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
void job_t::set_flag(job_flag_t flag, bool set) {
|
||||
if (set) {
|
||||
this->flags |= flag;
|
||||
} else {
|
||||
this->flags &= ~flag;
|
||||
}
|
||||
}
|
||||
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 & flag) == flag; }
|
||||
bool job_t::get_flag(job_flag_t flag) const { return this->flags.get(flag); }
|
||||
|
||||
int job_signal(job_t *j, int signal) {
|
||||
int job_t::signal(int signal) {
|
||||
pid_t my_pgid = getpgrp();
|
||||
int res = 0;
|
||||
|
||||
if (j->pgid != my_pgid) {
|
||||
res = killpg(j->pgid, signal);
|
||||
if (pgid != my_pgid) {
|
||||
res = killpg(pgid, signal);
|
||||
} else {
|
||||
for (const process_ptr_t &p : j->processes) {
|
||||
for (const process_ptr_t &p : processes) {
|
||||
if (!p->completed && p->pid && kill(p->pid, signal)) {
|
||||
res = -1;
|
||||
break;
|
||||
|
@ -344,7 +316,7 @@ static void handle_child_status(pid_t pid, int status) {
|
|||
process_t::process_t() {}
|
||||
|
||||
job_t::job_t(job_id_t jobid, io_chain_t bio)
|
||||
: block_io(std::move(bio)), pgid(INVALID_PID), tmodes(), job_id(jobid), flags(0) {}
|
||||
: block_io(std::move(bio)), pgid(INVALID_PID), tmodes(), job_id(jobid), flags{} {}
|
||||
|
||||
job_t::~job_t() { release_job_id(job_id); }
|
||||
|
||||
|
@ -382,7 +354,7 @@ static bool process_mark_finished_children(bool block_on_fg) {
|
|||
job_iterator_t jobs;
|
||||
while (auto j = jobs.next()) {
|
||||
// A job can have pgrp INVALID_PID if it consists solely of builtins that perform no IO
|
||||
if (j->pgid == INVALID_PID || !j->get_flag(JOB_CONSTRUCTED)) {
|
||||
if (j->pgid == INVALID_PID || !j->is_constructed()) {
|
||||
// Job has not been fully constructed yet
|
||||
debug(5, "Skipping wait on incomplete job %d (%ls)", j->job_id, j->preview().c_str());
|
||||
continue;
|
||||
|
@ -392,10 +364,11 @@ static bool process_mark_finished_children(bool block_on_fg) {
|
|||
// nature of the process. Default is WNOHANG, but if foreground, constructed, not stopped, *and*
|
||||
// block_on_fg is true, then no WNOHANG (i.e. "HANG").
|
||||
int options = WUNTRACED | WNOHANG;
|
||||
if (j->get_flag(JOB_FOREGROUND) && !job_is_stopped(j) && !job_is_completed(j)) {
|
||||
if (j->is_foreground() && !j->is_stopped() && !j->is_completed()) {
|
||||
assert(job_fg == nullptr && "More than one active, fully-constructed foreground job!");
|
||||
job_fg = j;
|
||||
}
|
||||
|
||||
// We should never block twice in the same go, as `waitpid()' returning could mean one
|
||||
// process completed or many, and there is a race condition when calling `waitpid()` after
|
||||
// the process group exits having reaped all children and terminated the process group and
|
||||
|
@ -408,8 +381,8 @@ static bool process_mark_finished_children(bool block_on_fg) {
|
|||
// never wait/block on fg processes after an error has been encountered to give ourselves
|
||||
// (elsewhere) a chance to handle the fallout from process termination, etc.
|
||||
if (!has_error && block_on_fg && j->pgid != shell_pgid
|
||||
&& j == job_fg && j->get_flag(JOB_CONTROL)) {
|
||||
debug(4, "Waiting on processes from foreground job %d.", j->pgid, shell_pgid);
|
||||
&& j == job_fg && j->get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
debug(4, "Waiting on processes from foreground job %d", job_fg->pgid);
|
||||
options &= ~WNOHANG;
|
||||
}
|
||||
|
||||
|
@ -524,8 +497,8 @@ static int process_clean_after_marking(bool allow_interactive) {
|
|||
|
||||
// If we are reaping only jobs who do not need status messages sent to the console, do not
|
||||
// consider reaping jobs that need status messages.
|
||||
if ((!j->get_flag(JOB_SKIP_NOTIFICATION)) && (!interactive) &&
|
||||
(!j->get_flag(JOB_FOREGROUND))) {
|
||||
if ((!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) && (!interactive) &&
|
||||
(!j->is_foreground())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -550,9 +523,10 @@ static int process_clean_after_marking(bool allow_interactive) {
|
|||
|
||||
// Handle signals other than SIGPIPE.
|
||||
int proc_is_job = (p->is_first_in_job && p->is_last_in_job);
|
||||
if (proc_is_job) j->set_flag(JOB_NOTIFIED, true);
|
||||
if (proc_is_job) j->set_flag(job_flag_t::NOTIFIED, true);
|
||||
// Always report crashes.
|
||||
if (j->get_flag(JOB_SKIP_NOTIFICATION) && !contains(crashsignals,WTERMSIG(p->status))) {
|
||||
if (j->get_flag(job_flag_t::SKIP_NOTIFICATION) &&
|
||||
!contains(crashsignals, WTERMSIG(p->status))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -565,7 +539,7 @@ static int process_clean_after_marking(bool allow_interactive) {
|
|||
// signals. If echoctl is on, then the terminal will have written ^C to the console.
|
||||
// If off, it won't have. We don't echo ^C either way, so as to respect the user's
|
||||
// preference.
|
||||
if (WTERMSIG(p->status) != SIGINT || !j->get_flag(JOB_FOREGROUND)) {
|
||||
if (WTERMSIG(p->status) != SIGINT || !j->is_foreground()) {
|
||||
if (proc_is_job) {
|
||||
// We want to report the job number, unless it's the only job, in which case
|
||||
// we don't need to.
|
||||
|
@ -598,9 +572,9 @@ static int process_clean_after_marking(bool allow_interactive) {
|
|||
|
||||
// If all processes have completed, tell the user the job has completed and delete it from
|
||||
// the active job list.
|
||||
if (job_is_completed(j)) {
|
||||
if (!j->get_flag(JOB_FOREGROUND) && !j->get_flag(JOB_NOTIFIED) &&
|
||||
!j->get_flag(JOB_SKIP_NOTIFICATION)) {
|
||||
if (j->is_completed()) {
|
||||
if (!j->is_foreground() && !j->get_flag(job_flag_t::NOTIFIED) &&
|
||||
!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) {
|
||||
format_job_info(j, JOB_ENDED);
|
||||
found = 1;
|
||||
}
|
||||
|
@ -616,13 +590,13 @@ static int process_clean_after_marking(bool allow_interactive) {
|
|||
proc_fire_event(L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0);
|
||||
|
||||
job_remove(j);
|
||||
} else if (job_is_stopped(j) && !j->get_flag(JOB_NOTIFIED)) {
|
||||
} else if (j->is_stopped() && !j->get_flag(job_flag_t::NOTIFIED)) {
|
||||
// Notify the user about newly stopped jobs.
|
||||
if (!j->get_flag(JOB_SKIP_NOTIFICATION)) {
|
||||
if (!j->get_flag(job_flag_t::SKIP_NOTIFICATION)) {
|
||||
format_job_info(j, JOB_STOPPED);
|
||||
found = 1;
|
||||
}
|
||||
j->set_flag(JOB_NOTIFIED, true);
|
||||
j->set_flag(job_flag_t::NOTIFIED, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -946,35 +920,35 @@ static bool terminal_return_from_job(job_t *j) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void job_continue(job_t *j, bool cont) {
|
||||
void job_t::continue_job(bool cont) {
|
||||
// Put job first in the job list.
|
||||
job_promote(j);
|
||||
j->set_flag(JOB_NOTIFIED, false);
|
||||
promote();
|
||||
set_flag(job_flag_t::NOTIFIED, false);
|
||||
|
||||
CHECK_BLOCK();
|
||||
debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", cont ? L"Continue" : L"Start", j->job_id,
|
||||
j->pgid, j->command_wcstr(), job_is_completed(j) ? L"COMPLETED" : L"UNCOMPLETED",
|
||||
debug(4, L"%ls job %d, gid %d (%ls), %ls, %ls", cont ? L"Continue" : L"Start", job_id, pgid,
|
||||
command_wcstr(), is_completed() ? L"COMPLETED" : L"UNCOMPLETED",
|
||||
is_interactive ? L"INTERACTIVE" : L"NON-INTERACTIVE");
|
||||
|
||||
if (!job_is_completed(j)) {
|
||||
if (j->get_flag(JOB_TERMINAL) && j->get_flag(JOB_FOREGROUND)) {
|
||||
if (!is_completed()) {
|
||||
if (get_flag(job_flag_t::TERMINAL) && is_foreground()) {
|
||||
// Put the job into the foreground. Hack: ensure that stdin is marked as blocking first
|
||||
// (issue #176).
|
||||
make_fd_blocking(STDIN_FILENO);
|
||||
if (!terminal_give_to_job(j, cont)) return;
|
||||
if (!terminal_give_to_job(this, cont)) return;
|
||||
}
|
||||
|
||||
// Send the job a continue signal, if necessary.
|
||||
if (cont) {
|
||||
for (process_ptr_t &p : j->processes) p->stopped = false;
|
||||
for (process_ptr_t &p : processes) p->stopped = false;
|
||||
|
||||
if (j->get_flag(JOB_CONTROL)) {
|
||||
if (killpg(j->pgid, SIGCONT)) {
|
||||
if (get_flag(job_flag_t::JOB_CONTROL)) {
|
||||
if (killpg(pgid, SIGCONT)) {
|
||||
wperror(L"killpg (SIGCONT)");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
for (const process_ptr_t &p : j->processes) {
|
||||
for (const process_ptr_t &p : processes) {
|
||||
if (kill(p->pid, SIGCONT) < 0) {
|
||||
wperror(L"kill (SIGCONT)");
|
||||
return;
|
||||
|
@ -983,16 +957,16 @@ void job_continue(job_t *j, bool cont) {
|
|||
}
|
||||
}
|
||||
|
||||
if (j->get_flag(JOB_FOREGROUND)) {
|
||||
if (is_foreground()) {
|
||||
// Look for finished processes first, to avoid select() if it's already done.
|
||||
process_mark_finished_children(false);
|
||||
|
||||
// Wait for job to report.
|
||||
while (!reader_exit_forced() && !job_is_stopped(j) && !job_is_completed(j)) {
|
||||
switch (select_try(j)) {
|
||||
while (!reader_exit_forced() && !is_stopped() && !is_completed()) {
|
||||
switch (select_try(this)) {
|
||||
case 1: {
|
||||
// debug(1, L"select_try() 1" );
|
||||
read_try(j);
|
||||
read_try(this);
|
||||
process_mark_finished_children(false);
|
||||
break;
|
||||
}
|
||||
|
@ -1022,8 +996,8 @@ void job_continue(job_t *j, bool cont) {
|
|||
}
|
||||
}
|
||||
|
||||
if (j->get_flag(JOB_FOREGROUND)) {
|
||||
if (job_is_completed(j)) {
|
||||
if (is_foreground()) {
|
||||
if (is_completed()) {
|
||||
// It's possible that the job will produce output and exit before we've even read from
|
||||
// it.
|
||||
//
|
||||
|
@ -1031,23 +1005,21 @@ void job_continue(job_t *j, bool cont) {
|
|||
// This is why my prompt colors kept getting screwed up - the builtin echo calls
|
||||
// were sometimes having their output combined with the set_color calls in the wrong
|
||||
// order!
|
||||
read_try(j);
|
||||
read_try(this);
|
||||
|
||||
const std::unique_ptr<process_t> &p = j->processes.back();
|
||||
const std::unique_ptr<process_t> &p = processes.back();
|
||||
|
||||
// Mark process status only if we are in the foreground and the last process in a pipe,
|
||||
// and it is not a short circuited builtin.
|
||||
if ((WIFEXITED(p->status) || WIFSIGNALED(p->status)) && p->pid) {
|
||||
int status = proc_format_status(p->status);
|
||||
// fwprintf(stdout, L"setting status %d for %ls\n", job_get_flag( j, JOB_NEGATE
|
||||
// )?!status:status, j->command);
|
||||
proc_set_last_status(j->get_flag(JOB_NEGATE) ? !status : status);
|
||||
proc_set_last_status(get_flag(job_flag_t::NEGATE) ? !status : status);
|
||||
}
|
||||
}
|
||||
|
||||
// Put the shell back in the foreground.
|
||||
if (j->get_flag(JOB_TERMINAL) && j->get_flag(JOB_FOREGROUND)) {
|
||||
terminal_return_from_job(j);
|
||||
if (get_flag(job_flag_t::TERMINAL) && is_foreground()) {
|
||||
terminal_return_from_job(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1066,10 +1038,10 @@ void proc_sanity_check() {
|
|||
|
||||
job_iterator_t jobs;
|
||||
while (const job_t *j = jobs.next()) {
|
||||
if (!j->get_flag(JOB_CONSTRUCTED)) continue;
|
||||
if (!j->is_constructed()) continue;
|
||||
|
||||
// More than one foreground job?
|
||||
if (j->get_flag(JOB_FOREGROUND) && !(job_is_stopped(j) || job_is_completed(j))) {
|
||||
if (j->is_foreground() && !(j->is_stopped() || j->is_completed())) {
|
||||
if (fg_job) {
|
||||
debug(0, _(L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
|
||||
fg_job->command_wcstr(), j->command_wcstr());
|
||||
|
|
75
src/proc.h
75
src/proc.h
|
@ -16,6 +16,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "common.h"
|
||||
#include "enum_set.h"
|
||||
#include "io.h"
|
||||
#include "parse_tree.h"
|
||||
#include "tnode.h"
|
||||
|
@ -139,23 +140,23 @@ typedef std::unique_ptr<process_t> process_ptr_t;
|
|||
typedef std::vector<process_ptr_t> process_list_t;
|
||||
|
||||
/// Constants for the flag variable in the job struct.
|
||||
enum job_flag_t {
|
||||
enum class job_flag_t {
|
||||
/// Whether the user has been told about stopped job.
|
||||
JOB_NOTIFIED = 1 << 0,
|
||||
NOTIFIED,
|
||||
/// Whether this job is in the foreground.
|
||||
JOB_FOREGROUND = 1 << 1,
|
||||
FOREGROUND,
|
||||
/// Whether the specified job is completely constructed, i.e. completely parsed, and every
|
||||
/// process in the job has been forked, etc.
|
||||
JOB_CONSTRUCTED = 1 << 2,
|
||||
CONSTRUCTED,
|
||||
/// Whether the specified job is a part of a subshell, event handler or some other form of
|
||||
/// special job that should not be reported.
|
||||
JOB_SKIP_NOTIFICATION = 1 << 3,
|
||||
SKIP_NOTIFICATION,
|
||||
/// Whether the exit status should be negated. This flag can only be set by the not builtin.
|
||||
JOB_NEGATE = 1 << 4,
|
||||
NEGATE,
|
||||
/// Whether the job is under job control.
|
||||
JOB_CONTROL = 1 << 5,
|
||||
JOB_CONTROL,
|
||||
/// Whether the job wants to own the terminal when in the foreground.
|
||||
JOB_TERMINAL = 1 << 6
|
||||
TERMINAL,
|
||||
};
|
||||
|
||||
typedef int job_id_t;
|
||||
|
@ -215,7 +216,7 @@ class job_t {
|
|||
/// this shell, and is used e.g. in process expansion.
|
||||
const job_id_t job_id;
|
||||
/// Bitset containing information about the job. A combination of the JOB_* constants.
|
||||
unsigned int flags;
|
||||
enum_set_t<job_flag_t> flags;
|
||||
|
||||
// Get and set flags
|
||||
bool get_flag(job_flag_t flag) const;
|
||||
|
@ -227,6 +228,37 @@ class job_t {
|
|||
|
||||
/// Fetch all the IO redirections associated with the job.
|
||||
io_chain_t all_io_redirections() const;
|
||||
|
||||
// Helper functions to check presence of flags on instances of jobs
|
||||
/// The job has been fully constructed, i.e. all its member processes have been launched
|
||||
bool is_constructed() const { return get_flag(job_flag_t::CONSTRUCTED); };
|
||||
/// The job was launched in the foreground and has control of the terminal
|
||||
bool is_foreground() const { return get_flag(job_flag_t::FOREGROUND); };
|
||||
/// The job is complete, i.e. all its member processes have been reaped
|
||||
bool is_completed() const;
|
||||
/// The job is in a stopped state
|
||||
bool is_stopped() const;
|
||||
|
||||
/// 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
|
||||
/// block.
|
||||
///
|
||||
/// \param cont Whether the function should wait for the job to complete before returning
|
||||
// (This would just be called `continue` but that's obviously a reserved keyword)
|
||||
void continue_job(bool cont);
|
||||
|
||||
/// Promotes the job to the front of the job list.
|
||||
void promote();
|
||||
|
||||
/// Send the specified signal to all processes in this job.
|
||||
int signal(int signal);
|
||||
|
||||
/// Return the job instance matching this unique job id.
|
||||
/// If id is 0 or less, return the last job used.
|
||||
static job_t *from_job_id(job_id_t id);
|
||||
|
||||
/// Return the job containing the process identified by the unique pid provided.
|
||||
static job_t *from_pid(pid_t pid);
|
||||
};
|
||||
|
||||
/// Whether we are reading from the keyboard right now.
|
||||
|
@ -306,28 +338,6 @@ void proc_set_last_status(int s);
|
|||
/// Returns the status of the last process to exit.
|
||||
int proc_get_last_status();
|
||||
|
||||
/// Promotes a job to the front of the job list.
|
||||
void job_promote(job_t *job);
|
||||
|
||||
/// Return the job with the specified job id. If id is 0 or less, return the last job used.
|
||||
job_t *job_get(job_id_t id);
|
||||
|
||||
/// Return the job with the specified pid.
|
||||
job_t *job_get_from_pid(int pid);
|
||||
|
||||
/// Tests if the job is stopped.
|
||||
int job_is_stopped(const job_t *j);
|
||||
|
||||
/// Tests if the job has completed, i.e. if the last process of the pipeline has ended.
|
||||
bool job_is_completed(const job_t *j);
|
||||
|
||||
/// Reassume a (possibly) stopped job. Put job j 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 block.
|
||||
///
|
||||
/// \param j The job
|
||||
/// \param cont Whether the function should wait for the job to complete before returning
|
||||
void job_continue(job_t *j, bool cont);
|
||||
|
||||
/// Notify the user about stopped or terminated jobs. Delete terminated jobs from the job list.
|
||||
///
|
||||
/// \param interactive whether interactive jobs should be reaped as well
|
||||
|
@ -336,9 +346,6 @@ int job_reap(bool interactive);
|
|||
/// Signal handler for SIGCHLD. Mark any processes with relevant information.
|
||||
void job_handle_signal(int signal, siginfo_t *info, void *con);
|
||||
|
||||
/// Send the specified signal to all processes in the specified job.
|
||||
int job_signal(job_t *j, int signal);
|
||||
|
||||
/// Mark a process as failed to execute (and therefore completed).
|
||||
void job_mark_process_as_failed(job_t *job, const process_t *p);
|
||||
|
||||
|
|
|
@ -2242,7 +2242,7 @@ void reader_bg_job_warning() {
|
|||
|
||||
job_iterator_t jobs;
|
||||
while (job_t *j = jobs.next()) {
|
||||
if (!job_is_completed(j)) {
|
||||
if (!j->is_completed()) {
|
||||
fwprintf(stdout, L"%6d %ls\n", j->processes[0]->pid, j->command_wcstr());
|
||||
}
|
||||
}
|
||||
|
@ -2254,9 +2254,9 @@ void reader_bg_job_warning() {
|
|||
void kill_background_jobs() {
|
||||
job_iterator_t jobs;
|
||||
while (job_t *j = jobs.next()) {
|
||||
if (!job_is_completed(j)) {
|
||||
if (job_is_stopped(j)) job_signal(j, SIGCONT);
|
||||
job_signal(j, SIGHUP);
|
||||
if (!j->is_completed()) {
|
||||
if (j->is_stopped()) j->signal(SIGCONT);
|
||||
j->signal(SIGHUP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2277,7 +2277,7 @@ static void handle_end_loop() {
|
|||
bool bg_jobs = false;
|
||||
job_iterator_t jobs;
|
||||
while (const job_t *j = jobs.next()) {
|
||||
if (!job_is_completed(j)) {
|
||||
if (!j->is_completed()) {
|
||||
bg_jobs = true;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue