Преглед на файлове

Kernel: Distinguish between new and old process groups with equal pgids

This does not add any behaviour change to the processes, but it ties a
TTY to an active process group via TIOCSPGRP, and returns the TTY to the
kernel when all processes in the process group die.
Also makes the TTY keep a link to the original controlling process' parent (for
SIGCHLD) instead of the process itself.
AnotherTest преди 5 години
родител
ревизия
688e54eac7
променени са 9 файла, в които са добавени 176 реда и са изтрити 23 реда
  1. 1 0
      Kernel/CMakeLists.txt
  2. 1 0
      Kernel/Process.cpp
  3. 4 3
      Kernel/Process.h
  4. 70 0
      Kernel/ProcessGroup.cpp
  5. 72 0
      Kernel/ProcessGroup.h
  6. 1 1
      Kernel/Syscalls/fork.cpp
  7. 5 5
      Kernel/Syscalls/setpgid.cpp
  8. 18 12
      Kernel/TTY/TTY.cpp
  9. 4 2
      Kernel/TTY/TTY.h

+ 1 - 0
Kernel/CMakeLists.txt

@@ -82,6 +82,7 @@ set(KERNEL_SOURCES
     PCI/MMIOAccess.cpp
     PerformanceEventBuffer.cpp
     Process.cpp
+    ProcessGroup.cpp
     Profiling.cpp
     Ptrace.cpp
     RTC.cpp

+ 1 - 0
Kernel/Process.cpp

@@ -111,6 +111,7 @@ void Process::initialize()
 
     next_pid.store(0, AK::MemoryOrder::memory_order_release);
     g_processes = new InlineLinkedList<Process>;
+    g_process_groups = new InlineLinkedList<ProcessGroup>;
     g_hostname = new String("courage");
     g_hostname_lock = new Lock;
 

+ 4 - 3
Kernel/Process.h

@@ -40,6 +40,7 @@
 #include <Kernel/FileSystem/InodeMetadata.h>
 #include <Kernel/Forward.h>
 #include <Kernel/Lock.h>
+#include <Kernel/ProcessGroup.h>
 #include <Kernel/StdLib.h>
 #include <Kernel/Thread.h>
 #include <Kernel/UnixTypes.h>
@@ -159,8 +160,8 @@ public:
     ProcessID pid() const { return m_pid; }
     SessionID sid() const { return m_sid; }
     bool is_session_leader() const { return m_sid.value() == m_pid.value(); }
-    ProcessGroupID pgid() const { return m_pgid; }
-    bool is_group_leader() const { return m_pgid.value() == m_pid.value(); }
+    ProcessGroupID pgid() const { return m_pg ? m_pg->pgid() : 0; }
+    bool is_group_leader() const { return pgid().value() == m_pid.value(); }
     const FixedArray<gid_t>& extra_gids() const { return m_extra_gids; }
     uid_t euid() const { return m_euid; }
     gid_t egid() const { return m_egid; }
@@ -620,7 +621,7 @@ private:
 
     ProcessID m_pid { 0 };
     SessionID m_sid { 0 };
-    ProcessGroupID m_pgid { 0 };
+    RefPtr<ProcessGroup> m_pg;
 
     uid_t m_euid { 0 };
     gid_t m_egid { 0 };

+ 70 - 0
Kernel/ProcessGroup.cpp

@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ProcessGroup.h"
+
+namespace Kernel {
+
+RecursiveSpinLock g_process_groups_lock;
+InlineLinkedList<ProcessGroup>* g_process_groups;
+
+ProcessGroup::~ProcessGroup()
+{
+    ScopedSpinLock lock(g_process_groups_lock);
+    g_process_groups->remove(this);
+}
+
+NonnullRefPtr<ProcessGroup> ProcessGroup::create(ProcessGroupID pgid)
+{
+    auto process_group = adopt(*new ProcessGroup(pgid));
+    {
+        ScopedSpinLock lock(g_process_groups_lock);
+        g_process_groups->prepend(process_group);
+    }
+
+    return process_group;
+}
+
+NonnullRefPtr<ProcessGroup> ProcessGroup::find_or_create(ProcessGroupID pgid)
+{
+    if (auto existing = from_pgid(pgid))
+        return *existing;
+
+    return create(pgid);
+}
+
+ProcessGroup* ProcessGroup::from_pgid(ProcessGroupID pgid)
+{
+    ScopedSpinLock lock(g_process_groups_lock);
+
+    for (auto& group : *g_process_groups) {
+        if (group.pgid() == pgid)
+            return &group;
+    }
+    return nullptr;
+}
+
+}

+ 72 - 0
Kernel/ProcessGroup.h

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2020, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/InlineLinkedList.h>
+#include <AK/RefCounted.h>
+#include <AK/Weakable.h>
+#include <Kernel/Lock.h>
+#include <Kernel/SpinLock.h>
+#include <Kernel/UnixTypes.h>
+
+namespace Kernel {
+
+class ProcessGroup
+    : public RefCounted<ProcessGroup>
+    , public Weakable<ProcessGroup>
+    , public InlineLinkedListNode<ProcessGroup> {
+
+    AK_MAKE_NONMOVABLE(ProcessGroup);
+    AK_MAKE_NONCOPYABLE(ProcessGroup);
+
+    friend InlineLinkedListNode<ProcessGroup>;
+
+public:
+    ~ProcessGroup();
+
+    static NonnullRefPtr<ProcessGroup> create(ProcessGroupID);
+    static NonnullRefPtr<ProcessGroup> find_or_create(ProcessGroupID);
+    static ProcessGroup* from_pgid(ProcessGroupID);
+
+    const ProcessGroupID& pgid() const { return m_pgid; }
+
+private:
+    ProcessGroup(ProcessGroupID pgid)
+        : m_pgid(pgid)
+    {
+    }
+
+    ProcessGroup* m_prev { nullptr };
+    ProcessGroup* m_next { nullptr };
+
+    ProcessGroupID m_pgid;
+};
+
+extern InlineLinkedList<ProcessGroup>* g_process_groups;
+extern RecursiveSpinLock g_process_groups_lock;
+
+}

+ 1 - 1
Kernel/Syscalls/fork.cpp

@@ -46,7 +46,7 @@ pid_t Process::sys$fork(RegisterState& regs)
     child->m_unveiled_paths = m_unveiled_paths;
     child->m_fds = m_fds;
     child->m_sid = m_sid;
-    child->m_pgid = m_pgid;
+    child->m_pg = m_pg;
     child->m_umask = m_umask;
 
 #ifdef FORK_DEBUG

+ 5 - 5
Kernel/Syscalls/setpgid.cpp

@@ -56,7 +56,7 @@ pid_t Process::sys$setsid()
         return -EPERM;
     // Create a new Session and a new ProcessGroup.
     m_sid = m_pid.value();
-    m_pgid = m_pid.value();
+    m_pg = ProcessGroup::create(ProcessGroupID(m_pid.value()));
     m_tty = nullptr;
     return m_sid.value();
 }
