summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/event.cpp6
-rw-r--r--src/core/hle/kernel/event.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp49
-rw-r--r--src/core/hle/kernel/kernel.h13
-rw-r--r--src/core/hle/kernel/mutex.cpp84
-rw-r--r--src/core/hle/kernel/mutex.h17
-rw-r--r--src/core/hle/kernel/semaphore.cpp6
-rw-r--r--src/core/hle/kernel/semaphore.h4
-rw-r--r--src/core/hle/kernel/server_port.cpp6
-rw-r--r--src/core/hle/kernel/server_port.h4
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/server_session.h4
-rw-r--r--src/core/hle/kernel/thread.cpp50
-rw-r--r--src/core/hle/kernel/thread.h48
-rw-r--r--src/core/hle/kernel/timer.cpp6
-rw-r--r--src/core/hle/kernel/timer.h4
16 files changed, 184 insertions, 127 deletions
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 3e116e3df..e1f42af05 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -30,12 +30,12 @@ SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
30 return evt; 30 return evt;
31} 31}
32 32
33bool Event::ShouldWait() { 33bool Event::ShouldWait(Thread* thread) const {
34 return !signaled; 34 return !signaled;
35} 35}
36 36
37void Event::Acquire() { 37void Event::Acquire(Thread* thread) {
38 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 38 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
39 39
40 // Release the event if it's not sticky... 40 // Release the event if it's not sticky...
41 if (reset_type != ResetType::Sticky) 41 if (reset_type != ResetType::Sticky)
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 8dcd23edb..39452bf33 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -35,8 +35,8 @@ public:
35 bool signaled; ///< Whether the event has already been signaled 35 bool signaled; ///< Whether the event has already been signaled
36 std::string name; ///< Name of event (optional) 36 std::string name; ///< Name of event (optional)
37 37
38 bool ShouldWait() override; 38 bool ShouldWait(Thread* thread) const override;
39 void Acquire() override; 39 void Acquire(Thread* thread) override;
40 40
41 void Signal(); 41 void Signal();
42 void Clear(); 42 void Clear();
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1db8e102f..f599916f0 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <boost/range/algorithm_ext/erase.hpp>
7#include "common/assert.h" 6#include "common/assert.h"
8#include "common/logging/log.h" 7#include "common/logging/log.h"
9#include "core/hle/config_mem.h" 8#include "core/hle/config_mem.h"
@@ -28,32 +27,39 @@ void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
28 27
29void WaitObject::RemoveWaitingThread(Thread* thread) { 28void WaitObject::RemoveWaitingThread(Thread* thread) {
30 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread); 29 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
30 // If a thread passed multiple handles to the same object,
31 // the kernel might attempt to remove the thread from the object's
32 // waiting threads list multiple times.
31 if (itr != waiting_threads.end()) 33 if (itr != waiting_threads.end())
32 waiting_threads.erase(itr); 34 waiting_threads.erase(itr);
33} 35}
34 36
35SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { 37SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
36 // Remove the threads that are ready or already running from our waitlist
37 boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) {
38 return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY ||
39 thread->status == THREADSTATUS_DEAD;
40 });
41
42 // TODO(Subv): This call should be performed inside the loop below to check if an object can be
43 // acquired by a particular thread. This is useful for things like recursive locking of Mutexes.
44 if (ShouldWait())
45 return nullptr;
46
47 Thread* candidate = nullptr; 38 Thread* candidate = nullptr;
48 s32 candidate_priority = THREADPRIO_LOWEST + 1; 39 s32 candidate_priority = THREADPRIO_LOWEST + 1;
49 40
50 for (const auto& thread : waiting_threads) { 41 for (const auto& thread : waiting_threads) {
42 // The list of waiting threads must not contain threads that are not waiting to be awakened.
43 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
44 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
45 "Inconsistent thread statuses in waiting_threads");
46
51 if (thread->current_priority >= candidate_priority) 47 if (thread->current_priority >= candidate_priority)
52 continue; 48 continue;
53 49
54 bool ready_to_run = 50 if (ShouldWait(thread.get()))
55 std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), 51 continue;
56 [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); }); 52
53 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
54 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
55 bool ready_to_run = true;
56 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
57 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
58 [&thread](const SharedPtr<WaitObject>& object) {
59 return object->ShouldWait(thread.get());
60 });
61 }
62
57 if (ready_to_run) { 63 if (ready_to_run) {
58 candidate = thread.get(); 64 candidate = thread.get();
59 candidate_priority = thread->current_priority; 65 candidate_priority = thread->current_priority;
@@ -66,7 +72,7 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
66void WaitObject::WakeupAllWaitingThreads() { 72void WaitObject::WakeupAllWaitingThreads() {
67 while (auto thread = GetHighestPriorityReadyThread()) { 73 while (auto thread = GetHighestPriorityReadyThread()) {
68 if (!thread->IsSleepingOnWaitAll()) { 74 if (!thread->IsSleepingOnWaitAll()) {
69 Acquire(); 75 Acquire(thread.get());
70 // Set the output index of the WaitSynchronizationN call to the index of this object. 76 // Set the output index of the WaitSynchronizationN call to the index of this object.
71 if (thread->wait_set_output) { 77 if (thread->wait_set_output) {
72 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); 78 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
@@ -74,18 +80,17 @@ void WaitObject::WakeupAllWaitingThreads() {
74 } 80 }
75 } else { 81 } else {
76 for (auto& object : thread->wait_objects) { 82 for (auto& object : thread->wait_objects) {
77 object->Acquire(); 83 object->Acquire(thread.get());
78 object->RemoveWaitingThread(thread.get());
79 } 84 }
80 // Note: This case doesn't update the output index of WaitSynchronizationN. 85 // Note: This case doesn't update the output index of WaitSynchronizationN.
81 // Clear the thread's waitlist
82 thread->wait_objects.clear();
83 } 86 }
84 87
88 for (auto& object : thread->wait_objects)
89 object->RemoveWaitingThread(thread.get());
90 thread->wait_objects.clear();
91
85 thread->SetWaitSynchronizationResult(RESULT_SUCCESS); 92 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
86 thread->ResumeFromWait(); 93 thread->ResumeFromWait();
87 // Note: Removing the thread from the object's waitlist will be
88 // done by GetHighestPriorityReadyThread.
89 } 94 }
90} 95}
91 96
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 9503e7d04..05097824b 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -132,25 +132,26 @@ using SharedPtr = boost::intrusive_ptr<T>;
132class WaitObject : public Object { 132class WaitObject : public Object {
133public: 133public:
134 /** 134 /**
135 * Check if the current thread should wait until the object is available 135 * Check if the specified thread should wait until the object is available
136 * @param thread The thread about which we're deciding.
136 * @return True if the current thread should wait due to this object being unavailable 137 * @return True if the current thread should wait due to this object being unavailable
137 */ 138 */
138 virtual bool ShouldWait() = 0; 139 virtual bool ShouldWait(Thread* thread) const = 0;
139 140
140 /// Acquire/lock the object if it is available 141 /// Acquire/lock the object for the specified thread if it is available
141 virtual void Acquire() = 0; 142 virtual void Acquire(Thread* thread) = 0;
142 143
143 /** 144 /**
144 * Add a thread to wait on this object 145 * Add a thread to wait on this object
145 * @param thread Pointer to thread to add 146 * @param thread Pointer to thread to add
146 */ 147 */
147 void AddWaitingThread(SharedPtr<Thread> thread); 148 virtual void AddWaitingThread(SharedPtr<Thread> thread);
148 149
149 /** 150 /**
150 * Removes a thread from waiting on this object (e.g. if it was resumed already) 151 * Removes a thread from waiting on this object (e.g. if it was resumed already)
151 * @param thread Pointer to thread to remove 152 * @param thread Pointer to thread to remove
152 */ 153 */
153 void RemoveWaitingThread(Thread* thread); 154 virtual void RemoveWaitingThread(Thread* thread);
154 155
155 /** 156 /**
156 * Wake up all threads waiting on this object that can be awoken, in priority order, 157 * Wake up all threads waiting on this object that can be awoken, in priority order,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 736944bae..cef961289 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -6,26 +6,18 @@
6#include <vector> 6#include <vector>
7#include <boost/range/algorithm_ext/erase.hpp> 7#include <boost/range/algorithm_ext/erase.hpp>
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h"
9#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
12 13
13namespace Kernel { 14namespace Kernel {
14 15
15/**
16 * Resumes a thread waiting for the specified mutex
17 * @param mutex The mutex that some thread is waiting on
18 */
19static void ResumeWaitingThread(Mutex* mutex) {
20 // Reset mutex lock thread handle, nothing is waiting
21 mutex->lock_count = 0;
22 mutex->holding_thread = nullptr;
23 mutex->WakeupAllWaitingThreads();
24}
25
26void ReleaseThreadMutexes(Thread* thread) { 16void ReleaseThreadMutexes(Thread* thread) {
27 for (auto& mtx : thread->held_mutexes) { 17 for (auto& mtx : thread->held_mutexes) {
28 ResumeWaitingThread(mtx.get()); 18 mtx->lock_count = 0;
19 mtx->holding_thread = nullptr;
20 mtx->WakeupAllWaitingThreads();
29 } 21 }
30 thread->held_mutexes.clear(); 22 thread->held_mutexes.clear();
31} 23}
@@ -40,52 +32,74 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
40 mutex->name = std::move(name); 32 mutex->name = std::move(name);
41 mutex->holding_thread = nullptr; 33 mutex->holding_thread = nullptr;
42 34
43 // Acquire mutex with current thread if initialized as locked... 35 // Acquire mutex with current thread if initialized as locked
44 if (initial_locked) 36 if (initial_locked)
45 mutex->Acquire(); 37 mutex->Acquire(GetCurrentThread());
46 38
47 return mutex; 39 return mutex;
48} 40}
49 41
50bool Mutex::ShouldWait() { 42bool Mutex::ShouldWait(Thread* thread) const {
51 auto thread = GetCurrentThread(); 43 return lock_count > 0 && thread != holding_thread;
52 bool wait = lock_count > 0 && holding_thread != thread;
53
54 // If the holding thread of the mutex is lower priority than this thread, that thread should
55 // temporarily inherit this thread's priority
56 if (wait && thread->current_priority < holding_thread->current_priority)
57 holding_thread->BoostPriority(thread->current_priority);
58
59 return wait;
60}
61
62void Mutex::Acquire() {
63 Acquire(GetCurrentThread());
64} 44}
65 45
66void Mutex::Acquire(SharedPtr<Thread> thread) { 46void Mutex::Acquire(Thread* thread) {
67 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 47 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
68 48
69 // Actually "acquire" the mutex only if we don't already have it... 49 // Actually "acquire" the mutex only if we don't already have it
70 if (lock_count == 0) { 50 if (lock_count == 0) {
51 priority = thread->current_priority;
71 thread->held_mutexes.insert(this); 52 thread->held_mutexes.insert(this);
72 holding_thread = std::move(thread); 53 holding_thread = thread;
54 thread->UpdatePriority();
55 Core::System::GetInstance().PrepareReschedule();
73 } 56 }
74 57
75 lock_count++; 58 lock_count++;
76} 59}
77 60
78void Mutex::Release() { 61void Mutex::Release() {
79 // Only release if the mutex is held... 62 // Only release if the mutex is held
80 if (lock_count > 0) { 63 if (lock_count > 0) {
81 lock_count--; 64 lock_count--;
82 65
83 // Yield to the next thread only if we've fully released the mutex... 66 // Yield to the next thread only if we've fully released the mutex
84 if (lock_count == 0) { 67 if (lock_count == 0) {
85 holding_thread->held_mutexes.erase(this); 68 holding_thread->held_mutexes.erase(this);
86 ResumeWaitingThread(this); 69 holding_thread->UpdatePriority();
70 holding_thread = nullptr;
71 WakeupAllWaitingThreads();
72 Core::System::GetInstance().PrepareReschedule();
87 } 73 }
88 } 74 }
89} 75}
90 76
77void Mutex::AddWaitingThread(SharedPtr<Thread> thread) {
78 WaitObject::AddWaitingThread(thread);
79 thread->pending_mutexes.insert(this);
80 UpdatePriority();
81}
82
83void Mutex::RemoveWaitingThread(Thread* thread) {
84 WaitObject::RemoveWaitingThread(thread);
85 thread->pending_mutexes.erase(this);
86 UpdatePriority();
87}
88
89void Mutex::UpdatePriority() {
90 if (!holding_thread)
91 return;
92
93 s32 best_priority = THREADPRIO_LOWEST;
94 for (auto& waiter : GetWaitingThreads()) {
95 if (waiter->current_priority < best_priority)
96 best_priority = waiter->current_priority;
97 }
98
99 if (best_priority != priority) {
100 priority = best_priority;
101 holding_thread->UpdatePriority();
102 }
103}
104
91} // namespace 105} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 53c3dc1f1..c57adf400 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -35,17 +35,22 @@ public:
35 } 35 }
36 36
37 int lock_count; ///< Number of times the mutex has been acquired 37 int lock_count; ///< Number of times the mutex has been acquired
38 u32 priority; ///< The priority of the mutex, used for priority inheritance.
38 std::string name; ///< Name of mutex (optional) 39 std::string name; ///< Name of mutex (optional)
39 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex 40 SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
40 41
41 bool ShouldWait() override;
42 void Acquire() override;
43
44 /** 42 /**
45 * Acquires the specified mutex for the specified thread 43 * Elevate the mutex priority to the best priority
46 * @param thread Thread that will acquire the mutex 44 * among the priorities of all its waiting threads.
47 */ 45 */
48 void Acquire(SharedPtr<Thread> thread); 46 void UpdatePriority();
47
48 bool ShouldWait(Thread* thread) const override;
49 void Acquire(Thread* thread) override;
50
51 void AddWaitingThread(SharedPtr<Thread> thread) override;
52 void RemoveWaitingThread(Thread* thread) override;
53
49 void Release(); 54 void Release();
50 55
51private: 56private:
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index bf7600780..5e6139265 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -30,12 +30,12 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou
30 return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore)); 30 return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore));
31} 31}
32 32
33bool Semaphore::ShouldWait() { 33bool Semaphore::ShouldWait(Thread* thread) const {
34 return available_count <= 0; 34 return available_count <= 0;
35} 35}
36 36
37void Semaphore::Acquire() { 37void Semaphore::Acquire(Thread* thread) {
38 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 38 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
39 --available_count; 39 --available_count;
40} 40}
41 41
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index e01908a25..cde94f7cc 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -39,8 +39,8 @@ public:
39 s32 available_count; ///< Number of free slots left in the semaphore 39 s32 available_count; ///< Number of free slots left in the semaphore
40 std::string name; ///< Name of semaphore (optional) 40 std::string name; ///< Name of semaphore (optional)
41 41
42 bool ShouldWait() override; 42 bool ShouldWait(Thread* thread) const override;
43 void Acquire() override; 43 void Acquire(Thread* thread) override;
44 44
45 /** 45 /**
46 * Releases a certain number of slots from a semaphore. 46 * Releases a certain number of slots from a semaphore.
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 6c19aa7c0..fd3bbbcad 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -14,13 +14,13 @@ namespace Kernel {
14ServerPort::ServerPort() {} 14ServerPort::ServerPort() {}
15ServerPort::~ServerPort() {} 15ServerPort::~ServerPort() {}
16 16
17bool ServerPort::ShouldWait() { 17bool ServerPort::ShouldWait(Thread* thread) const {
18 // If there are no pending sessions, we wait until a new one is added. 18 // If there are no pending sessions, we wait until a new one is added.
19 return pending_sessions.size() == 0; 19 return pending_sessions.size() == 0;
20} 20}
21 21
22void ServerPort::Acquire() { 22void ServerPort::Acquire(Thread* thread) {
23 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 23 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
24} 24}
25 25
26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair( 26std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index b0f8df62c..6f8bdb6a9 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -53,8 +53,8 @@ public:
53 /// ServerSessions created from this port inherit a reference to this handler. 53 /// ServerSessions created from this port inherit a reference to this handler.
54 std::shared_ptr<Service::SessionRequestHandler> hle_handler; 54 std::shared_ptr<Service::SessionRequestHandler> hle_handler;
55 55
56 bool ShouldWait() override; 56 bool ShouldWait(Thread* thread) const override;
57 void Acquire() override; 57 void Acquire(Thread* thread) override;
58 58
59private: 59private:
60 ServerPort(); 60 ServerPort();
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 146458c1c..9447ff236 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -29,12 +29,12 @@ ResultVal<SharedPtr<ServerSession>> ServerSession::Create(
29 return MakeResult<SharedPtr<ServerSession>>(std::move(server_session)); 29 return MakeResult<SharedPtr<ServerSession>>(std::move(server_session));
30} 30}
31 31
32bool ServerSession::ShouldWait() { 32bool ServerSession::ShouldWait(Thread* thread) const {
33 return !signaled; 33 return !signaled;
34} 34}
35 35
36void ServerSession::Acquire() { 36void ServerSession::Acquire(Thread* thread) {
37 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 37 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
38 signaled = false; 38 signaled = false;
39} 39}
40 40
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 458284a5d..c088b9a19 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -57,9 +57,9 @@ public:
57 */ 57 */
58 ResultCode HandleSyncRequest(); 58 ResultCode HandleSyncRequest();
59 59
60 bool ShouldWait() override; 60 bool ShouldWait(Thread* thread) const override;
61 61
62 void Acquire() override; 62 void Acquire(Thread* thread) override;
63 63
64 std::string name; ///< The name of this session (optional) 64 std::string name; ///< The name of this session (optional)
65 bool signaled; ///< Whether there's new data available to this ServerSession 65 bool signaled; ///< Whether there's new data available to this ServerSession
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 5fb95dada..9109bd10b 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -27,12 +27,12 @@ namespace Kernel {
27/// Event type for the thread wake up event 27/// Event type for the thread wake up event
28static int ThreadWakeupEventType; 28static int ThreadWakeupEventType;
29 29
30bool Thread::ShouldWait() { 30bool Thread::ShouldWait(Thread* thread) const {
31 return status != THREADSTATUS_DEAD; 31 return status != THREADSTATUS_DEAD;
32} 32}
33 33
34void Thread::Acquire() { 34void Thread::Acquire(Thread* thread) {
35 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 35 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
36} 36}
37 37
38// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing 38// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
@@ -72,7 +72,8 @@ Thread* GetCurrentThread() {
72 * @return True if the thread is waiting, false otherwise 72 * @return True if the thread is waiting, false otherwise
73 */ 73 */
74static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) { 74static bool CheckWait_WaitObject(const Thread* thread, WaitObject* wait_object) {
75 if (thread->status != THREADSTATUS_WAIT_SYNCH) 75 if (thread->status != THREADSTATUS_WAIT_SYNCH_ALL &&
76 thread->status != THREADSTATUS_WAIT_SYNCH_ANY)
76 return false; 77 return false;
77 78
78 auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object); 79 auto itr = std::find(thread->wait_objects.begin(), thread->wait_objects.end(), wait_object);
@@ -90,9 +91,6 @@ static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) {
90} 91}
91 92
92void Thread::Stop() { 93void Thread::Stop() {
93 // Release all the mutexes that this thread holds
94 ReleaseThreadMutexes(this);
95
96 // Cancel any outstanding wakeup events for this thread 94 // Cancel any outstanding wakeup events for this thread
97 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); 95 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
98 wakeup_callback_handle_table.Close(callback_handle); 96 wakeup_callback_handle_table.Close(callback_handle);
@@ -114,6 +112,9 @@ void Thread::Stop() {
114 } 112 }
115 wait_objects.clear(); 113 wait_objects.clear();
116 114
115 // Release all the mutexes that this thread holds
116 ReleaseThreadMutexes(this);
117
117 // Mark the TLS slot in the thread's page as free. 118 // Mark the TLS slot in the thread's page as free.
118 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;
119 u32 tls_slot = 120 u32 tls_slot =
@@ -199,8 +200,8 @@ static void SwitchContext(Thread* new_thread) {
199 200
200 // Load context of new thread 201 // Load context of new thread
201 if (new_thread) { 202 if (new_thread) {
202 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, 203 ASSERT_MSG(new_thread->status == THREADSTATUS_READY,
203 "Thread must be ready to become running."); 204 "Thread must be ready to become running.");
204 205
205 // Cancel any outstanding wakeup events for this thread 206 // Cancel any outstanding wakeup events for this thread
206 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); 207 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
@@ -253,7 +254,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
253 Thread* thread = GetCurrentThread(); 254 Thread* thread = GetCurrentThread();
254 thread->wait_set_output = wait_set_output; 255 thread->wait_set_output = wait_set_output;
255 thread->wait_objects = std::move(wait_objects); 256 thread->wait_objects = std::move(wait_objects);
256 thread->status = THREADSTATUS_WAIT_SYNCH; 257 thread->status = THREADSTATUS_WAIT_SYNCH_ANY;
257} 258}
258 259
259void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { 260void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
@@ -281,7 +282,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
281 return; 282 return;
282 } 283 }
283 284
284 if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { 285 if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
286 thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) {
285 thread->wait_set_output = false; 287 thread->wait_set_output = false;
286 // Remove the thread from each of its waiting objects' waitlists 288 // Remove the thread from each of its waiting objects' waitlists
287 for (auto& object : thread->wait_objects) 289 for (auto& object : thread->wait_objects)
@@ -305,8 +307,11 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
305} 307}
306 308
307void Thread::ResumeFromWait() { 309void Thread::ResumeFromWait() {
310 ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects");
311
308 switch (status) { 312 switch (status) {
309 case THREADSTATUS_WAIT_SYNCH: 313 case THREADSTATUS_WAIT_SYNCH_ALL:
314 case THREADSTATUS_WAIT_SYNCH_ANY:
310 case THREADSTATUS_WAIT_ARB: 315 case THREADSTATUS_WAIT_ARB:
311 case THREADSTATUS_WAIT_SLEEP: 316 case THREADSTATUS_WAIT_SLEEP:
312 break; 317 break;
@@ -515,8 +520,21 @@ void Thread::SetPriority(s32 priority) {
515 nominal_priority = current_priority = priority; 520 nominal_priority = current_priority = priority;
516} 521}
517 522
523void Thread::UpdatePriority() {
524 s32 best_priority = nominal_priority;
525 for (auto& mutex : held_mutexes) {
526 if (mutex->priority < best_priority)
527 best_priority = mutex->priority;
528 }
529 BoostPriority(best_priority);
530}
531
518void Thread::BoostPriority(s32 priority) { 532void Thread::BoostPriority(s32 priority) {
519 ready_queue.move(this, current_priority, priority); 533 // If thread was ready, adjust queues
534 if (status == THREADSTATUS_READY)
535 ready_queue.move(this, current_priority, priority);
536 else
537 ready_queue.prepare(priority);
520 current_priority = priority; 538 current_priority = priority;
521} 539}
522 540
@@ -563,6 +581,12 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
563 context.cpu_registers[1] = output; 581 context.cpu_registers[1] = output;
564} 582}
565 583
584s32 Thread::GetWaitObjectIndex(WaitObject* object) const {
585 ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
586 auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
587 return std::distance(match, wait_objects.rend()) - 1;
588}
589
566//////////////////////////////////////////////////////////////////////////////////////////////////// 590////////////////////////////////////////////////////////////////////////////////////////////////////
567 591
568void ThreadingInit() { 592void ThreadingInit() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index c77ac644d..af72b76ea 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -31,13 +31,14 @@ enum ThreadProcessorId : s32 {
31}; 31};
32 32
33enum ThreadStatus { 33enum ThreadStatus {
34 THREADSTATUS_RUNNING, ///< Currently running 34 THREADSTATUS_RUNNING, ///< Currently running
35 THREADSTATUS_READY, ///< Ready to run 35 THREADSTATUS_READY, ///< Ready to run
36 THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter 36 THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
37 THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC 37 THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
38 THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC 38 THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false
39 THREADSTATUS_DORMANT, ///< Created but not yet made ready 39 THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true
40 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated 40 THREADSTATUS_DORMANT, ///< Created but not yet made ready
41 THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
41}; 42};
42 43
43namespace Kernel { 44namespace Kernel {
@@ -72,8 +73,8 @@ public:
72 return HANDLE_TYPE; 73 return HANDLE_TYPE;
73 } 74 }
74 75
75 bool ShouldWait() override; 76 bool ShouldWait(Thread* thread) const override;
76 void Acquire() override; 77 void Acquire(Thread* thread) override;
77 78
78 /** 79 /**
79 * Gets the thread's current priority 80 * Gets the thread's current priority
@@ -90,6 +91,12 @@ public:
90 void SetPriority(s32 priority); 91 void SetPriority(s32 priority);
91 92
92 /** 93 /**
94 * Boost's a thread's priority to the best priority among the thread's held mutexes.
95 * This prevents priority inversion via priority inheritance.
96 */
97 void UpdatePriority();
98
99 /**
93 * Temporarily boosts the thread's priority until the next time it is scheduled 100 * Temporarily boosts the thread's priority until the next time it is scheduled
94 * @param priority The new priority 101 * @param priority The new priority
95 */ 102 */
@@ -128,13 +135,14 @@ public:
128 135
129 /** 136 /**
130 * Retrieves the index that this particular object occupies in the list of objects 137 * Retrieves the index that this particular object occupies in the list of objects
131 * that the thread passed to WaitSynchronizationN. 138 * that the thread passed to WaitSynchronizationN, starting the search from the last element.
132 * It is used to set the output value of WaitSynchronizationN when the thread is awakened. 139 * It is used to set the output value of WaitSynchronizationN when the thread is awakened.
140 * When a thread wakes up due to an object signal, the kernel will use the index of the last
141 * matching object in the wait objects list in case of having multiple instances of the same
142 * object in the list.
133 * @param object Object to query the index of. 143 * @param object Object to query the index of.
134 */ 144 */
135 s32 GetWaitObjectIndex(const WaitObject* object) const { 145 s32 GetWaitObjectIndex(WaitObject* object) const;
136 return wait_objects_index.at(object->GetObjectId());
137 }
138 146
139 /** 147 /**
140 * Stops a thread, invalidating it from further use 148 * Stops a thread, invalidating it from further use
@@ -152,10 +160,10 @@ public:
152 /** 160 /**
153 * Returns whether this thread is waiting for all the objects in 161 * Returns whether this thread is waiting for all the objects in
154 * its wait list to become ready, as a result of a WaitSynchronizationN call 162 * its wait list to become ready, as a result of a WaitSynchronizationN call
155 * with wait_all = true, or a ReplyAndReceive call. 163 * with wait_all = true.
156 */ 164 */
157 bool IsSleepingOnWaitAll() const { 165 bool IsSleepingOnWaitAll() const {
158 return !wait_objects.empty(); 166 return status == THREADSTATUS_WAIT_SYNCH_ALL;
159 } 167 }
160 168
161 ARM_Interface::ThreadContext context; 169 ARM_Interface::ThreadContext context;
@@ -178,15 +186,15 @@ public:
178 /// Mutexes currently held by this thread, which will be released when it exits. 186 /// Mutexes currently held by this thread, which will be released when it exits.
179 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; 187 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
180 188
189 /// Mutexes that this thread is currently waiting for.
190 boost::container::flat_set<SharedPtr<Mutex>> pending_mutexes;
191
181 SharedPtr<Process> owner_process; ///< Process that owns this thread 192 SharedPtr<Process> owner_process; ///< Process that owns this thread
182 193
183 /// Objects that the thread is waiting on. 194 /// Objects that the thread is waiting on, in the same order as they were
184 /// This is only populated when the thread should wait for all the objects to become ready. 195 // passed to WaitSynchronization1/N.
185 std::vector<SharedPtr<WaitObject>> wait_objects; 196 std::vector<SharedPtr<WaitObject>> wait_objects;
186 197
187 /// Mapping of Object ids to their position in the last waitlist that this object waited on.
188 boost::container::flat_map<int, s32> wait_objects_index;
189
190 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address 198 VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
191 199
192 /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. 200 /// True if the WaitSynchronizationN output parameter should be set on thread wakeup.
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index b50cf520d..8f2bc4c7f 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -39,12 +39,12 @@ SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
39 return timer; 39 return timer;
40} 40}
41 41
42bool Timer::ShouldWait() { 42bool Timer::ShouldWait(Thread* thread) const {
43 return !signaled; 43 return !signaled;
44} 44}
45 45
46void Timer::Acquire() { 46void Timer::Acquire(Thread* thread) {
47 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 47 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
48 48
49 if (reset_type == ResetType::OneShot) 49 if (reset_type == ResetType::OneShot)
50 signaled = false; 50 signaled = false;
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index 18ea0236b..2e3b31b23 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -39,8 +39,8 @@ public:
39 u64 initial_delay; ///< The delay until the timer fires for the first time 39 u64 initial_delay; ///< The delay until the timer fires for the first time
40 u64 interval_delay; ///< The delay until the timer fires after the first time 40 u64 interval_delay; ///< The delay until the timer fires after the first time
41 41
42 bool ShouldWait() override; 42 bool ShouldWait(Thread* thread) const override;
43 void Acquire() override; 43 void Acquire(Thread* thread) override;
44 44
45 /** 45 /**
46 * Starts the timer, with the specified initial delay and interval. 46 * Starts the timer, with the specified initial delay and interval.