瀏覽代碼

Kernel: Don't mark current thread as inactive after successful exec()

At the end of sys$execve(), we perform a context switch from the old
executable into the new executable.

However, the Kernel::Thread object we are switching to is the *same*
thread as the one we are switching from. So we must not assume the
from_thread and to_thread are different threads.

We had a bug caused by this misconception, where the "from" thread would
always get marked as "inactive" when switching to a new thread.
This meant that threads would always get switched into "inactive" mode
on first context switch into them.

If a thread then tried blocking on a kernel mutex within its first time
slice, we'd end up in Thread::block(Mutex&) with an inactive thread.

Once a thread is inactive, the scheduler believes it's okay to
reactivate the thread (by scheduling it.) If a thread got re-scheduled
prematurely while setting up a mutex block, things would fall apart and
we'd crash in Thread::block() due to the thread state being "Runnable"
instead of the expected "Running".
Andreas Kling 3 年之前
父節點
當前提交
cc9ed31c37
共有 1 個文件被更改,包括 5 次插入1 次删除
  1. 5 1
      Kernel/Scheduler.cpp

+ 5 - 1
Kernel/Scheduler.cpp

@@ -316,7 +316,11 @@ void Scheduler::enter_current(Thread& prev_thread)
     auto* current_thread = Thread::current();
     current_thread->update_time_scheduled(scheduler_time, true, false);
 
-    prev_thread.set_active(false);
+    // NOTE: When doing an exec(), we will context switch from and to the same thread!
+    //       In that case, we must not mark the previous thread as inactive.
+    if (&prev_thread != current_thread)
+        prev_thread.set_active(false);
+
     if (prev_thread.state() == Thread::State::Dying) {
         // If the thread we switched from is marked as dying, then notify
         // the finalizer. Note that as soon as we leave the scheduler lock