mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 22:07:34 +00:00
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)`.
This commit is contained in:
parent
c81c8b68bb
commit
5ae2f6e9ec
3 changed files with 38 additions and 4 deletions
|
@ -30,6 +30,7 @@
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/URL.h>
|
#include <AK/URL.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
//#define EXECUTE_DEBUG
|
//#define EXECUTE_DEBUG
|
||||||
|
|
||||||
|
@ -754,6 +755,8 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
|
||||||
if (!m_block)
|
if (!m_block)
|
||||||
return create<ListValue>({});
|
return create<ListValue>({});
|
||||||
|
|
||||||
|
size_t consecutive_interruptions = 0;
|
||||||
|
|
||||||
NonnullRefPtrVector<Value> values;
|
NonnullRefPtrVector<Value> values;
|
||||||
auto resolved = m_iterated_expression->run(shell)->resolve_without_cast(shell);
|
auto resolved = m_iterated_expression->run(shell)->resolve_without_cast(shell);
|
||||||
if (resolved->is_list_without_resolution())
|
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();
|
values = create<ListValue>(resolved->resolve_as_list(shell))->values();
|
||||||
|
|
||||||
for (auto& value : values) {
|
for (auto& value : values) {
|
||||||
|
if (consecutive_interruptions == 2)
|
||||||
|
break;
|
||||||
|
|
||||||
auto frame = shell->push_frame();
|
auto frame = shell->push_frame();
|
||||||
shell->set_local_variable(m_variable_name, value);
|
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())
|
if (!job || job->is_running_in_background())
|
||||||
continue;
|
continue;
|
||||||
shell->block_on_job(job);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
Shell/Job.h
23
Shell/Job.h
|
@ -59,7 +59,17 @@ public:
|
||||||
const String& cmd() const { return m_cmd; }
|
const String& cmd() const { return m_cmd; }
|
||||||
u64 job_id() const { return m_job_id; }
|
u64 job_id() const { return m_job_id; }
|
||||||
bool exited() const { return m_exited; }
|
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; }
|
bool should_be_disowned() const { return m_should_be_disowned; }
|
||||||
void disown() { m_should_be_disowned = true; }
|
void disown() { m_should_be_disowned = true; }
|
||||||
bool is_running_in_background() const { return m_running_in_background; }
|
bool is_running_in_background() const { return m_running_in_background; }
|
||||||
|
@ -82,6 +92,16 @@ public:
|
||||||
if (on_exit)
|
if (on_exit)
|
||||||
on_exit(*this);
|
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; }
|
void set_is_suspended(bool value) const { m_is_suspended = value; }
|
||||||
|
|
||||||
|
@ -118,6 +138,7 @@ private:
|
||||||
bool m_exited { false };
|
bool m_exited { false };
|
||||||
bool m_running_in_background { false };
|
bool m_running_in_background { false };
|
||||||
int m_exit_code { -1 };
|
int m_exit_code { -1 };
|
||||||
|
int m_term_sig { -1 };
|
||||||
Core::ElapsedTimer m_command_timer;
|
Core::ElapsedTimer m_command_timer;
|
||||||
mutable bool m_active { true };
|
mutable bool m_active { true };
|
||||||
mutable bool m_is_suspended { false };
|
mutable bool m_is_suspended { false };
|
||||||
|
|
|
@ -105,10 +105,10 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (child_pid == job.pid()) {
|
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));
|
job.set_has_exit(WEXITSTATUS(wstatus));
|
||||||
} else if (WIFSIGNALED(wstatus) && !WIFSTOPPED(wstatus)) {
|
|
||||||
job.set_has_exit(126);
|
|
||||||
} else if (WIFSTOPPED(wstatus)) {
|
} else if (WIFSTOPPED(wstatus)) {
|
||||||
job.unblock();
|
job.unblock();
|
||||||
job.set_is_suspended(true);
|
job.set_is_suspended(true);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue