Explorar el Código

Shell: Moves pipelined processes to one process group

AnotherTest hace 4 años
padre
commit
ab3e787334
Se han modificado 6 ficheros con 44 adiciones y 11 borrados
  1. 8 0
      Shell/AST.cpp
  2. 7 1
      Shell/AST.h
  3. 1 0
      Shell/Forward.h
  4. 1 0
      Shell/Job.cpp
  5. 7 2
      Shell/Job.h
  6. 20 8
      Shell/Shell.cpp

+ 8 - 0
Shell/AST.cpp

@@ -1142,6 +1142,14 @@ RefPtr<Value> Pipe::run(RefPtr<Shell> shell)
     last_in_left.should_wait = false;
     last_in_left.is_pipe_source = true;
 
+    if (first_in_right.pipeline) {
+        last_in_left.pipeline = first_in_right.pipeline;
+    } else {
+        auto pipeline = adopt(*new Pipeline);
+        last_in_left.pipeline = pipeline;
+        first_in_right.pipeline = pipeline;
+    }
+
     Vector<Command> commands;
     commands.append(left);
     commands.append(last_in_left);

+ 7 - 1
Shell/AST.h

@@ -150,9 +150,15 @@ private:
     virtual bool is_fd_redirection() const override { return true; }
 };
 
+class Pipeline : public RefCounted<Pipeline> {
+public:
+    pid_t pgid { -1 };
+};
+
 struct Command {
     Vector<String> argv;
     NonnullRefPtrVector<Redirection> redirections;
+    mutable RefPtr<Pipeline> pipeline;
     bool should_wait { true };
     bool is_pipe_source { false };
     bool should_notify_if_in_background { true };
@@ -190,7 +196,7 @@ public:
     }
 
     CommandValue(Vector<String> argv)
-        : m_command({ move(argv), {}, true, false, true })
+        : m_command({ move(argv), {}, {}, true, false, true })
     {
     }
 

+ 1 - 0
Shell/Forward.h

@@ -32,5 +32,6 @@ namespace AST {
 class Node;
 class Value;
 class SyntaxError;
+class Pipeline;
 
 }

+ 1 - 0
Shell/Job.cpp

@@ -25,6 +25,7 @@
  */
 
 #include "Job.h"
+#include "AST.h"
 #include <inttypes.h>
 #include <stdio.h>
 #include <sys/wait.h>

+ 7 - 2
Shell/Job.h

@@ -27,6 +27,7 @@
 #pragma once
 
 #include "Execution.h"
+#include "Forward.h"
 #include <AK/Function.h>
 #include <AK/JsonObject.h>
 #include <AK/JsonValue.h>
@@ -42,7 +43,7 @@
 
 class Job : public RefCounted<Job> {
 public:
-    static NonnullRefPtr<Job> create(pid_t pid, pid_t pgid, String command, u64 job_id) { return adopt(*new Job(pid, pgid, move(command), job_id)); }
+    static NonnullRefPtr<Job> create(pid_t pid, pid_t pgid, String command, u64 job_id, AST::Pipeline* pipeline = nullptr) { return adopt(*new Job(pid, pgid, move(command), job_id, pipeline)); }
 
     ~Job()
     {
@@ -121,12 +122,15 @@ public:
     bool print_status(PrintStatusMode);
 
 private:
-    Job(pid_t pid, unsigned pgid, String cmd, u64 job_id)
+    Job(pid_t pid, unsigned pgid, String cmd, u64 job_id, AST::Pipeline* pipeline)
         : m_pgid(pgid)
         , m_pid(pid)
         , m_job_id(job_id)
         , m_cmd(move(cmd))
     {
+        if (pipeline)
+            m_pipeline = *pipeline;
+
         set_running_in_background(false);
         m_command_timer.start();
     }
@@ -143,4 +147,5 @@ private:
     mutable bool m_active { true };
     mutable bool m_is_suspended { false };
     bool m_should_be_disowned { false };
+    RefPtr<AST::Pipeline> m_pipeline;
 };

+ 20 - 8
Shell/Shell.cpp

@@ -518,15 +518,10 @@ RefPtr<Job> Shell::run_command(const AST::Command& command)
         perror("fork");
         return nullptr;
     }
+
     if (child == 0) {
-        setpgid(0, 0);
         tcsetattr(0, TCSANOW, &default_termios);
-        if (command.should_wait) {
-            auto pid = getpid();
-            auto pgid = getpgid(pid);
-            tcsetpgrp(STDOUT_FILENO, pgid);
-            tcsetpgrp(STDIN_FILENO, pgid);
-        }
+
         for (auto& rewiring : rewirings) {
 #ifdef SH_DEBUG
             dbgprintf("in %s<%d>, dup2(%d, %d)\n", argv[0], getpid(), rewiring.dest_fd, rewiring.source_fd);
@@ -572,10 +567,27 @@ RefPtr<Job> Shell::run_command(const AST::Command& command)
         ASSERT_NOT_REACHED();
     }
 
+    bool is_first = !command.pipeline || (command.pipeline && command.pipeline->pgid == -1);
+
+    if (command.pipeline) {
+        if (is_first) {
+            command.pipeline->pgid = child;
+        }
+    }
+
+    pid_t pgid = is_first ? child : (command.pipeline ? command.pipeline->pgid : child);
+    if (setpgid(child, pgid) < 0)
+        perror("setpgid");
+
+    if (command.should_wait) {
+        tcsetpgrp(STDOUT_FILENO, pgid);
+        tcsetpgrp(STDIN_FILENO, pgid);
+    }
+
     StringBuilder cmd;
     cmd.join(" ", command.argv);
 
-    auto job = Job::create(child, (unsigned)child, cmd.build(), find_last_job_id() + 1);
+    auto job = Job::create(child, pgid, cmd.build(), find_last_job_id() + 1, command.pipeline);
     jobs.set((u64)child, job);
 
     job->on_exit = [](auto job) {