diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 48 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.h | 41 |
2 files changed, 89 insertions, 0 deletions
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 118c1aa95..9556df951 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 19 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
| 20 | #include "core/hle/kernel/scheduler.h" | 20 | #include "core/hle/kernel/scheduler.h" |
| 21 | #include "core/hle/kernel/time_manager.h" | ||
| 21 | 22 | ||
| 22 | namespace Kernel { | 23 | namespace Kernel { |
| 23 | 24 | ||
| @@ -356,6 +357,29 @@ void GlobalScheduler::Shutdown() { | |||
| 356 | thread_list.clear(); | 357 | thread_list.clear(); |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 360 | void GlobalScheduler::Lock() { | ||
| 361 | Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId(); | ||
| 362 | if (current_thread == current_owner) { | ||
| 363 | ++scope_lock; | ||
| 364 | } else { | ||
| 365 | inner_lock.lock(); | ||
| 366 | current_owner = current_thread; | ||
| 367 | scope_lock = 1; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | void GlobalScheduler::Unlock() { | ||
| 372 | if (--scope_lock == 0) { | ||
| 373 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | ||
| 374 | SelectThread(i); | ||
| 375 | } | ||
| 376 | current_owner = Core::EmuThreadHandle::InvalidHandle(); | ||
| 377 | scope_lock = 1; | ||
| 378 | inner_lock.unlock(); | ||
| 379 | // TODO(Blinkhawk): Setup the interrupts and change context on current core. | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 359 | Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) | 383 | Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) |
| 360 | : system(system), cpu_core(cpu_core), core_id(core_id) {} | 384 | : system(system), cpu_core(cpu_core), core_id(core_id) {} |
| 361 | 385 | ||
| @@ -485,4 +509,28 @@ void Scheduler::Shutdown() { | |||
| 485 | selected_thread = nullptr; | 509 | selected_thread = nullptr; |
| 486 | } | 510 | } |
| 487 | 511 | ||
| 512 | SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} { | ||
| 513 | auto& global_scheduler = kernel.GlobalScheduler(); | ||
| 514 | global_scheduler.Lock(); | ||
| 515 | } | ||
| 516 | |||
| 517 | SchedulerLock::~SchedulerLock() { | ||
| 518 | auto& global_scheduler = kernel.GlobalScheduler(); | ||
| 519 | global_scheduler.Unlock(); | ||
| 520 | } | ||
| 521 | |||
| 522 | SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, | ||
| 523 | Thread* time_task, s64 nanoseconds) | ||
| 524 | : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{ | ||
| 525 | nanoseconds} { | ||
| 526 | event_handle = InvalidHandle; | ||
| 527 | } | ||
| 528 | |||
| 529 | SchedulerLockAndSleep::~SchedulerLockAndSleep() { | ||
| 530 | if (!sleep_cancelled) { | ||
| 531 | auto& time_manager = kernel.TimeManager(); | ||
| 532 | time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 488 | } // namespace Kernel | 536 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 283236d4c..a779bb70f 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <mutex> | ||
| 9 | #include <vector> | 10 | #include <vector> |
| 10 | 11 | ||
| 11 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| @@ -22,6 +23,7 @@ namespace Kernel { | |||
| 22 | 23 | ||
| 23 | class KernelCore; | 24 | class KernelCore; |
| 24 | class Process; | 25 | class Process; |
| 26 | class SchedulerLock; | ||
| 25 | 27 | ||
| 26 | class GlobalScheduler final { | 28 | class GlobalScheduler final { |
| 27 | public: | 29 | public: |
| @@ -139,6 +141,14 @@ public: | |||
| 139 | void Shutdown(); | 141 | void Shutdown(); |
| 140 | 142 | ||
| 141 | private: | 143 | private: |
| 144 | friend class SchedulerLock; | ||
| 145 | |||
| 146 | /// Lock the scheduler to the current thread. | ||
| 147 | void Lock(); | ||
| 148 | |||
| 149 | /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling | ||
| 150 | /// and reschedules current core if needed. | ||
| 151 | void Unlock(); | ||
| 142 | /** | 152 | /** |
| 143 | * Transfers a thread into an specific core. If the destination_core is -1 | 153 | * Transfers a thread into an specific core. If the destination_core is -1 |
| 144 | * it will be unscheduled from its source code and added into its suggested | 154 | * it will be unscheduled from its source code and added into its suggested |
| @@ -159,6 +169,11 @@ private: | |||
| 159 | // ordered from Core 0 to Core 3. | 169 | // ordered from Core 0 to Core 3. |
| 160 | std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; | 170 | std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62}; |
| 161 | 171 | ||
| 172 | /// Scheduler lock mechanisms. | ||
| 173 | std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock | ||
| 174 | std::atomic<std::size_t> scope_lock{}; | ||
| 175 | Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; | ||
| 176 | |||
| 162 | /// Lists all thread ids that aren't deleted/etc. | 177 | /// Lists all thread ids that aren't deleted/etc. |
| 163 | std::vector<std::shared_ptr<Thread>> thread_list; | 178 | std::vector<std::shared_ptr<Thread>> thread_list; |
| 164 | KernelCore& kernel; | 179 | KernelCore& kernel; |
| @@ -228,4 +243,30 @@ private: | |||
| 228 | bool is_context_switch_pending = false; | 243 | bool is_context_switch_pending = false; |
| 229 | }; | 244 | }; |
| 230 | 245 | ||
| 246 | class SchedulerLock { | ||
| 247 | public: | ||
| 248 | SchedulerLock(KernelCore& kernel); | ||
| 249 | ~SchedulerLock(); | ||
| 250 | |||
| 251 | protected: | ||
| 252 | KernelCore& kernel; | ||
| 253 | }; | ||
| 254 | |||
| 255 | class SchedulerLockAndSleep : public SchedulerLock { | ||
| 256 | public: | ||
| 257 | SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task, | ||
| 258 | s64 nanoseconds); | ||
| 259 | ~SchedulerLockAndSleep(); | ||
| 260 | |||
| 261 | void CancelSleep() { | ||
| 262 | sleep_cancelled = true; | ||
| 263 | } | ||
| 264 | |||
| 265 | private: | ||
| 266 | Handle& event_handle; | ||
| 267 | Thread* time_task; | ||
| 268 | s64 nanoseconds; | ||
| 269 | bool sleep_cancelled{}; | ||
| 270 | }; | ||
| 271 | |||
| 231 | } // namespace Kernel | 272 | } // namespace Kernel |