summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/thread.h')
-rw-r--r--src/core/hle/kernel/thread.h318
1 files changed, 197 insertions, 121 deletions
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 06dd2ef2d..820ea524f 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -6,16 +6,21 @@
6 6
7#include <array> 7#include <array>
8#include <functional> 8#include <functional>
9#include <span>
9#include <string> 10#include <string>
10#include <utility> 11#include <utility>
11#include <vector> 12#include <vector>
12 13
14#include <boost/intrusive/list.hpp>
15
13#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/intrusive_red_black_tree.h"
14#include "common/spin_lock.h" 18#include "common/spin_lock.h"
15#include "core/arm/arm_interface.h" 19#include "core/arm/arm_interface.h"
16#include "core/hle/kernel/k_affinity_mask.h" 20#include "core/hle/kernel/k_affinity_mask.h"
17#include "core/hle/kernel/k_synchronization_object.h" 21#include "core/hle/kernel/k_synchronization_object.h"
18#include "core/hle/kernel/object.h" 22#include "core/hle/kernel/object.h"
23#include "core/hle/kernel/svc_common.h"
19#include "core/hle/result.h" 24#include "core/hle/result.h"
20 25
21namespace Common { 26namespace Common {
@@ -89,8 +94,6 @@ enum class ThreadState : u16 {
89 InitSuspended = (1 << (4 + SuspendShift)), 94 InitSuspended = (1 << (4 + SuspendShift)),
90 95
91 SuspendFlagMask = ((1 << 5) - 1) << SuspendShift, 96 SuspendFlagMask = ((1 << 5) - 1) << SuspendShift,
92
93 HighMask = 0xfff0,
94}; 97};
95DECLARE_ENUM_FLAG_OPERATORS(ThreadState); 98DECLARE_ENUM_FLAG_OPERATORS(ThreadState);
96 99
@@ -111,7 +114,10 @@ enum class ThreadSchedFlags : u32 {
111 KernelInitPauseFlag = 1 << 8, 114 KernelInitPauseFlag = 1 << 8,
112}; 115};
113 116
114class Thread final : public KSynchronizationObject { 117class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
118 friend class KScheduler;
119 friend class Process;
120
115public: 121public:
116 explicit Thread(KernelCore& kernel); 122 explicit Thread(KernelCore& kernel);
117 ~Thread() override; 123 ~Thread() override;
@@ -180,49 +186,46 @@ public:
180 * Gets the thread's current priority 186 * Gets the thread's current priority
181 * @return The current thread's priority 187 * @return The current thread's priority
182 */ 188 */
183 u32 GetPriority() const { 189 [[nodiscard]] s32 GetPriority() const {
184 return current_priority; 190 return current_priority;
185 } 191 }
186 192
187 /** 193 /**
194 * Sets the thread's current priority.
195 * @param priority The new priority.
196 */
197 void SetPriority(s32 priority) {
198 current_priority = priority;
199 }
200
201 /**
188 * Gets the thread's nominal priority. 202 * Gets the thread's nominal priority.
189 * @return The current thread's nominal priority. 203 * @return The current thread's nominal priority.
190 */ 204 */
191 u32 GetNominalPriority() const { 205 [[nodiscard]] s32 GetBasePriority() const {
192 return nominal_priority; 206 return base_priority;
193 } 207 }
194 208
195 /** 209 /**
196 * Sets the thread's current priority 210 * Sets the thread's nominal priority.
197 * @param priority The new priority 211 * @param priority The new priority.
198 */ 212 */
199 void SetPriority(u32 priority); 213 void SetBasePriority(u32 priority);
200
201 /// Adds a thread to the list of threads that are waiting for a lock held by this thread.
202 void AddMutexWaiter(std::shared_ptr<Thread> thread);
203
204 /// Removes a thread from the list of threads that are waiting for a lock held by this thread.
205 void RemoveMutexWaiter(std::shared_ptr<Thread> thread);
206
207 /// Recalculates the current priority taking into account priority inheritance.
208 void UpdatePriority();
209 214
210 /// Changes the core that the thread is running or scheduled to run on. 215 /// Changes the core that the thread is running or scheduled to run on.
211 ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); 216 [[nodiscard]] ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask);
212 217
213 /** 218 /**
214 * Gets the thread's thread ID 219 * Gets the thread's thread ID
215 * @return The thread's ID 220 * @return The thread's ID
216 */ 221 */
217 u64 GetThreadID() const { 222 [[nodiscard]] u64 GetThreadID() const {
218 return thread_id; 223 return thread_id;
219 } 224 }
220 225
221 /// Resumes a thread from waiting 226 /// Resumes a thread from waiting
222 void Wakeup(); 227 void Wakeup();
223 228
224 void OnWakeUp();
225
226 ResultCode Start(); 229 ResultCode Start();
227 230
228 virtual bool IsSignaled() const override; 231 virtual bool IsSignaled() const override;
@@ -242,7 +245,7 @@ public:
242 } 245 }
243 246
244 ResultCode GetWaitResult(KSynchronizationObject** out) const { 247 ResultCode GetWaitResult(KSynchronizationObject** out) const {
245 *out = this->signaling_object; 248 *out = signaling_object;
246 return signaling_result; 249 return signaling_result;
247 } 250 }
248 251
@@ -328,18 +331,14 @@ public:
328 return thread_state; 331 return thread_state;
329 } 332 }
330 333
331 void SetState(ThreadState new_state); 334 void SetState(ThreadState state);
332
333 void SetWaitingCondVar(bool value) {
334 is_waiting_on_condvar = value;
335 }
336 335
337 s64 GetLastScheduledTick() const { 336 s64 GetLastScheduledTick() const {
338 return this->last_scheduled_tick; 337 return last_scheduled_tick;
339 } 338 }
340 339
341 void SetLastScheduledTick(s64 tick) { 340 void SetLastScheduledTick(s64 tick) {
342 this->last_scheduled_tick = tick; 341 last_scheduled_tick = tick;
343 } 342 }
344 343
345 u64 GetTotalCPUTimeTicks() const { 344 u64 GetTotalCPUTimeTicks() const {
@@ -379,55 +378,13 @@ public:
379 } 378 }
380 379
381 Thread* GetLockOwner() const { 380 Thread* GetLockOwner() const {
382 return lock_owner.get(); 381 return lock_owner;
383 }
384
385 void SetLockOwner(std::shared_ptr<Thread> owner) {
386 lock_owner = std::move(owner);
387 }
388
389 VAddr GetCondVarWaitAddress() const {
390 return condvar_wait_address;
391 }
392
393 void SetCondVarWaitAddress(VAddr address) {
394 condvar_wait_address = address;
395 }
396
397 VAddr GetMutexWaitAddress() const {
398 return mutex_wait_address;
399 } 382 }
400 383
401 void SetMutexWaitAddress(VAddr address) { 384 void SetLockOwner(Thread* owner) {
402 mutex_wait_address = address; 385 lock_owner = owner;
403 } 386 }
404 387
405 Handle GetWaitHandle() const {
406 return wait_handle;
407 }
408
409 void SetWaitHandle(Handle handle) {
410 wait_handle = handle;
411 }
412
413 VAddr GetArbiterWaitAddress() const {
414 return arb_wait_address;
415 }
416
417 void SetArbiterWaitAddress(VAddr address) {
418 arb_wait_address = address;
419 }
420
421 void SetHLETimeEvent(Handle time_event) {
422 hle_time_event = time_event;
423 }
424
425 Handle GetHLETimeEvent() const {
426 return hle_time_event;
427 }
428
429 bool InvokeHLECallback(std::shared_ptr<Thread> thread);
430
431 u32 GetIdealCore() const { 388 u32 GetIdealCore() const {
432 return ideal_core; 389 return ideal_core;
433 } 390 }
@@ -442,11 +399,11 @@ public:
442 ResultCode Sleep(s64 nanoseconds); 399 ResultCode Sleep(s64 nanoseconds);
443 400
444 s64 GetYieldScheduleCount() const { 401 s64 GetYieldScheduleCount() const {
445 return this->schedule_count; 402 return schedule_count;
446 } 403 }
447 404
448 void SetYieldScheduleCount(s64 count) { 405 void SetYieldScheduleCount(s64 count) {
449 this->schedule_count = count; 406 schedule_count = count;
450 } 407 }
451 408
452 bool IsRunning() const { 409 bool IsRunning() const {
@@ -469,14 +426,6 @@ public:
469 return global_handle; 426 return global_handle;
470 } 427 }
471 428
472 bool IsWaitingForArbitration() const {
473 return waiting_for_arbitration;
474 }
475
476 void WaitForArbitration(bool set) {
477 waiting_for_arbitration = set;
478 }
479
480 bool IsCancellable() const { 429 bool IsCancellable() const {
481 return is_cancellable; 430 return is_cancellable;
482 } 431 }
@@ -490,7 +439,7 @@ public:
490 } 439 }
491 440
492 bool IsTerminationRequested() const { 441 bool IsTerminationRequested() const {
493 return will_be_terminated || GetState() == ThreadState::Terminated; 442 return will_be_terminated || GetRawState() == ThreadState::Terminated;
494 } 443 }
495 444
496 bool IsPaused() const { 445 bool IsPaused() const {
@@ -522,21 +471,21 @@ public:
522 constexpr QueueEntry() = default; 471 constexpr QueueEntry() = default;
523 472
524 constexpr void Initialize() { 473 constexpr void Initialize() {
525 this->prev = nullptr; 474 prev = nullptr;
526 this->next = nullptr; 475 next = nullptr;
527 } 476 }
528 477
529 constexpr Thread* GetPrev() const { 478 constexpr Thread* GetPrev() const {
530 return this->prev; 479 return prev;
531 } 480 }
532 constexpr Thread* GetNext() const { 481 constexpr Thread* GetNext() const {
533 return this->next; 482 return next;
534 } 483 }
535 constexpr void SetPrev(Thread* thread) { 484 constexpr void SetPrev(Thread* thread) {
536 this->prev = thread; 485 prev = thread;
537 } 486 }
538 constexpr void SetNext(Thread* thread) { 487 constexpr void SetNext(Thread* thread) {
539 this->next = thread; 488 next = thread;
540 } 489 }
541 490
542 private: 491 private:
@@ -545,11 +494,11 @@ public:
545 }; 494 };
546 495
547 QueueEntry& GetPriorityQueueEntry(s32 core) { 496 QueueEntry& GetPriorityQueueEntry(s32 core) {
548 return this->per_core_priority_queue_entry[core]; 497 return per_core_priority_queue_entry[core];
549 } 498 }
550 499
551 const QueueEntry& GetPriorityQueueEntry(s32 core) const { 500 const QueueEntry& GetPriorityQueueEntry(s32 core) const {
552 return this->per_core_priority_queue_entry[core]; 501 return per_core_priority_queue_entry[core];
553 } 502 }
554 503
555 s32 GetDisableDispatchCount() const { 504 s32 GetDisableDispatchCount() const {
@@ -566,27 +515,155 @@ public:
566 disable_count--; 515 disable_count--;
567 } 516 }
568 517
569 void SetWaitObjectsForDebugging(KSynchronizationObject** objects, s32 num_objects) { 518 void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
570 wait_objects_for_debugging.clear(); 519 wait_objects_for_debugging.clear();
571 wait_objects_for_debugging.reserve(num_objects); 520 wait_objects_for_debugging.reserve(objects.size());
572 for (auto i = 0; i < num_objects; ++i) { 521 for (const auto& object : objects) {
573 wait_objects_for_debugging.emplace_back(objects[i]); 522 wait_objects_for_debugging.emplace_back(object);
574 } 523 }
575 } 524 }
576 525
577 const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const { 526 [[nodiscard]] const std::vector<KSynchronizationObject*>& GetWaitObjectsForDebugging() const {
578 return wait_objects_for_debugging; 527 return wait_objects_for_debugging;
579 } 528 }
580 529
530 void SetMutexWaitAddressForDebugging(VAddr address) {
531 mutex_wait_address_for_debugging = address;
532 }
533
534 [[nodiscard]] VAddr GetMutexWaitAddressForDebugging() const {
535 return mutex_wait_address_for_debugging;
536 }
537
538 void AddWaiter(Thread* thread);
539
540 void RemoveWaiter(Thread* thread);
541
542 [[nodiscard]] Thread* RemoveWaiterByKey(s32* out_num_waiters, VAddr key);
543
544 [[nodiscard]] VAddr GetAddressKey() const {
545 return address_key;
546 }
547
548 [[nodiscard]] u32 GetAddressKeyValue() const {
549 return address_key_value;
550 }
551
552 void SetAddressKey(VAddr key) {
553 address_key = key;
554 }
555
556 void SetAddressKey(VAddr key, u32 val) {
557 address_key = key;
558 address_key_value = val;
559 }
560
581private: 561private:
582 friend class GlobalSchedulerContext; 562 static constexpr size_t PriorityInheritanceCountMax = 10;
583 friend class KScheduler; 563 union SyncObjectBuffer {
584 friend class Process; 564 std::array<KSynchronizationObject*, Svc::ArgumentHandleCountMax> sync_objects{};
565 std::array<Handle,
566 Svc::ArgumentHandleCountMax*(sizeof(KSynchronizationObject*) / sizeof(Handle))>
567 handles;
568 constexpr SyncObjectBuffer() {}
569 };
570 static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles));
571
572 struct ConditionVariableComparator {
573 struct LightCompareType {
574 u64 cv_key{};
575 s32 priority{};
576
577 [[nodiscard]] constexpr u64 GetConditionVariableKey() const {
578 return cv_key;
579 }
580
581 [[nodiscard]] constexpr s32 GetPriority() const {
582 return priority;
583 }
584 };
585
586 template <typename T>
587 requires(
588 std::same_as<T, Thread> ||
589 std::same_as<T, LightCompareType>) static constexpr int Compare(const T& lhs,
590 const Thread& rhs) {
591 const uintptr_t l_key = lhs.GetConditionVariableKey();
592 const uintptr_t r_key = rhs.GetConditionVariableKey();
593
594 if (l_key < r_key) {
595 // Sort first by key
596 return -1;
597 } else if (l_key == r_key && lhs.GetPriority() < rhs.GetPriority()) {
598 // And then by priority.
599 return -1;
600 } else {
601 return 1;
602 }
603 }
604 };
605
606 Common::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node{};
607
608 using ConditionVariableThreadTreeTraits =
609 Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&Thread::condvar_arbiter_tree_node>;
610 using ConditionVariableThreadTree =
611 ConditionVariableThreadTreeTraits::TreeType<ConditionVariableComparator>;
612
613public:
614 using ConditionVariableThreadTreeType = ConditionVariableThreadTree;
585 615
586 void SetSchedulingStatus(ThreadState new_status); 616 [[nodiscard]] uintptr_t GetConditionVariableKey() const {
617 return condvar_key;
618 }
619
620 [[nodiscard]] uintptr_t GetAddressArbiterKey() const {
621 return condvar_key;
622 }
623
624 void SetConditionVariable(ConditionVariableThreadTree* tree, VAddr address, uintptr_t cv_key,
625 u32 value) {
626 condvar_tree = tree;
627 condvar_key = cv_key;
628 address_key = address;
629 address_key_value = value;
630 }
631
632 void ClearConditionVariable() {
633 condvar_tree = nullptr;
634 }
635
636 [[nodiscard]] bool IsWaitingForConditionVariable() const {
637 return condvar_tree != nullptr;
638 }
639
640 void SetAddressArbiter(ConditionVariableThreadTree* tree, uintptr_t address) {
641 condvar_tree = tree;
642 condvar_key = address;
643 }
644
645 void ClearAddressArbiter() {
646 condvar_tree = nullptr;
647 }
648
649 [[nodiscard]] bool IsWaitingForAddressArbiter() const {
650 return condvar_tree != nullptr;
651 }
652
653 [[nodiscard]] ConditionVariableThreadTree* GetConditionVariableTree() const {
654 return condvar_tree;
655 }
656
657 [[nodiscard]] bool HasWaiters() const {
658 return !waiter_list.empty();
659 }
660
661private:
587 void AddSchedulingFlag(ThreadSchedFlags flag); 662 void AddSchedulingFlag(ThreadSchedFlags flag);
588 void RemoveSchedulingFlag(ThreadSchedFlags flag); 663 void RemoveSchedulingFlag(ThreadSchedFlags flag);
589 void SetCurrentPriority(u32 new_priority); 664 void AddWaiterImpl(Thread* thread);
665 void RemoveWaiterImpl(Thread* thread);
666 static void RestorePriority(KernelCore& kernel, Thread* thread);
590 667
591 Common::SpinLock context_guard{}; 668 Common::SpinLock context_guard{};
592 ThreadContext32 context_32{}; 669 ThreadContext32 context_32{};
@@ -606,11 +683,11 @@ private:
606 /// Nominal thread priority, as set by the emulated application. 683 /// Nominal thread priority, as set by the emulated application.
607 /// The nominal priority is the thread priority without priority 684 /// The nominal priority is the thread priority without priority
608 /// inheritance taken into account. 685 /// inheritance taken into account.
609 u32 nominal_priority = 0; 686 s32 base_priority{};
610 687
611 /// Current thread priority. This may change over the course of the 688 /// Current thread priority. This may change over the course of the
612 /// thread's lifetime in order to facilitate priority inheritance. 689 /// thread's lifetime in order to facilitate priority inheritance.
613 u32 current_priority = 0; 690 s32 current_priority{};
614 691
615 u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks. 692 u64 total_cpu_time_ticks = 0; ///< Total CPU running ticks.
616 s64 schedule_count{}; 693 s64 schedule_count{};
@@ -628,6 +705,9 @@ private:
628 /// passed to WaitSynchronization. This is used for debugging only. 705 /// passed to WaitSynchronization. This is used for debugging only.
629 std::vector<KSynchronizationObject*> wait_objects_for_debugging; 706 std::vector<KSynchronizationObject*> wait_objects_for_debugging;
630 707
708 /// The current mutex wait address. This is used for debugging only.
709 VAddr mutex_wait_address_for_debugging{};
710
631 KSynchronizationObject* signaling_object; 711 KSynchronizationObject* signaling_object;
632 ResultCode signaling_result{RESULT_SUCCESS}; 712 ResultCode signaling_result{RESULT_SUCCESS};
633 713
@@ -635,25 +715,11 @@ private:
635 MutexWaitingThreads wait_mutex_threads; 715 MutexWaitingThreads wait_mutex_threads;
636 716
637 /// Thread that owns the lock that this thread is waiting for. 717 /// Thread that owns the lock that this thread is waiting for.
638 std::shared_ptr<Thread> lock_owner; 718 Thread* lock_owner{};
639
640 /// If waiting on a ConditionVariable, this is the ConditionVariable address
641 VAddr condvar_wait_address = 0;
642 bool is_waiting_on_condvar{};
643 /// If waiting on a Mutex, this is the mutex address
644 VAddr mutex_wait_address = 0;
645 /// The handle used to wait for the mutex.
646 Handle wait_handle = 0;
647
648 /// If waiting for an AddressArbiter, this is the address being waited on.
649 VAddr arb_wait_address{0};
650 bool waiting_for_arbitration{};
651 719
652 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. 720 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
653 Handle global_handle = 0; 721 Handle global_handle = 0;
654 722
655 Handle hle_time_event;
656
657 KScheduler* scheduler = nullptr; 723 KScheduler* scheduler = nullptr;
658 724
659 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{}; 725 std::array<QueueEntry, Core::Hardware::NUM_CPU_CORES> per_core_priority_queue_entry{};
@@ -679,6 +745,16 @@ private:
679 745
680 bool signaled{}; 746 bool signaled{};
681 747
748 ConditionVariableThreadTree* condvar_tree{};
749 uintptr_t condvar_key{};
750 VAddr address_key{};
751 u32 address_key_value{};
752 s32 num_kernel_waiters{};
753
754 using WaiterList = boost::intrusive::list<Thread>;
755 WaiterList waiter_list{};
756 WaiterList pinned_waiter_list{};
757
682 std::string name; 758 std::string name;
683}; 759};
684 760