소스 검색

Kernel: Briefly resume stopped threads when being killed

We need to briefly put Stopped threads back into Running state
so that the kernel stacks can get cleaned up when they're being
killed.

Fixes #3130
Tom 5 년 전
부모
커밋
72960fedc6
2개의 변경된 파일33개의 추가작업 그리고 13개의 파일을 삭제
  1. 31 13
      Kernel/Thread.cpp
  2. 2 0
      Kernel/Thread.h

+ 31 - 13
Kernel/Thread.cpp

@@ -136,7 +136,21 @@ void Thread::set_should_die()
 
 
     // Remember that we should die instead of returning to
     // Remember that we should die instead of returning to
     // the userspace.
     // the userspace.
-    m_should_die = true;
+    {
+        ScopedSpinLock lock(g_scheduler_lock);
+        m_should_die = true;
+
+        // NOTE: Even the current thread can technically be in "Stopped"
+        // state! This is the case when another thread sent a SIGSTOP to
+        // it while it was running and it calls e.g. exit() before
+        // the scheduler gets involved again.
+        if (is_stopped()) {
+            // If we were stopped, we need to briefly resume so that
+            // the kernel stacks can clean up. We won't ever return back
+            // to user mode, though
+            resume_from_stopped();
+        }
+    }
 
 
     if (is_blocked()) {
     if (is_blocked()) {
         ScopedSpinLock lock(m_lock);
         ScopedSpinLock lock(m_lock);
@@ -428,6 +442,20 @@ static void push_value_on_user_stack(u32* stack, u32 data)
     copy_to_user((u32*)*stack, &data);
     copy_to_user((u32*)*stack, &data);
 }
 }
 
 
+void Thread::resume_from_stopped()
+{
+    ASSERT(is_stopped());
+    ASSERT(m_stop_state != State::Invalid);
+    set_state(m_stop_state);
+    m_stop_state = State::Invalid;
+    // make sure SemiPermanentBlocker is unblocked
+    if (m_state != Thread::Runnable && m_state != Thread::Running) {
+        ScopedSpinLock lock(m_lock);
+        if (m_blocker && m_blocker->is_reason_signal())
+            unblock();
+    }
+}
+
 ShouldUnblockThread Thread::dispatch_signal(u8 signal)
 ShouldUnblockThread Thread::dispatch_signal(u8 signal)
 {
 {
     ASSERT_INTERRUPTS_DISABLED();
     ASSERT_INTERRUPTS_DISABLED();
@@ -455,18 +483,8 @@ ShouldUnblockThread Thread::dispatch_signal(u8 signal)
     }
     }
 
 
     if (signal == SIGCONT && is_stopped()) {
     if (signal == SIGCONT && is_stopped()) {
-        ASSERT(m_stop_state != State::Invalid);
-        set_state(m_stop_state);
-        m_stop_state = State::Invalid;
-        // make sure SemiPermanentBlocker is unblocked
-        if (m_state != Thread::Runnable && m_state != Thread::Running) {
-            ScopedSpinLock lock(m_lock);
-            if (m_blocker && m_blocker->is_reason_signal())
-                unblock();
-        }
-    }
-
-    else {
+        resume_from_stopped();
+    } else {
         auto* thread_tracer = tracer();
         auto* thread_tracer = tracer();
         if (thread_tracer != nullptr) {
         if (thread_tracer != nullptr) {
             // when a thread is traced, it should be stopped whenever it receives a signal
             // when a thread is traced, it should be stopped whenever it receives a signal

+ 2 - 0
Kernel/Thread.h

@@ -270,6 +270,8 @@ public:
     void did_schedule() { ++m_times_scheduled; }
     void did_schedule() { ++m_times_scheduled; }
     u32 times_scheduled() const { return m_times_scheduled; }
     u32 times_scheduled() const { return m_times_scheduled; }
 
 
+    void resume_from_stopped();
+
     bool is_stopped() const { return m_state == Stopped; }
     bool is_stopped() const { return m_state == Stopped; }
     bool is_blocked() const { return m_state == Blocked; }
     bool is_blocked() const { return m_state == Blocked; }
     bool has_blocker() const
     bool has_blocker() const