Przeglądaj źródła

Kernel: Implement Scheduler locks

Fernando Sahmkow 6 lat temu
rodzic
commit
ea956c823e
2 zmienionych plików z 89 dodań i 0 usunięć
  1. 48 0
      src/core/hle/kernel/scheduler.cpp
  2. 41 0
      src/core/hle/kernel/scheduler.h

+ 48 - 0
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

+ 41 - 0
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