diff options
-rw-r--r-- | Shell/Builtin.cpp | 35 | ||||
-rw-r--r-- | Shell/Job.h | 5 | ||||
-rw-r--r-- | Shell/Shell.cpp | 26 | ||||
-rw-r--r-- | Shell/Shell.h | 3 | ||||
-rw-r--r-- | Shell/main.cpp | 15 |
5 files changed, 49 insertions, 35 deletions
diff --git a/Shell/Builtin.cpp b/Shell/Builtin.cpp index a2e77c4183..1eace438f0 100644 --- a/Shell/Builtin.cpp +++ b/Shell/Builtin.cpp @@ -372,44 +372,33 @@ int Shell::builtin_disown(int argc, const char** argv) fprintf(stderr, "disown: Invalid job id %s\n", job_id); } - if (job_ids.is_empty()) { - u64 id = 0; - for (auto& job : jobs) - id = max(id, job.value->job_id()); - job_ids.append(id); - } + if (job_ids.is_empty()) + job_ids.append(find_last_job_id()); - Vector<size_t> keys_of_jobs_to_disown; + Vector<const Job*> jobs_to_disown; for (auto id : job_ids) { - bool found = false; - for (auto& entry : jobs) { - if (entry.value->job_id() == id) { - keys_of_jobs_to_disown.append(entry.key); - found = true; - break; - } - } - if (!found) { + auto job = find_job(id); + if (!job) fprintf(stderr, "disown: job with id %zu not found\n", id); - } + else + jobs_to_disown.append(job); } - if (keys_of_jobs_to_disown.is_empty()) { - if (str_job_ids.is_empty()) { + + if (jobs_to_disown.is_empty()) { + if (str_job_ids.is_empty()) fprintf(stderr, "disown: no current job\n"); - } // An error message has already been printed about the nonexistence of each listed job. return 1; } - for (auto job_index : keys_of_jobs_to_disown) { - auto job = jobs.get(job_index).value(); + for (auto job : jobs_to_disown) { job->deactivate(); if (!job->is_running_in_background()) fprintf(stderr, "disown warning: job %" PRIu64 " is currently not running, 'kill -%d %d' to make it continue\n", job->job_id(), SIGCONT, job->pid()); - jobs.remove(job_index); + jobs.remove(job->pid()); } return 0; diff --git a/Shell/Job.h b/Shell/Job.h index c674136942..239473fd87 100644 --- a/Shell/Job.h +++ b/Shell/Job.h @@ -75,6 +75,11 @@ public: bool should_be_disowned() const { return m_should_be_disowned; } void disown() { m_should_be_disowned = true; } bool is_running_in_background() const { return m_running_in_background; } + void unblock() const + { + if (!m_exited && on_exit) + on_exit(*this); + } Function<void(RefPtr<Job>)> on_exit; Core::ElapsedTimer& timer() { return m_command_timer; } diff --git a/Shell/Shell.cpp b/Shell/Shell.cpp index 2ee2e9f949..0b42ee6222 100644 --- a/Shell/Shell.cpp +++ b/Shell/Shell.cpp @@ -474,6 +474,7 @@ RefPtr<Job> Shell::run_command(const AST::Command& command) return nullptr; } if (child == 0) { + setpgid(0, 0); tcsetattr(0, TCSANOW, &default_termios); for (auto& rewiring : rewirings) { #ifdef SH_DEBUG @@ -523,6 +524,8 @@ RefPtr<Job> Shell::run_command(const AST::Command& command) jobs.set((u64)child, job); job->on_exit = [](auto job) { + if (!job->exited()) + return; if (job->is_running_in_background()) fprintf(stderr, "Shell: Job %d(%s) exited\n", job->pid(), job->cmd().characters()); job->disown(); @@ -598,6 +601,8 @@ void Shell::restore_stdin() void Shell::block_on_job(RefPtr<Job> job) { + TemporaryChange<const Job*> current_job { m_current_job, job.ptr() }; + if (!job) return; @@ -1051,18 +1056,10 @@ void Shell::stop_all_jobs() #ifdef SH_DEBUG dbg() << "Job " << entry.value->pid() << " is not running in background"; #endif - if (killpg(entry.value->pgid(), SIGCONT) < 0) { - perror("killpg(CONT)"); - } - } - - if (killpg(entry.value->pgid(), SIGHUP) < 0) { - perror("killpg(HUP)"); + kill_job(entry.value, SIGCONT); } - if (killpg(entry.value->pgid(), SIGTERM) < 0) { - perror("killpg(TERM)"); - } + kill_job(entry.value, SIGHUP); } usleep(10000); // Wait for a bit before killing the job @@ -1099,6 +1096,15 @@ const Job* Shell::find_job(u64 id) return nullptr; } +void Shell::kill_job(const Job* job, int sig) +{ + if (!job) + return; + + if (killpg(job->pgid(), sig) < 0) + perror("killpg(job)"); +} + void Shell::save_to(JsonObject& object) { Core::Object::save_to(object); diff --git a/Shell/Shell.h b/Shell/Shell.h index 72b500ab40..177a22eab2 100644 --- a/Shell/Shell.h +++ b/Shell/Shell.h @@ -111,6 +111,8 @@ public: u64 find_last_job_id() const; const Job* find_job(u64 id); + const Job* current_job() const { return m_current_job; } + void kill_job(const Job*, int sig); String get_history_path(); void load_history(); @@ -163,6 +165,7 @@ private: void cache_path(); void stop_all_jobs(); + const Job* m_current_job { nullptr }; virtual void custom_event(Core::CustomEvent&) override; diff --git a/Shell/main.cpp b/Shell/main.cpp index b26ae28092..2d041679f5 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -62,16 +62,21 @@ int main(int argc, char** argv) Core::EventLoop::register_signal(SIGINT, [](int) { editor->interrupted(); + s_shell->kill_job(s_shell->current_job(), SIGINT); }); Core::EventLoop::register_signal(SIGWINCH, [](int) { editor->resized(); + s_shell->kill_job(s_shell->current_job(), SIGWINCH); }); Core::EventLoop::register_signal(SIGTTIN, [](int) {}); Core::EventLoop::register_signal(SIGTTOU, [](int) {}); Core::EventLoop::register_signal(SIGHUP, [](int) { + for (auto& it : s_shell->jobs) + s_shell->kill_job(it.value.ptr(), SIGHUP); + s_shell->save_history(); }); @@ -102,6 +107,8 @@ int main(int argc, char** argv) job.value->set_has_exit(WEXITSTATUS(wstatus)); } else if (WIFSIGNALED(wstatus) && !WIFSTOPPED(wstatus)) { job.value->set_has_exit(126); + } else if (WIFSTOPPED(wstatus)) { + job.value->unblock(); } } if (job.value->should_be_disowned()) @@ -111,8 +118,12 @@ int main(int argc, char** argv) jobs.remove(key); }); - // Ignore SIGTSTP as the shell should not be suspended with ^Z. - Core::EventLoop::register_signal(SIGTSTP, [](auto) {}); + Core::EventLoop::register_signal(SIGTSTP, [](auto) { + auto job = s_shell->current_job(); + s_shell->kill_job(job, SIGTSTP); + if (job) + job->unblock(); + }); #ifndef __serenity__ sigset_t blocked; |