summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp119
1 files changed, 18 insertions, 101 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4ffd8d5cc..520ea0853 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -20,6 +20,7 @@
20#include "core/core_timing_util.h" 20#include "core/core_timing_util.h"
21#include "core/hle/kernel/errors.h" 21#include "core/hle/kernel/errors.h"
22#include "core/hle/kernel/handle_table.h" 22#include "core/hle/kernel/handle_table.h"
23#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/object.h" 24#include "core/hle/kernel/object.h"
24#include "core/hle/kernel/process.h" 25#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/thread.h" 26#include "core/hle/kernel/thread.h"
@@ -29,9 +30,6 @@
29 30
30namespace Kernel { 31namespace Kernel {
31 32
32/// Event type for the thread wake up event
33static CoreTiming::EventType* ThreadWakeupEventType = nullptr;
34
35bool Thread::ShouldWait(Thread* thread) const { 33bool Thread::ShouldWait(Thread* thread) const {
36 return status != ThreadStatus::Dead; 34 return status != ThreadStatus::Dead;
37} 35}
@@ -40,32 +38,17 @@ void Thread::Acquire(Thread* thread) {
40 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 38 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
41} 39}
42 40
43// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing 41Thread::Thread(KernelCore& kernel) : WaitObject{kernel} {}
44// us to simply use a pool index or similar. 42Thread::~Thread() = default;
45static Kernel::HandleTable wakeup_callback_handle_table;
46
47// The first available thread id at startup
48static u32 next_thread_id;
49
50/**
51 * Creates a new thread ID
52 * @return The new thread ID
53 */
54inline static u32 const NewThreadId() {
55 return next_thread_id++;
56}
57
58Thread::Thread() {}
59Thread::~Thread() {}
60 43
61void Thread::Stop() { 44void Thread::Stop() {
62 // Cancel any outstanding wakeup events for this thread 45 // Cancel any outstanding wakeup events for this thread
63 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); 46 CoreTiming::UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), callback_handle);
64 wakeup_callback_handle_table.Close(callback_handle); 47 kernel.ThreadWakeupCallbackHandleTable().Close(callback_handle);
65 callback_handle = 0; 48 callback_handle = 0;
66 49
67 // Clean up thread from ready queue 50 // Clean up thread from ready queue
68 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) 51 // This is only needed when the thread is terminated forcefully (SVC TerminateProcess)
69 if (status == ThreadStatus::Ready) { 52 if (status == ThreadStatus::Ready) {
70 scheduler->UnscheduleThread(this, current_priority); 53 scheduler->UnscheduleThread(this, current_priority);
71 } 54 }
@@ -98,63 +81,6 @@ void ExitCurrentThread() {
98 Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); 81 Core::System::GetInstance().CurrentScheduler().RemoveThread(thread);
99} 82}
100 83
101/**
102 * Callback that will wake up the thread it was scheduled for
103 * @param thread_handle The handle of the thread that's been awoken
104 * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time
105 */
106static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
107 const auto proper_handle = static_cast<Handle>(thread_handle);
108
109 // Lock the global kernel mutex when we enter the kernel HLE.
110 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
111
112 SharedPtr<Thread> thread = wakeup_callback_handle_table.Get<Thread>(proper_handle);
113 if (thread == nullptr) {
114 LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle);
115 return;
116 }
117
118 bool resume = true;
119
120 if (thread->status == ThreadStatus::WaitSynchAny ||
121 thread->status == ThreadStatus::WaitSynchAll ||
122 thread->status == ThreadStatus::WaitHLEEvent) {
123 // Remove the thread from each of its waiting objects' waitlists
124 for (auto& object : thread->wait_objects)
125 object->RemoveWaitingThread(thread.get());
126 thread->wait_objects.clear();
127
128 // Invoke the wakeup callback before clearing the wait objects
129 if (thread->wakeup_callback)
130 resume = thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr, 0);
131 }
132
133 if (thread->mutex_wait_address != 0 || thread->condvar_wait_address != 0 ||
134 thread->wait_handle) {
135 ASSERT(thread->status == ThreadStatus::WaitMutex);
136 thread->mutex_wait_address = 0;
137 thread->condvar_wait_address = 0;
138 thread->wait_handle = 0;
139
140 auto lock_owner = thread->lock_owner;
141 // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
142 // and don't have a lock owner unless SignalProcessWideKey was called first and the thread
143 // wasn't awakened due to the mutex already being acquired.
144 if (lock_owner) {
145 lock_owner->RemoveMutexWaiter(thread);
146 }
147 }
148
149 if (thread->arb_wait_address != 0) {
150 ASSERT(thread->status == ThreadStatus::WaitArb);
151 thread->arb_wait_address = 0;
152 }
153
154 if (resume)
155 thread->ResumeFromWait();
156}
157
158void Thread::WakeAfterDelay(s64 nanoseconds) { 84void Thread::WakeAfterDelay(s64 nanoseconds) {
159 // Don't schedule a wakeup if the thread wants to wait forever 85 // Don't schedule a wakeup if the thread wants to wait forever
160 if (nanoseconds == -1) 86 if (nanoseconds == -1)
@@ -162,12 +88,12 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
162 88
163 // This function might be called from any thread so we have to be cautious and use the 89 // This function might be called from any thread so we have to be cautious and use the
164 // thread-safe version of ScheduleEvent. 90 // thread-safe version of ScheduleEvent.
165 CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds), ThreadWakeupEventType, 91 CoreTiming::ScheduleEventThreadsafe(CoreTiming::nsToCycles(nanoseconds),
166 callback_handle); 92 kernel.ThreadWakeupCallbackEventType(), callback_handle);
167} 93}
168 94
169void Thread::CancelWakeupTimer() { 95void Thread::CancelWakeupTimer() {
170 CoreTiming::UnscheduleEventThreadsafe(ThreadWakeupEventType, callback_handle); 96 CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
171} 97}
172 98
173static boost::optional<s32> GetNextProcessorId(u64 mask) { 99static boost::optional<s32> GetNextProcessorId(u64 mask) {
@@ -294,9 +220,9 @@ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAdd
294 context.fpscr = 0; 220 context.fpscr = 0;
295} 221}
296 222
297ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, 223ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
298 u64 arg, s32 processor_id, VAddr stack_top, 224 u32 priority, u64 arg, s32 processor_id,
299 SharedPtr<Process> owner_process) { 225 VAddr stack_top, SharedPtr<Process> owner_process) {
300 // Check if priority is in ranged. Lowest priority -> highest priority id. 226 // Check if priority is in ranged. Lowest priority -> highest priority id.
301 if (priority > THREADPRIO_LOWEST) { 227 if (priority > THREADPRIO_LOWEST) {
302 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 228 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@@ -316,9 +242,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
316 return ResultCode(-1); 242 return ResultCode(-1);
317 } 243 }
318 244
319 SharedPtr<Thread> thread(new Thread); 245 SharedPtr<Thread> thread(new Thread(kernel));
320 246
321 thread->thread_id = NewThreadId(); 247 thread->thread_id = kernel.CreateNewThreadID();
322 thread->status = ThreadStatus::Dormant; 248 thread->status = ThreadStatus::Dormant;
323 thread->entry_point = entry_point; 249 thread->entry_point = entry_point;
324 thread->stack_top = stack_top; 250 thread->stack_top = stack_top;
@@ -333,7 +259,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
333 thread->condvar_wait_address = 0; 259 thread->condvar_wait_address = 0;
334 thread->wait_handle = 0; 260 thread->wait_handle = 0;
335 thread->name = std::move(name); 261 thread->name = std::move(name);
336 thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); 262 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
337 thread->owner_process = owner_process; 263 thread->owner_process = owner_process;
338 thread->scheduler = Core::System::GetInstance().Scheduler(processor_id); 264 thread->scheduler = Core::System::GetInstance().Scheduler(processor_id);
339 thread->scheduler->AddThread(thread, priority); 265 thread->scheduler->AddThread(thread, priority);
@@ -383,19 +309,19 @@ void Thread::BoostPriority(u32 priority) {
383 current_priority = priority; 309 current_priority = priority;
384} 310}
385 311
386SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, 312SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
387 SharedPtr<Process> owner_process) { 313 SharedPtr<Process> owner_process) {
388 // Setup page table so we can write to memory 314 // Setup page table so we can write to memory
389 SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); 315 SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
390 316
391 // Initialize new "main" thread 317 // Initialize new "main" thread
392 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, 318 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
393 Memory::STACK_AREA_VADDR_END, std::move(owner_process)); 319 Memory::STACK_AREA_VADDR_END, std::move(owner_process));
394 320
395 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 321 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
396 322
397 // Register 1 must be a handle to the main thread 323 // Register 1 must be a handle to the main thread
398 thread->guest_handle = Kernel::g_handle_table.Create(thread).Unwrap(); 324 thread->guest_handle = kernel.HandleTable().Create(thread).Unwrap();
399 325
400 thread->context.cpu_registers[1] = thread->guest_handle; 326 thread->context.cpu_registers[1] = thread->guest_handle;
401 327
@@ -528,13 +454,4 @@ Thread* GetCurrentThread() {
528 return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); 454 return Core::System::GetInstance().CurrentScheduler().GetCurrentThread();
529} 455}
530 456
531void ThreadingInit() {
532 ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
533 next_thread_id = 1;
534}
535
536void ThreadingShutdown() {
537 Kernel::ClearProcessList();
538}
539
540} // namespace Kernel 457} // namespace Kernel