summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2016-09-21 11:29:48 -0700
committerGravatar GitHub2016-09-21 11:29:48 -0700
commitd5d2ca8058a0f1c00ab7ca9fe2c058ba47546c0a (patch)
tree8a22ca73ff838f3f0090b29a548ae81087fc90ed /src/core/hle/kernel/thread.cpp
parentREADME: Specify master branch for Travis CI badge (diff)
parentFix Travis clang-format check (diff)
downloadyuzu-d5d2ca8058a0f1c00ab7ca9fe2c058ba47546c0a.tar.gz
yuzu-d5d2ca8058a0f1c00ab7ca9fe2c058ba47546c0a.tar.xz
yuzu-d5d2ca8058a0f1c00ab7ca9fe2c058ba47546c0a.zip
Merge pull request #2086 from linkmauve/clang-format
Add clang-format as part of our {commit,travis}-time checks
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp110
1 files changed, 61 insertions, 49 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index f1e5cf3cb..4486a812c 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -5,23 +5,21 @@
5#include <algorithm> 5#include <algorithm>
6#include <list> 6#include <list>
7#include <vector> 7#include <vector>
8
9#include "common/assert.h" 8#include "common/assert.h"
10#include "common/common_types.h" 9#include "common/common_types.h"
11#include "common/logging/log.h" 10#include "common/logging/log.h"
12#include "common/math_util.h" 11#include "common/math_util.h"
13#include "common/thread_queue_list.h" 12#include "common/thread_queue_list.h"
14
15#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
16#include "core/arm/skyeye_common/armstate.h" 14#include "core/arm/skyeye_common/armstate.h"
17#include "core/core.h" 15#include "core/core.h"
18#include "core/core_timing.h" 16#include "core/core_timing.h"
19#include "core/hle/hle.h" 17#include "core/hle/hle.h"
20#include "core/hle/kernel/kernel.h" 18#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/process.h"
22#include "core/hle/kernel/thread.h"
23#include "core/hle/kernel/memory.h" 19#include "core/hle/kernel/memory.h"
24#include "core/hle/kernel/mutex.h" 20#include "core/hle/kernel/mutex.h"
21#include "core/hle/kernel/process.h"
22#include "core/hle/kernel/thread.h"
25#include "core/hle/result.h" 23#include "core/hle/result.h"
26#include "core/memory.h" 24#include "core/memory.h"
27 25
@@ -46,7 +44,7 @@ static Kernel::HandleTable wakeup_callback_handle_table;
46static std::vector<SharedPtr<Thread>> thread_list; 44static std::vector<SharedPtr<Thread>> thread_list;
47 45
48// Lists only ready thread ids. 46// Lists only ready thread ids.
49static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue; 47static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
50 48
51static Thread* current_thread; 49static Thread* current_thread;
52 50
@@ -103,7 +101,7 @@ void Thread::Stop() {
103 101
104 // Clean up thread from ready queue 102 // Clean up thread from ready queue
105 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) 103 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
106 if (status == THREADSTATUS_READY){ 104 if (status == THREADSTATUS_READY) {
107 ready_queue.remove(current_priority, this); 105 ready_queue.remove(current_priority, this);
108 } 106 }
109 107
@@ -119,7 +117,8 @@ void Thread::Stop() {
119 117
120 // Mark the TLS slot in the thread's page as free. 118 // Mark the TLS slot in the thread's page as free.
121 u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; 119 u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
122 u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; 120 u32 tls_slot =
121 ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
123 Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); 122 Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
124 123
125 HLE::Reschedule(__func__); 124 HLE::Reschedule(__func__);
@@ -137,7 +136,7 @@ Thread* ArbitrateHighestPriorityThread(u32 address) {
137 if (thread == nullptr) 136 if (thread == nullptr)
138 continue; 137 continue;
139 138
140 if(thread->current_priority <= priority) { 139 if (thread->current_priority <= priority) {
141 highest_priority_thread = thread.get(); 140 highest_priority_thread = thread.get();
142 priority = thread->current_priority; 141 priority = thread->current_priority;
143 } 142 }
@@ -170,7 +169,7 @@ static void PriorityBoostStarvedThreads() {
170 // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler 169 // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler
171 // should probably be reversed to verify this. 170 // should probably be reversed to verify this.
172 171
173 const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long 172 const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
174 173
175 u64 delta = current_ticks - thread->last_running_ticks; 174 u64 delta = current_ticks - thread->last_running_ticks;
176 175
@@ -193,10 +192,12 @@ static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* threa
193 192
194 if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { 193 if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
195 // svc #0x24 (WaitSynchronization1) 194 // svc #0x24 (WaitSynchronization1)
196 return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]); 195 return std::make_tuple(&thread->context.cpu_registers[2],
196 &thread->context.cpu_registers[3]);
197 } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { 197 } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
198 // svc #0x25 (WaitSynchronizationN) 198 // svc #0x25 (WaitSynchronizationN)
199 return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]); 199 return std::make_tuple(&thread->context.cpu_registers[0],
200 &thread->context.cpu_registers[4]);
200 } 201 }
201 202
202 UNREACHABLE(); 203 UNREACHABLE();
@@ -245,7 +246,8 @@ static void SwitchContext(Thread* new_thread) {
245 246
246 // Load context of new thread 247 // Load context of new thread
247 if (new_thread) { 248 if (new_thread) {
248 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); 249 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY,
250 "Thread must be ready to become running.");
249 251
250 // Cancel any outstanding wakeup events for this thread 252 // Cancel any outstanding wakeup events for this thread
251 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); 253 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
@@ -263,7 +265,7 @@ static void SwitchContext(Thread* new_thread) {
263 new_thread->context.pc -= thumb_mode ? 2 : 4; 265 new_thread->context.pc -= thumb_mode ? 2 : 4;
264 266
265 // Get the register for timeout parameter 267 // Get the register for timeout parameter
266 u32* timeout_low, *timeout_high; 268 u32 *timeout_low, *timeout_high;
267 std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); 269 std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
268 270
269 // Update the timeout parameter 271 // Update the timeout parameter
@@ -307,7 +309,7 @@ static Thread* PopNextReadyThread() {
307 // Otherwise just keep going with the current thread 309 // Otherwise just keep going with the current thread
308 next = thread; 310 next = thread;
309 } 311 }
310 } else { 312 } else {
311 next = ready_queue.pop_first(); 313 next = ready_queue.pop_first();
312 } 314 }
313 315
@@ -321,7 +323,8 @@ void WaitCurrentThread_Sleep() {
321 HLE::Reschedule(__func__); 323 HLE::Reschedule(__func__);
322} 324}
323 325
324void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all) { 326void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
327 bool wait_set_output, bool wait_all) {
325 Thread* thread = GetCurrentThread(); 328 Thread* thread = GetCurrentThread();
326 thread->wait_set_output = wait_set_output; 329 thread->wait_set_output = wait_set_output;
327 thread->wait_all = wait_all; 330 thread->wait_all = wait_all;
@@ -352,7 +355,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
352 355
353 if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { 356 if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
354 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, 357 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
355 ErrorSummary::StatusChanged, ErrorLevel::Info)); 358 ErrorSummary::StatusChanged,
359 ErrorLevel::Info));
356 360
357 if (thread->wait_set_output) 361 if (thread->wait_set_output)
358 thread->SetWaitSynchronizationOutput(-1); 362 thread->SetWaitSynchronizationOutput(-1);
@@ -372,25 +376,25 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
372 376
373void Thread::ResumeFromWait() { 377void Thread::ResumeFromWait() {
374 switch (status) { 378 switch (status) {
375 case THREADSTATUS_WAIT_SYNCH: 379 case THREADSTATUS_WAIT_SYNCH:
376 case THREADSTATUS_WAIT_ARB: 380 case THREADSTATUS_WAIT_ARB:
377 case THREADSTATUS_WAIT_SLEEP: 381 case THREADSTATUS_WAIT_SLEEP:
378 break; 382 break;
379 383
380 case THREADSTATUS_READY: 384 case THREADSTATUS_READY:
381 // If the thread is waiting on multiple wait objects, it might be awoken more than once 385 // If the thread is waiting on multiple wait objects, it might be awoken more than once
382 // before actually resuming. We can ignore subsequent wakeups if the thread status has 386 // before actually resuming. We can ignore subsequent wakeups if the thread status has
383 // already been set to THREADSTATUS_READY. 387 // already been set to THREADSTATUS_READY.
384 return; 388 return;
385 389
386 case THREADSTATUS_RUNNING: 390 case THREADSTATUS_RUNNING:
387 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); 391 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
388 return; 392 return;
389 case THREADSTATUS_DEAD: 393 case THREADSTATUS_DEAD:
390 // This should never happen, as threads must complete before being stopped. 394 // This should never happen, as threads must complete before being stopped.
391 DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.", 395 DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
392 GetObjectId()); 396 GetObjectId());
393 return; 397 return;
394 } 398 }
395 399
396 ready_queue.push_back(current_priority, this); 400 ready_queue.push_back(current_priority, this);
@@ -405,7 +409,8 @@ static void DebugThreadQueue() {
405 if (!thread) { 409 if (!thread) {
406 LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); 410 LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD");
407 } else { 411 } else {
408 LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId()); 412 LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority,
413 GetCurrentThread()->GetObjectId());
409 } 414 }
410 415
411 for (auto& t : thread_list) { 416 for (auto& t : thread_list) {
@@ -448,7 +453,8 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
448 * @param entry_point Address of entry point for execution 453 * @param entry_point Address of entry point for execution
449 * @param arg User argument for thread 454 * @param arg User argument for thread
450 */ 455 */
451static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { 456static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point,
457 u32 arg) {
452 memset(&context, 0, sizeof(Core::ThreadContext)); 458 memset(&context, 0, sizeof(Core::ThreadContext));
453 459
454 context.cpu_registers[0] = arg; 460 context.cpu_registers[0] = arg;
@@ -458,11 +464,11 @@ static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32
458} 464}
459 465
460ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, 466ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
461 u32 arg, s32 processor_id, VAddr stack_top) { 467 u32 arg, s32 processor_id, VAddr stack_top) {
462 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { 468 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
463 s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); 469 s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
464 LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", 470 LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(),
465 name.c_str(), priority, new_priority); 471 priority, new_priority);
466 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm 472 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
467 // validity of this 473 // validity of this
468 priority = new_priority; 474 priority = new_priority;
@@ -472,7 +478,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
472 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); 478 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
473 // TODO: Verify error 479 // TODO: Verify error
474 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 480 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
475 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 481 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
476 } 482 }
477 483
478 SharedPtr<Thread> thread(new Thread); 484 SharedPtr<Thread> thread(new Thread);
@@ -511,8 +517,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
511 auto& linheap_memory = memory_region->linear_heap_memory; 517 auto& linheap_memory = memory_region->linear_heap_memory;
512 518
513 if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { 519 if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
514 LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread"); 520 LOG_ERROR(Kernel_SVC,
515 return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent); 521 "Not enough space in region to allocate a new TLS page for thread");
522 return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
523 ErrorSummary::OutOfResource, ErrorLevel::Permanent);
516 } 524 }
517 525
518 u32 offset = linheap_memory->size(); 526 u32 offset = linheap_memory->size();
@@ -537,7 +545,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
537 545
538 // Mark the slot as used 546 // Mark the slot as used
539 tls_slots[available_page].set(available_slot); 547 tls_slots[available_page].set(available_slot);
540 thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; 548 thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
549 available_slot * Memory::TLS_ENTRY_SIZE;
541 550
542 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used 551 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
543 // to initialize the context 552 // to initialize the context
@@ -551,10 +560,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
551 return MakeResult<SharedPtr<Thread>>(std::move(thread)); 560 return MakeResult<SharedPtr<Thread>>(std::move(thread));
552} 561}
553 562
554// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be returned. 563// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be
564// returned.
555static void ClampPriority(const Thread* thread, s32* priority) { 565static void ClampPriority(const Thread* thread, s32* priority) {
556 if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) { 566 if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) {
557 DEBUG_ASSERT_MSG(false, "Application passed an out of range priority. An error should be returned."); 567 DEBUG_ASSERT_MSG(
568 false, "Application passed an out of range priority. An error should be returned.");
558 569
559 s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); 570 s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
560 LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", 571 LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
@@ -586,12 +597,13 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
586 DEBUG_ASSERT(!GetCurrentThread()); 597 DEBUG_ASSERT(!GetCurrentThread());
587 598
588 // Initialize new "main" thread 599 // Initialize new "main" thread
589 auto thread_res = Thread::Create("main", entry_point, priority, 0, 600 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
590 THREADPROCESSORID_0, Memory::HEAP_VADDR_END); 601 Memory::HEAP_VADDR_END);
591 602
592 SharedPtr<Thread> thread = thread_res.MoveFrom(); 603 SharedPtr<Thread> thread = thread_res.MoveFrom();
593 604
594 thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 605 thread->context.fpscr =
606 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
595 607
596 // Run new "main" thread 608 // Run new "main" thread
597 SwitchContext(thread.get()); 609 SwitchContext(thread.get());