Skip to content

Commit bdee003

Browse files
committed
Kernel: Don't context-switch when dispatching signals in exit_trap
We shouldn't be context-switching before the very end of this function. The increment to m_in_critical is meant to prevent that, but Thread::yield_without_releasing_big_lock() (potentially called by Thread::check_dispatch_pending_signal) temporarily clears m_in_critical and forces a context-switch regardless. To avoid inadvertently context-switching, this patch adds a new argument to Thread::check_dispatch_pending_signal() which can optionally make it call Scheduler::yield() directly (which won't context switch while we're in a critical section).
1 parent b9e81af commit bdee003

File tree

3 files changed

+18
-4
lines changed

3 files changed

+18
-4
lines changed

Kernel/Arch/Processor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ void ProcessorBase::exit_trap(TrapFrame& trap)
288288
auto* current_thread = Processor::current_thread();
289289
if (current_thread) {
290290
SpinlockLocker thread_lock(current_thread->get_lock());
291-
current_thread->check_dispatch_pending_signal();
291+
current_thread->check_dispatch_pending_signal(YieldBehavior::FlagYield);
292292
}
293293

294294
// Process the deferred call queue. Among other things, this ensures

Kernel/Tasks/Thread.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ bool Thread::tick()
623623
return m_ticks_left != 0;
624624
}
625625

626-
void Thread::check_dispatch_pending_signal()
626+
void Thread::check_dispatch_pending_signal(YieldBehavior yield_behavior)
627627
{
628628
auto result = DispatchSignalResult::Continue;
629629
{
@@ -634,7 +634,16 @@ void Thread::check_dispatch_pending_signal()
634634
}
635635

636636
if (result == DispatchSignalResult::Yield) {
637-
yield_without_releasing_big_lock();
637+
switch (yield_behavior) {
638+
case YieldBehavior::DoYield:
639+
yield_without_releasing_big_lock();
640+
break;
641+
case YieldBehavior::FlagYield:
642+
// This is essentially the same as the above,
643+
// but doesn't call Processor::clear_critical().
644+
Scheduler::yield();
645+
break;
646+
}
638647
}
639648
}
640649

Kernel/Tasks/Thread.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ enum class [[nodiscard]] DispatchSignalResult {
4848
Continue
4949
};
5050

51+
enum class YieldBehavior {
52+
DoYield,
53+
FlagYield
54+
};
55+
5156
struct ThreadSpecificData {
5257
ThreadSpecificData* self;
5358
};
@@ -878,7 +883,7 @@ class Thread
878883

879884
DispatchSignalResult dispatch_one_pending_signal();
880885
DispatchSignalResult dispatch_signal(u8 signal);
881-
void check_dispatch_pending_signal();
886+
void check_dispatch_pending_signal(YieldBehavior yield_behavior = YieldBehavior::DoYield);
882887
[[nodiscard]] bool has_unmasked_pending_signals() const { return m_have_any_unmasked_pending_signals.load(AK::memory_order_consume); }
883888
[[nodiscard]] bool should_ignore_signal(u8 signal) const;
884889
[[nodiscard]] bool has_signal_handler(u8 signal) const;

0 commit comments

Comments
 (0)