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".
This commit is contained in:
Andreas Kling 2022-01-30 16:09:38 +01:00
parent a44316fa8b
commit cc9ed31c37
Notes: sideshowbarker 2024-07-17 19:59:31 +09:00

View File

@ -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