@@ -65,18 +65,18 @@ pid_t Process::sys$getpgid(pid_t pid)
 {
     REQUIRE_PROMISE(proc);
     if (pid == 0)
-        return m_pgid.value();
+        return pgid().value();
     ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
     auto process = Process::from_pid(pid);
     if (!process)
         return -ESRCH;
-    return process->m_pgid.value();
+    return process->pgid().value();
 }
 
 pid_t Process::sys$getpgrp()
 {
     REQUIRE_PROMISE(stdio);
-    return m_pgid.value();
+    return pgid().value();
 }
 
 SessionID Process::get_sid_from_pgid(ProcessGroupID pgid)
@@ -134,7 +134,7 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
         return -EPERM;
     }
     // FIXME: There are more EPERM conditions to check for here..
-    process->m_pgid = new_pgid;
+    process->m_pg = ProcessGroup::find_or_create(new_pgid);
     return 0;
 }
 

+ 18 - 12
Kernel/TTY/TTY.cpp

@@ -155,10 +155,8 @@ void TTY::emit(u8 ch)
         if (ch == m_termios.c_cc[VSUSP]) {
             dbg() << tty_name() << ": VSUSP pressed!";
             generate_signal(SIGTSTP);
-            if (m_process) {
-                if (auto parent = Process::from_pid(m_process->ppid()))
-                    (void)parent->send_signal(SIGCHLD, m_process);
-            }
+            if (m_original_process_parent)
+                (void)m_original_process_parent->send_signal(SIGCHLD, nullptr);
             // TODO: Else send it to the session leader maybe?
             return;
         }
@@ -310,13 +308,27 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
         if (pgid <= 0)
             return -EINVAL;
         InterruptDisabler disabler;
-        auto process = Process::from_pid(pgid.value());
+        auto process_group = ProcessGroup::from_pgid(pgid);
+        // Disallow setting a nonexistent PGID.
+        if (!process_group)
+            return -EINVAL;
+
+        auto process = Process::from_pid(ProcessID(pgid.value()));
         SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
         if (!new_sid || new_sid != current_process.sid())
             return -EPERM;
         if (process && pgid != process->pgid())
             return -EPERM;
-        m_process = process ? process->make_weak_ptr() : WeakPtr<Process>();
+        m_pg = process_group->make_weak_ptr();
+
+        if (process) {
+            if (auto parent = Process::from_pid(process->ppid())) {
+                m_original_process_parent = parent->make_weak_ptr();
+                return 0;
+            }
+        }
+
+        m_original_process_parent = nullptr;
         return 0;
     }
     case TCGETS: {
@@ -392,10 +404,4 @@ void TTY::hang_up()
 {
     generate_signal(SIGHUP);
 }
-
-ProcessGroupID TTY::pgid() const
-{
-    return m_process ? m_process->pgid() : 0;
-}
-
 }

+ 4 - 2
Kernel/TTY/TTY.h

@@ -30,6 +30,7 @@
 #include <AK/WeakPtr.h>
 #include <Kernel/Devices/CharacterDevice.h>
 #include <Kernel/DoubleBuffer.h>
+#include <Kernel/ProcessGroup.h>
 #include <Kernel/UnixTypes.h>
 
 namespace Kernel {
@@ -50,7 +51,7 @@ public:
     unsigned short rows() const { return m_rows; }
     unsigned short columns() const { return m_columns; }
 
-    ProcessGroupID pgid() const;
+    ProcessGroupID pgid() const { return m_pg ? m_pg->pgid() : 0; }
 
     void set_termios(const termios&);
     bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }
@@ -91,7 +92,8 @@ private:
     virtual bool is_tty() const final override { return true; }
 
     CircularDeque<u8, 1024> m_input_buffer;
-    WeakPtr<Process> m_process;
+    WeakPtr<Process> m_original_process_parent;
+    WeakPtr<ProcessGroup> m_pg;
     termios m_termios;
     unsigned short m_rows { 0 };
     unsigned short m_columns { 0 };