1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 23:27:43 +00:00

Kernel: Prevent recursive calls into the scheduler

Upon leaving a critical section (such as a SpinLock) we need to
check if we're already asynchronously invoking the Scheduler.
Otherwise we might end up triggering another context switch
as soon as leaving the scheduler lock.

Fixes #2883
This commit is contained in:
Tom 2020-08-01 14:37:40 -06:00 committed by Andreas Kling
parent a19304c9d6
commit 728de56481
5 changed files with 136 additions and 21 deletions

View file

@ -623,6 +623,7 @@ static_assert(GDT_SELECTOR_CODE0 + 16 == GDT_SELECTOR_CODE3); // CS3 = CS0 + 16
static_assert(GDT_SELECTOR_CODE0 + 24 == GDT_SELECTOR_DATA3); // SS3 = CS0 + 32
class ProcessorInfo;
class SchedulerPerProcessorData;
struct MemoryManagerData;
struct ProcessorMessageEntry;
@ -683,6 +684,7 @@ class Processor {
ProcessorInfo* m_info;
MemoryManagerData* m_mm_data;
SchedulerPerProcessorData* m_scheduler_data;
Thread* m_current_thread;
Thread* m_idle_thread;
@ -770,6 +772,16 @@ public:
return get_fs() == GDT_SELECTOR_PROC && read_fs_u32(0) != 0;
}
ALWAYS_INLINE void set_scheduler_data(SchedulerPerProcessorData& scheduler_data)
{
m_scheduler_data = &scheduler_data;
}
ALWAYS_INLINE SchedulerPerProcessorData& get_scheduler_data() const
{
return *m_scheduler_data;
}
ALWAYS_INLINE void set_mm_data(MemoryManagerData& mm_data)
{
m_mm_data = &mm_data;
@ -920,16 +932,13 @@ class ScopedCritical {
public:
ScopedCritical()
{
m_valid = true;
Processor::current().enter_critical(m_prev_flags);
enter();
}
~ScopedCritical()
{
if (m_valid) {
m_valid = false;
Processor::current().leave_critical(m_prev_flags);
}
if (m_valid)
leave();
}
ScopedCritical(ScopedCritical&& from)
@ -955,6 +964,20 @@ public:
m_prev_flags &= ~0x200;
}
void leave()
{
ASSERT(m_valid);
m_valid = false;
Processor::current().leave_critical(m_prev_flags);
}
void enter()
{
ASSERT(!m_valid);
m_valid = true;
Processor::current().enter_critical(m_prev_flags);
}
private:
u32 m_prev_flags { 0 };
bool m_valid { false };