Преглед изворни кода

Kernel: Add a Finalizer process to take care of dying processes.

Instead of processes themselves getting scheduled to finish dying,
let's have a Finalizer process that wakes up whenever someone is dying.
This way we can do all kinds of lock-taking in process cleanup without
risking reentering the scheduler.
Andreas Kling пре 6 година
родитељ
комит
6cba80510e
5 измењених фајлова са 59 додато и 23 уклоњено
  1. 37 22
      Kernel/Process.cpp
  2. 4 0
      Kernel/Process.h
  3. 9 1
      Kernel/Scheduler.cpp
  4. 1 0
      Kernel/Scheduler.h
  5. 8 0
      Kernel/init.cpp

+ 37 - 22
Kernel/Process.cpp

@@ -62,21 +62,21 @@ void Process::initialize()
 
 Vector<pid_t> Process::all_pids()
 {
-    InterruptDisabler disabler;
     Vector<pid_t> pids;
-    pids.ensure_capacity(g_processes->size_slow());
+    pids.ensure_capacity(system.nprocess);
+    InterruptDisabler disabler;
     for (auto* process = g_processes->head(); process; process = process->next())
-        pids.unchecked_append(process->pid());
+        pids.append(process->pid());
     return pids;
 }
 
 Vector<Process*> Process::all_processes()
 {
-    InterruptDisabler disabler;
     Vector<Process*> processes;
-    processes.ensure_capacity(g_processes->size_slow());
+    processes.ensure_capacity(system.nprocess);
+    InterruptDisabler disabler;
     for (auto* process = g_processes->head(); process; process = process->next())
-        processes.unchecked_append(process);
+        processes.append(process);
     return processes;
 }
 
@@ -747,11 +747,9 @@ void Process::sys$exit(int status)
     kprintf("sys$exit: %s(%u) exit with status %d\n", name().characters(), pid(), status);
 #endif
 
-    die();
     m_termination_status = status;
     m_termination_signal = 0;
-
-    Scheduler::pick_next_and_switch_now();
+    die();
     ASSERT_NOT_REACHED();
 }
 
@@ -952,7 +950,6 @@ void Process::crash()
     m_termination_signal = SIGSEGV;
     dump_regions();
     die();
-    Scheduler::pick_next_and_switch_now();
     ASSERT_NOT_REACHED();
 }
 
@@ -2122,29 +2119,32 @@ int Process::sys$chmod(const char* pathname, mode_t mode)
     return 0;
 }
 
-void Process::die()
+void Process::finalize()
 {
-    // This is pretty hairy wrt interrupts. Once we set_state(Dead), we never get scheduled again.
-    // For this reason, we mark ourselves as Dying, which prevents the scheduler from dispatching signals in this process.
-    set_state(Dying);
-    InterruptFlagSaver saver;
+    ASSERT(current == g_finalizer);
 
-    // STI so we can take locks.
-    sti();
     destroy_all_windows();
     m_fds.clear();
     m_tty = nullptr;
 
-    // CLI for Process::from_pid(). This should go away eventually.
-    cli();
-    if (auto* parent_process = Process::from_pid(m_ppid)) {
-        parent_process->send_signal(SIGCHLD, this);
+    {
+        InterruptDisabler disabler;
+        if (auto* parent_process = Process::from_pid(m_ppid)) {
+            parent_process->send_signal(SIGCHLD, this);
+        }
     }
 
-    // Good night.
     set_state(Dead);
 }
 
+void Process::die()
+{
+    set_state(Dying);
+
+    if (!Scheduler::is_active())
+        Scheduler::pick_next_and_switch_now();
+}
+
 size_t Process::amount_virtual() const
 {
     size_t amount = 0;
@@ -2186,3 +2186,18 @@ size_t Process::amount_shared() const
     }
     return amount;
 }
+
+void Process::finalize_dying_processes()
+{
+    Vector<Process*> dying_processes;
+    {
+        InterruptDisabler disabler;
+        dying_processes.ensure_capacity(system.nprocess);
+        for (auto* process = g_processes->head(); process; process = process->next()) {
+            if (process->state() == Process::Dying)
+                dying_processes.append(process);
+        }
+    }
+    for (auto* process : dying_processes)
+        process->finalize();
+}

+ 4 - 0
Kernel/Process.h

@@ -60,6 +60,7 @@ public:
 
     static Vector<pid_t> all_pids();
     static Vector<Process*> all_processes();
+    static void finalize_dying_processes();
 
     enum State {
         Invalid = 0,
@@ -70,6 +71,7 @@ public:
         Dying,
         Dead,
         BeingInspected,
+        BlockedLurking,
         BlockedSleep,
         BlockedWait,
         BlockedRead,
@@ -135,6 +137,7 @@ public:
     void set_selector(word s) { m_far_ptr.selector = s; }
     void set_state(State s) { m_state = s; }
     void die();
+    void finalize();
 
     pid_t sys$setsid();
     pid_t sys$getsid(pid_t);
@@ -453,6 +456,7 @@ static inline const char* to_string(Process::State state)
     case Process::BlockedWrite: return "Write";
     case Process::BlockedSignal: return "Signal";
     case Process::BlockedSelect: return "Select";
+    case Process::BlockedLurking: return "Lurking";
     case Process::BeingInspected: return "Inspect";
     }
     ASSERT_NOT_REACHED();

+ 9 - 1
Kernel/Scheduler.cpp

@@ -12,6 +12,7 @@ static const dword time_slice = 5; // *10 = 50ms
 
 Process* current;
 Process* g_last_fpu_process;
+Process* g_finalizer;
 static Process* s_colonel_process;
 
 struct TaskRedirectionData {
@@ -127,6 +128,13 @@ bool Scheduler::pick_next()
             return true;
         }
 
+        if (process.state() == Process::Dying) {
+            ASSERT(g_finalizer);
+            if (g_finalizer->state() == Process::BlockedLurking)
+                g_finalizer->unblock();
+            return true;
+        }
+
         return true;
     });
 
@@ -170,7 +178,7 @@ bool Scheduler::pick_next()
         g_processes->append(g_processes->remove_head());
         auto* process = g_processes->head();
 
-        if (process->state() == Process::Runnable || process->state() == Process::Running || process->state() == Process::Dying) {
+        if (process->state() == Process::Runnable || process->state() == Process::Running) {
 #ifdef SCHEDULER_DEBUG
             dbgprintf("switch to %s(%u) @ %w:%x\n", process->name().characters(), process->pid(), process->tss().cs, process->tss().eip);
 #endif

+ 1 - 0
Kernel/Scheduler.h

@@ -7,6 +7,7 @@ struct RegisterDump;
 
 extern Process* current;
 extern Process* g_last_fpu_process;
+extern Process* g_finalizer;
 
 class Scheduler {
 public:

+ 8 - 0
Kernel/init.cpp

@@ -187,6 +187,14 @@ void init()
             sleep(10 * TICKS_PER_SECOND);
         }
     });
+    Process::create_kernel_process("Finalizer", [] {
+        g_finalizer = current;
+        for (;;) {
+            Process::finalize_dying_processes();
+            current->block(Process::BlockedLurking);
+            Scheduler::yield();
+        }
+    });
 
     Scheduler::pick_next();