Prechádzať zdrojové kódy

Shell: Make interrupts kill the whole chain and not just the current job

This makes interrupting `sleep 10; echo hi` not print `hi` anymore,
which is the expected behaviour anyway.
Also fixes the problem with fast-running loops "eating" interrupts and
not quitting.
Ali Mohammad Pur 3 rokov pred
rodič
commit
ea66750640
3 zmenil súbory, kde vykonal 33 pridanie a 13 odobranie
  1. 21 12
      Userland/Shell/AST.cpp
  2. 8 1
      Userland/Shell/Shell.cpp
  3. 4 0
      Userland/Shell/Shell.h

+ 21 - 12
Userland/Shell/AST.cpp

@@ -1190,7 +1190,7 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
             return IterationDecision::Continue;
         }
 
-        if (!shell->has_error(Shell::ShellError::None))
+        if (shell->has_any_error() && !shell->has_error(Shell::ShellError::InternalControlFlowInterrupted))
             return IterationDecision::Break;
 
         if (block_value->is_job()) {
@@ -1199,13 +1199,12 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
                 return IterationDecision::Continue;
             shell->block_on_job(job);
 
-            if (job->signaled()) {
-                if (job->termination_signal() == SIGINT)
+            if (shell->has_any_error()) {
+                if (shell->has_error(Shell::ShellError::InternalControlFlowInterrupted))
                     ++consecutive_interruptions;
-                else
+
+                if (shell->has_error(Shell::ShellError::InternalControlFlowKilled))
                     return IterationDecision::Break;
-            } else {
-                consecutive_interruptions = 0;
             }
         }
         return IterationDecision::Continue;
@@ -1216,11 +1215,16 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
         Optional<StringView> index_name = m_index_variable.has_value() ? Optional<StringView>(m_index_variable->name) : Optional<StringView>();
         size_t i = 0;
         m_iterated_expression->for_each_entry(shell, [&](auto value) {
-            if (consecutive_interruptions == 2)
+            if (consecutive_interruptions >= 2)
                 return IterationDecision::Break;
 
-            if (shell && shell->has_any_error())
-                return IterationDecision::Break;
+            if (shell) {
+                if (shell->has_error(Shell::ShellError::InternalControlFlowInterrupted))
+                    shell->take_error();
+
+                if (shell->has_any_error())
+                    return IterationDecision::Break;
+            }
 
             RefPtr<Value> block_value;
 
@@ -1240,11 +1244,16 @@ RefPtr<Value> ForLoop::run(RefPtr<Shell> shell)
         });
     } else {
         for (;;) {
-            if (shell && shell->has_any_error())
+            if (consecutive_interruptions >= 2)
                 break;
 
-            if (consecutive_interruptions == 2)
-                break;
+            if (shell) {
+                if (shell->has_error(Shell::ShellError::InternalControlFlowInterrupted))
+                    shell->take_error();
+
+                if (shell->has_any_error())
+                    break;
+            }
 
             RefPtr<Value> block_value = m_block->run(shell);
             if (run(block_value) == IterationDecision::Break)

+ 8 - 1
Userland/Shell/Shell.cpp

@@ -1765,7 +1765,12 @@ void Shell::notify_child_event()
             }
             if (child_pid == job.pid()) {
                 if (WIFSIGNALED(wstatus) && !WIFSTOPPED(wstatus)) {
-                    job.set_signalled(WTERMSIG(wstatus));
+                    auto signal = WTERMSIG(wstatus);
+                    job.set_signalled(signal);
+                    if (signal == SIGINT)
+                        raise_error(ShellError::InternalControlFlowInterrupted, "Interrupted"sv, job.command().position);
+                    else if (signal == SIGKILL)
+                        raise_error(ShellError::InternalControlFlowKilled, "Interrupted"sv, job.command().position);
                 } else if (WIFEXITED(wstatus)) {
                     job.set_has_exit(WEXITSTATUS(wstatus));
                 } else if (WIFSTOPPED(wstatus)) {
@@ -1998,6 +2003,8 @@ void Shell::possibly_print_error() const
         break;
     case ShellError::InternalControlFlowBreak:
     case ShellError::InternalControlFlowContinue:
+    case ShellError::InternalControlFlowInterrupted:
+    case ShellError::InternalControlFlowKilled:
         return;
     case ShellError::None:
         return;

+ 4 - 0
Userland/Shell/Shell.h

@@ -228,6 +228,8 @@ public:
         None,
         InternalControlFlowBreak,
         InternalControlFlowContinue,
+        InternalControlFlowInterrupted,
+        InternalControlFlowKilled,
         EvaluatedSyntaxError,
         NonExhaustiveMatchRules,
         InvalidGlobError,
@@ -260,6 +262,8 @@ public:
         switch (error) {
         case ShellError::InternalControlFlowBreak:
         case ShellError::InternalControlFlowContinue:
+        case ShellError::InternalControlFlowInterrupted:
+        case ShellError::InternalControlFlowKilled:
             return true;
         default:
             return false;