summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/kernel/scheduler.cpp48
-rw-r--r--src/core/hle/kernel/scheduler.h41
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 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/time_manager.h"
namespace Kernel {
@@ -356,6 +357,29 @@ void GlobalScheduler::Shutdown() {
thread_list.clear();
}
+void GlobalScheduler::Lock() {
+ Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadId();
+ if (current_thread == current_owner) {
+ ++scope_lock;
+ } else {
+ inner_lock.lock();
+ current_owner = current_thread;
+ scope_lock = 1;
+ }
+}
+
+void GlobalScheduler::Unlock() {
+ if (--scope_lock == 0) {
+ for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
+ SelectThread(i);
+ }
+ current_owner = Core::EmuThreadHandle::InvalidHandle();
+ scope_lock = 1;
+ inner_lock.unlock();
+ // TODO(Blinkhawk): Setup the interrupts and change context on current core.
+ }
+}
+
Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id)
: system(system), cpu_core(cpu_core), core_id(core_id) {}
@@ -485,4 +509,28 @@ void Scheduler::Shutdown() {
selected_thread = nullptr;
}
+SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
+ auto& global_scheduler = kernel.GlobalScheduler();
+ global_scheduler.Lock();
+}
+
+SchedulerLock::~SchedulerLock() {
+ auto& global_scheduler = kernel.GlobalScheduler();
+ global_scheduler.Unlock();
+}
+
+SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
+ Thread* time_task, s64 nanoseconds)
+ : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
+ nanoseconds} {
+ event_handle = InvalidHandle;
+}
+
+SchedulerLockAndSleep::~SchedulerLockAndSleep() {
+ if (!sleep_cancelled) {
+ auto& time_manager = kernel.TimeManager();
+ time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
+ }
+}
+
} // 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 @@
#include <atomic>
#include <memory>
+#include <mutex>
#include <vector>
#include "common/common_types.h"
@@ -22,6 +23,7 @@ namespace Kernel {
class KernelCore;
class Process;
+class SchedulerLock;
class GlobalScheduler final {
public:
@@ -139,6 +141,14 @@ public:
void Shutdown();
private:
+ friend class SchedulerLock;
+
+ /// Lock the scheduler to the current thread.
+ void Lock();
+
+ /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
+ /// and reschedules current core if needed.
+ void Unlock();
/**
* Transfers a thread into an specific core. If the destination_core is -1
* it will be unscheduled from its source code and added into its suggested
@@ -159,6 +169,11 @@ private:
// ordered from Core 0 to Core 3.
std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 62};
+ /// Scheduler lock mechanisms.
+ std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock
+ std::atomic<std::size_t> scope_lock{};
+ Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
+
/// Lists all thread ids that aren't deleted/etc.
std::vector<std::shared_ptr<Thread>> thread_list;
KernelCore& kernel;
@@ -228,4 +243,30 @@ private:
bool is_context_switch_pending = false;
};
+class SchedulerLock {
+public:
+ SchedulerLock(KernelCore& kernel);
+ ~SchedulerLock();
+
+protected:
+ KernelCore& kernel;
+};
+
+class SchedulerLockAndSleep : public SchedulerLock {
+public:
+ SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
+ s64 nanoseconds);
+ ~SchedulerLockAndSleep();
+
+ void CancelSleep() {
+ sleep_cancelled = true;
+ }
+
+private:
+ Handle& event_handle;
+ Thread* time_task;
+ s64 nanoseconds;
+ bool sleep_cancelled{};
+};
+
} // namespace Kernel