summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp8
-rw-r--r--src/core/core.h6
-rw-r--r--src/core/hardware_properties.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp121
-rw-r--r--src/core/hle/kernel/kernel.h37
-rw-r--r--src/core/hle/kernel/scheduler.cpp56
-rw-r--r--src/core/hle/kernel/scheduler.h46
-rw-r--r--src/core/hle/kernel/thread.cpp12
-rw-r--r--src/core/hle/kernel/thread.h6
-rw-r--r--src/core/hle/kernel/time_manager.cpp44
-rw-r--r--src/core/hle/kernel/time_manager.h43
12 files changed, 349 insertions, 34 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 26612e692..88c06b2ce 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -187,6 +187,8 @@ add_library(core STATIC
187 hle/kernel/synchronization.h 187 hle/kernel/synchronization.h
188 hle/kernel/thread.cpp 188 hle/kernel/thread.cpp
189 hle/kernel/thread.h 189 hle/kernel/thread.h
190 hle/kernel/time_manager.cpp
191 hle/kernel/time_manager.h
190 hle/kernel/transfer_memory.cpp 192 hle/kernel/transfer_memory.cpp
191 hle/kernel/transfer_memory.h 193 hle/kernel/transfer_memory.h
192 hle/kernel/vm_manager.cpp 194 hle/kernel/vm_manager.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0eb0c0dca..86e314c94 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -707,4 +707,12 @@ const Service::SM::ServiceManager& System::ServiceManager() const {
707 return *impl->service_manager; 707 return *impl->service_manager;
708} 708}
709 709
710void System::RegisterCoreThread(std::size_t id) {
711 impl->kernel.RegisterCoreThread(id);
712}
713
714void System::RegisterHostThread() {
715 impl->kernel.RegisterHostThread();
716}
717
710} // namespace Core 718} // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index e69d68fcf..8d862a8e6 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -360,6 +360,12 @@ public:
360 360
361 const CurrentBuildProcessID& GetCurrentProcessBuildID() const; 361 const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
362 362
363 /// Register a host thread as an emulated CPU Core.
364 void RegisterCoreThread(std::size_t id);
365
366 /// Register a host thread as an auxiliary thread.
367 void RegisterHostThread();
368
363private: 369private:
364 System(); 370 System();
365 371
diff --git a/src/core/hardware_properties.h b/src/core/hardware_properties.h
index 213461b6a..b04e046ed 100644
--- a/src/core/hardware_properties.h
+++ b/src/core/hardware_properties.h
@@ -20,6 +20,8 @@ constexpr u32 NUM_CPU_CORES = 4; // Number of CPU Cores
20 20
21} // namespace Hardware 21} // namespace Hardware
22 22
23constexpr u32 INVALID_HOST_THREAD_ID = 0xFFFFFFFF;
24
23struct EmuThreadHandle { 25struct EmuThreadHandle {
24 u32 host_handle; 26 u32 host_handle;
25 u32 guest_handle; 27 u32 guest_handle;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4eb1d8703..9232f4d7e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,9 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <atomic> 5#include <atomic>
6#include <bitset>
6#include <functional> 7#include <functional>
7#include <memory> 8#include <memory>
8#include <mutex> 9#include <mutex>
10#include <thread>
11#include <unordered_map>
9#include <utility> 12#include <utility>
10 13
11#include "common/assert.h" 14#include "common/assert.h"
@@ -15,6 +18,7 @@
15#include "core/core.h" 18#include "core/core.h"
16#include "core/core_timing.h" 19#include "core/core_timing.h"
17#include "core/core_timing_util.h" 20#include "core/core_timing_util.h"
21#include "core/hardware_properties.h"
18#include "core/hle/kernel/client_port.h" 22#include "core/hle/kernel/client_port.h"
19#include "core/hle/kernel/errors.h" 23#include "core/hle/kernel/errors.h"
20#include "core/hle/kernel/handle_table.h" 24#include "core/hle/kernel/handle_table.h"
@@ -25,6 +29,7 @@
25#include "core/hle/kernel/scheduler.h" 29#include "core/hle/kernel/scheduler.h"
26#include "core/hle/kernel/synchronization.h" 30#include "core/hle/kernel/synchronization.h"
27#include "core/hle/kernel/thread.h" 31#include "core/hle/kernel/thread.h"
32#include "core/hle/kernel/time_manager.h"
28#include "core/hle/lock.h" 33#include "core/hle/lock.h"
29#include "core/hle/result.h" 34#include "core/hle/result.h"
30#include "core/memory.h" 35#include "core/memory.h"
@@ -44,7 +49,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
44 std::lock_guard lock{HLE::g_hle_lock}; 49 std::lock_guard lock{HLE::g_hle_lock};
45 50
46 std::shared_ptr<Thread> thread = 51 std::shared_ptr<Thread> thread =
47 system.Kernel().RetrieveThreadFromWakeupCallbackHandleTable(proper_handle); 52 system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
48 if (thread == nullptr) { 53 if (thread == nullptr) {
49 LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); 54 LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
50 return; 55 return;
@@ -97,8 +102,8 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_
97} 102}
98 103
99struct KernelCore::Impl { 104struct KernelCore::Impl {
100 explicit Impl(Core::System& system) 105 explicit Impl(Core::System& system, KernelCore& kernel)
101 : system{system}, global_scheduler{system}, synchronization{system} {} 106 : system{system}, global_scheduler{kernel}, synchronization{system}, time_manager{system} {}
102 107
103 void Initialize(KernelCore& kernel) { 108 void Initialize(KernelCore& kernel) {
104 Shutdown(); 109 Shutdown();
@@ -120,7 +125,7 @@ struct KernelCore::Impl {
120 125
121 system_resource_limit = nullptr; 126 system_resource_limit = nullptr;
122 127
123 thread_wakeup_callback_handle_table.Clear(); 128 global_handle_table.Clear();
124 thread_wakeup_event_type = nullptr; 129 thread_wakeup_event_type = nullptr;
125 preemption_event = nullptr; 130 preemption_event = nullptr;
126 131
@@ -138,8 +143,8 @@ struct KernelCore::Impl {
138 143
139 void InitializePhysicalCores() { 144 void InitializePhysicalCores() {
140 exclusive_monitor = 145 exclusive_monitor =
141 Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); 146 Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES);
142 for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { 147 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
143 cores.emplace_back(system, i, *exclusive_monitor); 148 cores.emplace_back(system, i, *exclusive_monitor);
144 } 149 }
145 } 150 }
@@ -184,6 +189,50 @@ struct KernelCore::Impl {
184 system.Memory().SetCurrentPageTable(*process); 189 system.Memory().SetCurrentPageTable(*process);
185 } 190 }
186 191
192 void RegisterCoreThread(std::size_t core_id) {
193 std::unique_lock lock{register_thread_mutex};
194 const std::thread::id this_id = std::this_thread::get_id();
195 const auto it = host_thread_ids.find(this_id);
196 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
197 ASSERT(it == host_thread_ids.end());
198 ASSERT(!registered_core_threads[core_id]);
199 host_thread_ids[this_id] = static_cast<u32>(core_id);
200 registered_core_threads.set(core_id);
201 }
202
203 void RegisterHostThread() {
204 std::unique_lock lock{register_thread_mutex};
205 const std::thread::id this_id = std::this_thread::get_id();
206 const auto it = host_thread_ids.find(this_id);
207 ASSERT(it == host_thread_ids.end());
208 host_thread_ids[this_id] = registered_thread_ids++;
209 }
210
211 u32 GetCurrentHostThreadID() const {
212 const std::thread::id this_id = std::this_thread::get_id();
213 const auto it = host_thread_ids.find(this_id);
214 if (it == host_thread_ids.end()) {
215 return Core::INVALID_HOST_THREAD_ID;
216 }
217 return it->second;
218 }
219
220 Core::EmuThreadHandle GetCurrentEmuThreadID() const {
221 Core::EmuThreadHandle result = Core::EmuThreadHandle::InvalidHandle();
222 result.host_handle = GetCurrentHostThreadID();
223 if (result.host_handle >= Core::Hardware::NUM_CPU_CORES) {
224 return result;
225 }
226 const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler();
227 const Kernel::Thread* current = sched.GetCurrentThread();
228 if (current != nullptr) {
229 result.guest_handle = current->GetGlobalHandle();
230 } else {
231 result.guest_handle = InvalidHandle;
232 }
233 return result;
234 }
235
187 std::atomic<u32> next_object_id{0}; 236 std::atomic<u32> next_object_id{0};
188 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin}; 237 std::atomic<u64> next_kernel_process_id{Process::InitialKIPIDMin};
189 std::atomic<u64> next_user_process_id{Process::ProcessIDMin}; 238 std::atomic<u64> next_user_process_id{Process::ProcessIDMin};
@@ -194,15 +243,16 @@ struct KernelCore::Impl {
194 Process* current_process = nullptr; 243 Process* current_process = nullptr;
195 Kernel::GlobalScheduler global_scheduler; 244 Kernel::GlobalScheduler global_scheduler;
196 Kernel::Synchronization synchronization; 245 Kernel::Synchronization synchronization;
246 Kernel::TimeManager time_manager;
197 247
198 std::shared_ptr<ResourceLimit> system_resource_limit; 248 std::shared_ptr<ResourceLimit> system_resource_limit;
199 249
200 std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type; 250 std::shared_ptr<Core::Timing::EventType> thread_wakeup_event_type;
201 std::shared_ptr<Core::Timing::EventType> preemption_event; 251 std::shared_ptr<Core::Timing::EventType> preemption_event;
202 252
203 // TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, 253 // This is the kernel's handle table or supervisor handle table which
204 // allowing us to simply use a pool index or similar. 254 // stores all the objects in place.
205 Kernel::HandleTable thread_wakeup_callback_handle_table; 255 Kernel::HandleTable global_handle_table;
206 256
207 /// Map of named ports managed by the kernel, which can be retrieved using 257 /// Map of named ports managed by the kernel, which can be retrieved using
208 /// the ConnectToPort SVC. 258 /// the ConnectToPort SVC.
@@ -211,11 +261,17 @@ struct KernelCore::Impl {
211 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 261 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
212 std::vector<Kernel::PhysicalCore> cores; 262 std::vector<Kernel::PhysicalCore> cores;
213 263
264 // 0-3 IDs represent core threads, >3 represent others
265 std::unordered_map<std::thread::id, u32> host_thread_ids;
266 u32 registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
267 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
268 std::mutex register_thread_mutex;
269
214 // System context 270 // System context
215 Core::System& system; 271 Core::System& system;
216}; 272};
217 273
218KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system)} {} 274KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
219KernelCore::~KernelCore() { 275KernelCore::~KernelCore() {
220 Shutdown(); 276 Shutdown();
221} 277}
@@ -232,9 +288,8 @@ std::shared_ptr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
232 return impl->system_resource_limit; 288 return impl->system_resource_limit;
233} 289}
234 290
235std::shared_ptr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable( 291std::shared_ptr<Thread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
236 Handle handle) const { 292 return impl->global_handle_table.Get<Thread>(handle);
237 return impl->thread_wakeup_callback_handle_table.Get<Thread>(handle);
238} 293}
239 294
240void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) { 295void KernelCore::AppendNewProcess(std::shared_ptr<Process> process) {
@@ -265,6 +320,14 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
265 return impl->global_scheduler; 320 return impl->global_scheduler;
266} 321}
267 322
323Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) {
324 return impl->cores[id].Scheduler();
325}
326
327const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const {
328 return impl->cores[id].Scheduler();
329}
330
268Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { 331Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
269 return impl->cores[id]; 332 return impl->cores[id];
270} 333}
@@ -281,6 +344,14 @@ const Kernel::Synchronization& KernelCore::Synchronization() const {
281 return impl->synchronization; 344 return impl->synchronization;
282} 345}
283 346
347Kernel::TimeManager& KernelCore::TimeManager() {
348 return impl->time_manager;
349}
350
351const Kernel::TimeManager& KernelCore::TimeManager() const {
352 return impl->time_manager;
353}
354
284Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { 355Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
285 return *impl->exclusive_monitor; 356 return *impl->exclusive_monitor;
286} 357}
@@ -338,12 +409,28 @@ const std::shared_ptr<Core::Timing::EventType>& KernelCore::ThreadWakeupCallback
338 return impl->thread_wakeup_event_type; 409 return impl->thread_wakeup_event_type;
339} 410}
340 411
341Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() { 412Kernel::HandleTable& KernelCore::GlobalHandleTable() {
342 return impl->thread_wakeup_callback_handle_table; 413 return impl->global_handle_table;
414}
415
416const Kernel::HandleTable& KernelCore::GlobalHandleTable() const {
417 return impl->global_handle_table;
418}
419
420void KernelCore::RegisterCoreThread(std::size_t core_id) {
421 impl->RegisterCoreThread(core_id);
422}
423
424void KernelCore::RegisterHostThread() {
425 impl->RegisterHostThread();
426}
427
428u32 KernelCore::GetCurrentHostThreadID() const {
429 return impl->GetCurrentHostThreadID();
343} 430}
344 431
345const Kernel::HandleTable& KernelCore::ThreadWakeupCallbackHandleTable() const { 432Core::EmuThreadHandle KernelCore::GetCurrentEmuThreadID() const {
346 return impl->thread_wakeup_callback_handle_table; 433 return impl->GetCurrentEmuThreadID();
347} 434}
348 435
349} // namespace Kernel 436} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 1eede3063..c4f78ab71 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,6 +11,7 @@
11#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/object.h"
12 12
13namespace Core { 13namespace Core {
14struct EmuThreadHandle;
14class ExclusiveMonitor; 15class ExclusiveMonitor;
15class System; 16class System;
16} // namespace Core 17} // namespace Core
@@ -29,8 +30,10 @@ class HandleTable;
29class PhysicalCore; 30class PhysicalCore;
30class Process; 31class Process;
31class ResourceLimit; 32class ResourceLimit;
33class Scheduler;
32class Synchronization; 34class Synchronization;
33class Thread; 35class Thread;
36class TimeManager;
34 37
35/// Represents a single instance of the kernel. 38/// Represents a single instance of the kernel.
36class KernelCore { 39class KernelCore {
@@ -64,7 +67,7 @@ public:
64 std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const; 67 std::shared_ptr<ResourceLimit> GetSystemResourceLimit() const;
65 68
66 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. 69 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
67 std::shared_ptr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; 70 std::shared_ptr<Thread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
68 71
69 /// Adds the given shared pointer to an internal list of active processes. 72 /// Adds the given shared pointer to an internal list of active processes.
70 void AppendNewProcess(std::shared_ptr<Process> process); 73 void AppendNewProcess(std::shared_ptr<Process> process);
@@ -87,6 +90,12 @@ public:
87 /// Gets the sole instance of the global scheduler 90 /// Gets the sole instance of the global scheduler
88 const Kernel::GlobalScheduler& GlobalScheduler() const; 91 const Kernel::GlobalScheduler& GlobalScheduler() const;
89 92
93 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
94 Kernel::Scheduler& Scheduler(std::size_t id);
95
96 /// Gets the sole instance of the Scheduler assoviated with cpu core 'id'
97 const Kernel::Scheduler& Scheduler(std::size_t id) const;
98
90 /// Gets the an instance of the respective physical CPU core. 99 /// Gets the an instance of the respective physical CPU core.
91 Kernel::PhysicalCore& PhysicalCore(std::size_t id); 100 Kernel::PhysicalCore& PhysicalCore(std::size_t id);
92 101
@@ -99,6 +108,12 @@ public:
99 /// Gets the an instance of the Synchronization Interface. 108 /// Gets the an instance of the Synchronization Interface.
100 const Kernel::Synchronization& Synchronization() const; 109 const Kernel::Synchronization& Synchronization() const;
101 110
111 /// Gets the an instance of the TimeManager Interface.
112 Kernel::TimeManager& TimeManager();
113
114 /// Gets the an instance of the TimeManager Interface.
115 const Kernel::TimeManager& TimeManager() const;
116
102 /// Stops execution of 'id' core, in order to reschedule a new thread. 117 /// Stops execution of 'id' core, in order to reschedule a new thread.
103 void PrepareReschedule(std::size_t id); 118 void PrepareReschedule(std::size_t id);
104 119
@@ -120,6 +135,18 @@ public:
120 /// Determines whether or not the given port is a valid named port. 135 /// Determines whether or not the given port is a valid named port.
121 bool IsValidNamedPort(NamedPortTable::const_iterator port) const; 136 bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
122 137
138 /// Gets the current host_thread/guest_thread handle.
139 Core::EmuThreadHandle GetCurrentEmuThreadID() const;
140
141 /// Gets the current host_thread handle.
142 u32 GetCurrentHostThreadID() const;
143
144 /// Register the current thread as a CPU Core Thread.
145 void RegisterCoreThread(std::size_t core_id);
146
147 /// Register the current thread as a non CPU core thread.
148 void RegisterHostThread();
149
123private: 150private:
124 friend class Object; 151 friend class Object;
125 friend class Process; 152 friend class Process;
@@ -140,11 +167,11 @@ private:
140 /// Retrieves the event type used for thread wakeup callbacks. 167 /// Retrieves the event type used for thread wakeup callbacks.
141 const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const; 168 const std::shared_ptr<Core::Timing::EventType>& ThreadWakeupCallbackEventType() const;
142 169
143 /// Provides a reference to the thread wakeup callback handle table. 170 /// Provides a reference to the global handle table.
144 Kernel::HandleTable& ThreadWakeupCallbackHandleTable(); 171 Kernel::HandleTable& GlobalHandleTable();
145 172
146 /// Provides a const reference to the thread wakeup callback handle table. 173 /// Provides a const reference to the global handle table.
147 const Kernel::HandleTable& ThreadWakeupCallbackHandleTable() const; 174 const Kernel::HandleTable& GlobalHandleTable() const;
148 175
149 struct Impl; 176 struct Impl;
150 std::unique_ptr<Impl> impl; 177 std::unique_ptr<Impl> impl;
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 86f1421bf..c65f82fb7 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -18,10 +18,11 @@
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
22namespace Kernel { 23namespace Kernel {
23 24
24GlobalScheduler::GlobalScheduler(Core::System& system) : system{system} {} 25GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {}
25 26
26GlobalScheduler::~GlobalScheduler() = default; 27GlobalScheduler::~GlobalScheduler() = default;
27 28
@@ -35,7 +36,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr<Thread> thread) {
35} 36}
36 37
37void GlobalScheduler::UnloadThread(std::size_t core) { 38void GlobalScheduler::UnloadThread(std::size_t core) {
38 Scheduler& sched = system.Scheduler(core); 39 Scheduler& sched = kernel.Scheduler(core);
39 sched.UnloadThread(); 40 sched.UnloadThread();
40} 41}
41 42
@@ -50,7 +51,7 @@ void GlobalScheduler::SelectThread(std::size_t core) {
50 sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; 51 sched.is_context_switch_pending = sched.selected_thread != sched.current_thread;
51 std::atomic_thread_fence(std::memory_order_seq_cst); 52 std::atomic_thread_fence(std::memory_order_seq_cst);
52 }; 53 };
53 Scheduler& sched = system.Scheduler(core); 54 Scheduler& sched = kernel.Scheduler(core);
54 Thread* current_thread = nullptr; 55 Thread* current_thread = nullptr;
55 // Step 1: Get top thread in schedule queue. 56 // Step 1: Get top thread in schedule queue.
56 current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); 57 current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front();
@@ -356,6 +357,32 @@ void GlobalScheduler::Shutdown() {
356 thread_list.clear(); 357 thread_list.clear();
357} 358}
358 359
360void 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 ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle());
368 scope_lock = 1;
369 }
370}
371
372void GlobalScheduler::Unlock() {
373 if (--scope_lock != 0) {
374 ASSERT(scope_lock > 0);
375 return;
376 }
377 for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
378 SelectThread(i);
379 }
380 current_owner = Core::EmuThreadHandle::InvalidHandle();
381 scope_lock = 1;
382 inner_lock.unlock();
383 // TODO(Blinkhawk): Setup the interrupts and change context on current core.
384}
385
359Scheduler::Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, std::size_t core_id) 386Scheduler::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) {} 387 : system(system), cpu_core(cpu_core), core_id(core_id) {}
361 388
@@ -485,4 +512,27 @@ void Scheduler::Shutdown() {
485 selected_thread = nullptr; 512 selected_thread = nullptr;
486} 513}
487 514
515SchedulerLock::SchedulerLock(KernelCore& kernel) : kernel{kernel} {
516 kernel.GlobalScheduler().Lock();
517}
518
519SchedulerLock::~SchedulerLock() {
520 kernel.GlobalScheduler().Unlock();
521}
522
523SchedulerLockAndSleep::SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle,
524 Thread* time_task, s64 nanoseconds)
525 : SchedulerLock{kernel}, event_handle{event_handle}, time_task{time_task}, nanoseconds{
526 nanoseconds} {
527 event_handle = InvalidHandle;
528}
529
530SchedulerLockAndSleep::~SchedulerLockAndSleep() {
531 if (sleep_cancelled) {
532 return;
533 }
534 auto& time_manager = kernel.TimeManager();
535 time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds);
536}
537
488} // namespace Kernel 538} // namespace Kernel
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 96db049cb..1c93a838c 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"
@@ -20,11 +21,13 @@ class System;
20 21
21namespace Kernel { 22namespace Kernel {
22 23
24class KernelCore;
23class Process; 25class Process;
26class SchedulerLock;
24 27
25class GlobalScheduler final { 28class GlobalScheduler final {
26public: 29public:
27 explicit GlobalScheduler(Core::System& system); 30 explicit GlobalScheduler(KernelCore& kernel);
28 ~GlobalScheduler(); 31 ~GlobalScheduler();
29 32
30 /// Adds a new thread to the scheduler 33 /// Adds a new thread to the scheduler
@@ -138,6 +141,14 @@ public:
138 void Shutdown(); 141 void Shutdown();
139 142
140private: 143private:
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();
141 /** 152 /**
142 * 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
143 * 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
@@ -158,9 +169,14 @@ private:
158 // ordered from Core 0 to Core 3. 169 // ordered from Core 0 to Core 3.
159 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};
160 171
172 /// Scheduler lock mechanisms.
173 std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock
174 std::atomic<s64> scope_lock{};
175 Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()};
176
161 /// Lists all thread ids that aren't deleted/etc. 177 /// Lists all thread ids that aren't deleted/etc.
162 std::vector<std::shared_ptr<Thread>> thread_list; 178 std::vector<std::shared_ptr<Thread>> thread_list;
163 Core::System& system; 179 KernelCore& kernel;
164}; 180};
165 181
166class Scheduler final { 182class Scheduler final {
@@ -227,4 +243,30 @@ private:
227 bool is_context_switch_pending = false; 243 bool is_context_switch_pending = false;
228}; 244};
229 245
246class SchedulerLock {
247public:
248 explicit SchedulerLock(KernelCore& kernel);
249 ~SchedulerLock();
250
251protected:
252 KernelCore& kernel;
253};
254
255class SchedulerLockAndSleep : public SchedulerLock {
256public:
257 explicit SchedulerLockAndSleep(KernelCore& kernel, Handle& event_handle, Thread* time_task,
258 s64 nanoseconds);
259 ~SchedulerLockAndSleep();
260
261 void CancelSleep() {
262 sleep_cancelled = true;
263 }
264
265private:
266 Handle& event_handle;
267 Thread* time_task;
268 s64 nanoseconds;
269 bool sleep_cancelled{};
270};
271
230} // namespace Kernel 272} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ae5f2c8bd..bf850e0b2 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -46,9 +46,9 @@ Thread::~Thread() = default;
46void Thread::Stop() { 46void Thread::Stop() {
47 // Cancel any outstanding wakeup events for this thread 47 // Cancel any outstanding wakeup events for this thread
48 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), 48 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
49 callback_handle); 49 global_handle);
50 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle); 50 kernel.GlobalHandleTable().Close(global_handle);
51 callback_handle = 0; 51 global_handle = 0;
52 SetStatus(ThreadStatus::Dead); 52 SetStatus(ThreadStatus::Dead);
53 Signal(); 53 Signal();
54 54
@@ -73,12 +73,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
73 // thread-safe version of ScheduleEvent. 73 // thread-safe version of ScheduleEvent.
74 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); 74 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
75 Core::System::GetInstance().CoreTiming().ScheduleEvent( 75 Core::System::GetInstance().CoreTiming().ScheduleEvent(
76 cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle); 76 cycles, kernel.ThreadWakeupCallbackEventType(), global_handle);
77} 77}
78 78
79void Thread::CancelWakeupTimer() { 79void Thread::CancelWakeupTimer() {
80 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), 80 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
81 callback_handle); 81 global_handle);
82} 82}
83 83
84void Thread::ResumeFromWait() { 84void Thread::ResumeFromWait() {
@@ -190,7 +190,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
190 thread->condvar_wait_address = 0; 190 thread->condvar_wait_address = 0;
191 thread->wait_handle = 0; 191 thread->wait_handle = 0;
192 thread->name = std::move(name); 192 thread->name = std::move(name);
193 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); 193 thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
194 thread->owner_process = &owner_process; 194 thread->owner_process = &owner_process;
195 auto& scheduler = kernel.GlobalScheduler(); 195 auto& scheduler = kernel.GlobalScheduler();
196 scheduler.AddThread(thread); 196 scheduler.AddThread(thread);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7a4916318..129e7858a 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -453,6 +453,10 @@ public:
453 is_sync_cancelled = value; 453 is_sync_cancelled = value;
454 } 454 }
455 455
456 Handle GetGlobalHandle() const {
457 return global_handle;
458 }
459
456private: 460private:
457 void SetSchedulingStatus(ThreadSchedStatus new_status); 461 void SetSchedulingStatus(ThreadSchedStatus new_status);
458 void SetCurrentPriority(u32 new_priority); 462 void SetCurrentPriority(u32 new_priority);
@@ -514,7 +518,7 @@ private:
514 VAddr arb_wait_address{0}; 518 VAddr arb_wait_address{0};
515 519
516 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. 520 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
517 Handle callback_handle = 0; 521 Handle global_handle = 0;
518 522
519 /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread 523 /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
520 /// was waiting via WaitSynchronization then the object will be the last object that became 524 /// was waiting via WaitSynchronization then the object will be the last object that became
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
new file mode 100644
index 000000000..21b290468
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -0,0 +1,44 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/core_timing_util.h"
9#include "core/hle/kernel/handle_table.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/thread.h"
12#include "core/hle/kernel/time_manager.h"
13
14namespace Kernel {
15
16TimeManager::TimeManager(Core::System& system) : system{system} {
17 time_manager_event_type = Core::Timing::CreateEvent(
18 "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) {
19 Handle proper_handle = static_cast<Handle>(thread_handle);
20 std::shared_ptr<Thread> thread =
21 this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
22 thread->ResumeFromWait();
23 });
24}
25
26void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) {
27 if (nanoseconds > 0) {
28 ASSERT(timetask);
29 event_handle = timetask->GetGlobalHandle();
30 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
31 system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle);
32 } else {
33 event_handle = InvalidHandle;
34 }
35}
36
37void TimeManager::UnscheduleTimeEvent(Handle event_handle) {
38 if (event_handle == InvalidHandle) {
39 return;
40 }
41 system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle);
42}
43
44} // namespace Kernel
diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h
new file mode 100644
index 000000000..eaec486d1
--- /dev/null
+++ b/src/core/hle/kernel/time_manager.h
@@ -0,0 +1,43 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "core/hle/kernel/object.h"
10
11namespace Core {
12class System;
13} // namespace Core
14
15namespace Core::Timing {
16struct EventType;
17} // namespace Core::Timing
18
19namespace Kernel {
20
21class Thread;
22
23/**
24 * The `TimeManager` takes care of scheduling time events on threads and executes their TimeUp
25 * method when the event is triggered.
26 */
27class TimeManager {
28public:
29 explicit TimeManager(Core::System& system);
30
31 /// Schedule a time event on `timetask` thread that will expire in 'nanoseconds'
32 /// returns a non-invalid handle in `event_handle` if correctly scheduled
33 void ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds);
34
35 /// Unschedule an existing time event
36 void UnscheduleTimeEvent(Handle event_handle);
37
38private:
39 Core::System& system;
40 std::shared_ptr<Core::Timing::EventType> time_manager_event_type;
41};
42
43} // namespace Kernel