summaryrefslogtreecommitdiff
path: root/Shell
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-08-08 13:48:07 +0430
committerAndreas Kling <kling@serenityos.org>2020-08-09 21:08:07 +0200
commit5ae2f6e9ec077432dc56d5cb8fc5c26c5cca8517 (patch)
tree4b388dc3e4c7a76175b5484c23c64ecc8e9056b8 /Shell
parentc81c8b68bb7a0b8aa6989d505002fa697014919b (diff)
downloadserenity-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.cpp13
-rw-r--r--Shell/Job.h23
-rw-r--r--Shell/main.cpp6
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);