Repository: SerenityOS/serenity
File: Kernel/Tasks/Thread.cpp (C++)

Code before:
        ++m_process->m_ticks_in_user;
        ++m_ticks_in_user;
    }
    --m_ticks_left;
    return m_ticks_left != 0;
}

void Thread::check_dispatch_pending_signal(YieldBehavior yield_behavior)
{
    auto result = DispatchSignalResult::Continue;
    {
        SpinlockLocker scheduler_lock(g_scheduler_lock);
        if (pending_signals_for_state() != 0) {
            result = dispatch_one_pending_signal();
        }
    }

    if (result == DispatchSignalResult::Yield) {
        switch (yield_behavior) {
        case YieldBehavior::DoYield:
            yield_without_releasing_big_lock();
            break;
        case YieldBehavior::FlagYield:
            // This is essentially the same as the above,
            // but doesn't call Processor::clear_critical().
            Scheduler::yield();
            break;
        }
    }
}

u32 Thread::pending_signals() const
{
    SpinlockLocker lock(g_scheduler_lock);
    return pending_signals_for_state();
}

u32 Thread::pending_signals_for_state() const
{
    VERIFY(g_scheduler_lock.is_locked_by_current_processor());
    constexpr u32 stopped_signal_mask = (1 << (SIGCONT - 1)) | (1 << (SIGKILL - 1)) | (1 << (SIGTRAP - 1));
    if (is_handling_page_fault())
        return 0;
    return m_state != State::Stopped ? m_pending_signals : m_pending_signals & stopped_signal_mask;
}

void Thread::send_signal(u8 signal, [[maybe_unused]] Process* sender)
{
    VERIFY(signal < NSIG);
    VERIFY(process().is_user_process());
    SpinlockLocker scheduler_lock(g_scheduler_lock);

Review comment (suggestion):
Shouldn't using `invoke_scheduler_async` be more appropriate?

Otherwise the `YieldBehaviour` enum names are not quite fitting, since `FlagYield` does actually yield if not inside a critical section.

Code after:
        ++m_process->m_ticks_in_user;
        ++m_ticks_in_user;
    }
    --m_ticks_left;
    return m_ticks_left != 0;
}

void Thread::check_dispatch_pending_signal(YieldBehavior yield_behavior)
{
    auto result = DispatchSignalResult::Continue;
    {
        SpinlockLocker scheduler_lock(g_scheduler_lock);
        if (pending_signals_for_state() != 0) {
            result = dispatch_one_pending_signal();
        }
    }

    if (result == DispatchSignalResult::Yield) {
        switch (yield_behavior) {
        case YieldBehavior::DoYield:
            yield_without_releasing_big_lock();
            break;
        case YieldBehavior::FlagYield:
            VERIFY_INTERRUPTS_DISABLED();
            Processor::current().invoke_scheduler_async();
            break;
        }
    }
}

u32 Thread::pending_signals() const
{
    SpinlockLocker lock(g_scheduler_lock);
    return pending_signals_for_state();
}

u32 Thread::pending_signals_for_state() const
{
    VERIFY(g_scheduler_lock.is_locked_by_current_processor());
    constexpr u32 stopped_signal_mask = (1 << (SIGCONT - 1)) | (1 << (SIGKILL - 1)) | (1 << (SIGTRAP - 1));
    if (is_handling_page_fault())
        return 0;
    return m_state != State::Stopped ? m_pending_signals : m_pending_signals & stopped_signal_mask;
}

void Thread::send_signal(u8 signal, [[maybe_unused]] Process* sender)
{
    VERIFY(signal < NSIG);
    VERIFY(process().is_user_process());
    SpinlockLocker scheduler_lock(g_scheduler_lock);