From 5ae2f6e9ec077432dc56d5cb8fc5c26c5cca8517 Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Sat, 8 Aug 2020 13:48:07 +0430 Subject: [PATCH] Shell: Stop a for loop upon receiving two consecutive interruptions This does not work perfectly (just like every other shell...), if the running program handles the signal (SIGINT in this case) and quits cleanly, the shell cannot detect the interruption. This is the case with our `sleep(1)`. --- Shell/AST.cpp | 13 +++++++++++++ Shell/Job.h | 23 ++++++++++++++++++++++- Shell/main.cpp | 6 +++--- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Shell/AST.cpp b/Shell/AST.cpp index d337581631..64a9ef86ca 100644 --- a/Shell/AST.cpp +++ b/Shell/AST.cpp @@ -30,6 +30,7 @@ #include #include #include +#include //#define EXECUTE_DEBUG @@ -754,6 +755,8 @@ RefPtr ForLoop::run(RefPtr shell) if (!m_block) return create({}); + size_t consecutive_interruptions = 0; + NonnullRefPtrVector values; auto resolved = m_iterated_expression->run(shell)->resolve_without_cast(shell); if (resolved->is_list_without_resolution()) @@ -762,6 +765,9 @@ RefPtr ForLoop::run(RefPtr shell) values = create(resolved->resolve_as_list(shell))->values(); for (auto& value : values) { + if (consecutive_interruptions == 2) + break; + auto frame = shell->push_frame(); shell->set_local_variable(m_variable_name, value); @@ -771,6 +777,13 @@ RefPtr ForLoop::run(RefPtr shell) if (!job || job->is_running_in_background()) continue; shell->block_on_job(job); + if (job->signaled() + && (job->termination_signal() == SIGINT + || job->termination_signal() == SIGKILL + || job->termination_signal() == SIGQUIT)) + ++consecutive_interruptions; + else + consecutive_interruptions = 0; } } diff --git a/Shell/Job.h b/Shell/Job.h index 75636a8758..9de08bfebc 100644 --- a/Shell/Job.h +++ b/Shell/Job.h @@ -59,7 +59,17 @@ public: const String& cmd() const { return m_cmd; } u64 job_id() const { return m_job_id; } bool exited() const { return m_exited; } - int exit_code() const { return m_exit_code; } + bool signaled() const { return m_term_sig != -1; } + int exit_code() const + { + ASSERT(exited()); + return m_exit_code; + } + int termination_signal() const + { + ASSERT(signaled()); + return m_term_sig; + } 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; } @@ -82,6 +92,16 @@ public: if (on_exit) on_exit(*this); } + void set_signalled(int sig) + { + if (m_exited) + return; + m_exited = true; + m_exit_code = 126; + m_term_sig = sig; + if (on_exit) + on_exit(*this); + } void set_is_suspended(bool value) const { m_is_suspended = value; } @@ -118,6 +138,7 @@ private: bool m_exited { false }; bool m_running_in_background { false }; int m_exit_code { -1 }; + int m_term_sig { -1 }; Core::ElapsedTimer m_command_timer; mutable bool m_active { true }; mutable bool m_is_suspended { false }; diff --git a/Shell/main.cpp b/Shell/main.cpp index 6c279ba488..80ef3aa22d 100644 --- a/Shell/main.cpp +++ b/Shell/main.cpp @@ -105,10 +105,10 @@ int main(int argc, char** argv) } #endif if (child_pid == job.pid()) { - if (WIFEXITED(wstatus)) { + if (WIFSIGNALED(wstatus) && !WIFSTOPPED(wstatus)) { + job.set_signalled(WTERMSIG(wstatus)); + } else if (WIFEXITED(wstatus)) { job.set_has_exit(WEXITSTATUS(wstatus)); - } else if (WIFSIGNALED(wstatus) && !WIFSTOPPED(wstatus)) { - job.set_has_exit(126); } else if (WIFSTOPPED(wstatus)) { job.unblock(); job.set_is_suspended(true);