diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-08-08 13:48:07 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-08-09 21:08:07 +0200 |
commit | 5ae2f6e9ec077432dc56d5cb8fc5c26c5cca8517 (patch) | |
tree | 4b388dc3e4c7a76175b5484c23c64ecc8e9056b8 /Shell | |
parent | c81c8b68bb7a0b8aa6989d505002fa697014919b (diff) | |
download | serenity-5ae2f6e9ec077432dc56d5cb8fc5c26c5cca8517.zip |
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)`.
Diffstat (limited to 'Shell')
-rw-r--r-- | Shell/AST.cpp | 13 | ||||
-rw-r--r-- | Shell/Job.h | 23 | ||||
-rw-r--r-- | 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 <AK/StringBuilder.h> #include <AK/URL.h> #include <LibCore/File.h> +#include <signal.h> //#define EXECUTE_DEBUG @@ -754,6 +755,8 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell) if (!m_block) return create<ListValue>({}); + size_t consecutive_interruptions = 0; + NonnullRefPtrVector<Value> values; auto resolved = m_iterated_expression->run(shell)->resolve_without_cast(shell); if (resolved->is_list_without_resolution()) @@ -762,6 +765,9 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell) values = create<ListValue>(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<Value> ForLoop::run(RefPtr<Shell> 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); |