1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:37:34 +00:00

Kernel: Make Thread::current smp-safe

Change Thread::current to be a static function and read using the fs
register, which eliminates a window between Processor::current()
returning and calling a function on it, which can trigger preemption
and a move to a different processor, which then causes operating
on the wrong object.
This commit is contained in:
Tom 2021-01-26 14:16:07 -07:00 committed by Andreas Kling
parent f88a8b16d7
commit 21d288a10e
5 changed files with 45 additions and 29 deletions

View file

@ -700,7 +700,7 @@ class Processor {
AK_MAKE_NONCOPYABLE(Processor);
AK_MAKE_NONMOVABLE(Processor);
Processor* m_self; // must be first field (%fs offset 0x0)
Processor* m_self;
DescriptorTablePointer m_gdtr;
Descriptor m_gdt[256];
@ -812,12 +812,12 @@ public:
ALWAYS_INLINE static Processor& current()
{
return *(Processor*)read_fs_u32(0);
return *(Processor*)read_fs_u32(__builtin_offsetof(Processor, m_self));
}
ALWAYS_INLINE static bool is_initialized()
{
return get_fs() == GDT_SELECTOR_PROC && read_fs_u32(0) != 0;
return get_fs() == GDT_SELECTOR_PROC && read_fs_u32(__builtin_offsetof(Processor, m_self)) != 0;
}
ALWAYS_INLINE void set_scheduler_data(SchedulerPerProcessorData& scheduler_data)
@ -850,16 +850,21 @@ public:
m_idle_thread = &idle_thread;
}
ALWAYS_INLINE Thread* current_thread() const
ALWAYS_INLINE static Thread* current_thread()
{
// NOTE: NOT safe to call from another processor!
ASSERT(&Processor::current() == this);
return m_current_thread;
// If we were to use Processor::current here, we'd have to
// disable interrupts to prevent a race where we may get pre-empted
// right after getting the Processor structure and then get moved
// to another processor, which would lead us to get the wrong thread.
// To avoid having to disable interrupts, we can just read the field
// directly in an atomic fashion, similar to Processor::current.
return (Thread*)read_fs_u32(__builtin_offsetof(Processor, m_current_thread));
}
ALWAYS_INLINE void set_current_thread(Thread& current_thread)
ALWAYS_INLINE static void set_current_thread(Thread& current_thread)
{
m_current_thread = &current_thread;
// See comment in Processor::current_thread
write_fs_u32(__builtin_offsetof(Processor, m_current_thread), FlatPtr(&current_thread));
}
ALWAYS_INLINE u32 id()