@ -1,7 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-License-Identifier: GPL-2.0-or-later
# include <mutex>
# include <mutex>
# include <ranges>
# include "common/assert.h"
# include "common/assert.h"
# include "core/core.h"
# include "core/core.h"
@ -17,57 +21,61 @@ GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
GlobalSchedulerContext : : ~ GlobalSchedulerContext ( ) = default ;
GlobalSchedulerContext : : ~ GlobalSchedulerContext ( ) = default ;
void GlobalSchedulerContext : : AddThread ( KThread * thread ) {
/// @brief Adds a new thread to the scheduler
void GlobalSchedulerContext : : AddThread ( KThread * thread ) noexcept {
std : : scoped_lock lock { m_global_list_guard } ;
std : : scoped_lock lock { m_global_list_guard } ;
m_thread_list . push_back ( thread ) ;
m_thread_list . push_back ( thread ) ;
}
}
void GlobalSchedulerContext : : RemoveThread ( KThread * thread ) {
/// @brief Removes a thread from the scheduler
void GlobalSchedulerContext : : RemoveThread ( KThread * thread ) noexcept {
std : : scoped_lock lock { m_global_list_guard } ;
std : : scoped_lock lock { m_global_list_guard } ;
std : : erase ( m_thread_list , thread ) ;
m_thread_list . erase ( std : : ranges : : find ( m_thread_list , thread ) ) ;
}
}
void GlobalSchedulerContext : : PreemptThreads ( ) {
/// @brief Rotates the scheduling queues of threads at a preemption priority
/// and then does some core rebalancing. Preemption priorities can be found
/// in the array 'preemption_priorities'.
/// @note This operation happens every 10ms.
void GlobalSchedulerContext : : PreemptThreads ( ) noexcept {
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
// The priority levels at which the global scheduler preempts threads every 10 ms. They are
// ordered from Core 0 to Core 3.
// ordered from Core 0 to Core 3.
static constexpr std : : array < u32 , Core : : Hardware : : NUM_CPU_CORES > preemption_priorities {
static constexpr std : : array < u32 , Core : : Hardware : : NUM_CPU_CORES > per_core {
59 ,
59 ,
59 ,
59 ,
59 ,
59 ,
63 ,
63 ,
} ;
} ;
ASSERT ( KScheduler : : IsSchedulerLockedByCurrentThread ( m_kernel ) ) ;
ASSERT ( KScheduler : : IsSchedulerLockedByCurrentThread ( m_kernel ) ) ;
for ( u32 core_id = 0 ; core_id < Core : : Hardware : : NUM_CPU_CORES ; core_id + + ) {
const u32 priority = preemption_priorities [ core_id ] ;
KScheduler : : RotateScheduledQueue ( m_kernel , core_id , priority ) ;
}
for ( u32 core_id = 0 ; core_id < per_core . size ( ) ; core_id + + )
KScheduler : : RotateScheduledQueue ( m_kernel , core_id , per_core [ core_id ] ) ;
}
}
bool GlobalSchedulerContext : : IsLocked ( ) const {
/// @brief Returns true if the global scheduler lock is acquired
bool GlobalSchedulerContext : : IsLocked ( ) const noexcept {
return m_scheduler_lock . IsLockedByCurrentThread ( ) ;
return m_scheduler_lock . IsLockedByCurrentThread ( ) ;
}
}
void GlobalSchedulerContext : : RegisterDummyThreadForWakeup ( KThread * thread ) {
void GlobalSchedulerContext : : RegisterDummyThreadForWakeup ( KThread * thread ) noexcept {
ASSERT ( this - > IsLocked ( ) ) ;
ASSERT ( this - > IsLocked ( ) ) ;
m_woken_dummy_threads . insert ( thread ) ;
m_woken_dummy_threads . push_back ( thread ) ;
}
}
void GlobalSchedulerContext : : UnregisterDummyThreadForWakeup ( KThread * thread ) {
void GlobalSchedulerContext : : UnregisterDummyThreadForWakeup ( KThread * thread ) noexcept {
ASSERT ( this - > IsLocked ( ) ) ;
ASSERT ( this - > IsLocked ( ) ) ;
m_woken_dummy_threads . erase ( thread ) ;
if ( auto it = std : : ranges : : find ( m_woken_dummy_threads , thread ) ; it ! = m_woken_dummy_threads . end ( ) ) {
* it = m_woken_dummy_threads . back ( ) ;
m_woken_dummy_threads . pop_back ( ) ;
}
}
}
void GlobalSchedulerContext : : WakeupWaitingDummyThreads ( ) {
void GlobalSchedulerContext : : WakeupWaitingDummyThreads ( ) noexcept {
ASSERT ( this - > IsLocked ( ) ) ;
ASSERT ( this - > IsLocked ( ) ) ;
for ( auto * thread : m_woken_dummy_threads ) {
thread - > DummyThreadEndWait ( ) ;
if ( m_woken_dummy_threads . size ( ) > 0 ) {
for ( auto * thread : m_woken_dummy_threads )
thread - > DummyThreadEndWait ( ) ;
m_woken_dummy_threads . clear ( ) ;
}
}
m_woken_dummy_threads . clear ( ) ;
}
}
} // namespace Kernel
} // namespace Kernel