summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-14 19:22:50 -0500
committerGravatar bunnei2015-01-21 18:41:00 -0500
commitc22bac6398ff1705992fc44b2c29775c84cff662 (patch)
treee20da7e6e1824c19b7ced73f43815397749ffae7 /src
parentMerge pull request #491 from archshift/hidspvr (diff)
downloadyuzu-c22bac6398ff1705992fc44b2c29775c84cff662.tar.gz
yuzu-c22bac6398ff1705992fc44b2c29775c84cff662.tar.xz
yuzu-c22bac6398ff1705992fc44b2c29775c84cff662.zip
Kernel: Added WaitObject and changed "waitable" objects inherit from it.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/event.cpp26
-rw-r--r--src/core/hle/kernel/kernel.cpp26
-rw-r--r--src/core/hle/kernel/kernel.h25
-rw-r--r--src/core/hle/kernel/mutex.cpp29
-rw-r--r--src/core/hle/kernel/semaphore.cpp11
-rw-r--r--src/core/hle/kernel/thread.cpp11
-rw-r--r--src/core/hle/kernel/thread.h4
-rw-r--r--src/core/hle/kernel/timer.cpp12
8 files changed, 73 insertions, 71 deletions
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 271190dbe..bf71e9edb 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -14,7 +14,7 @@
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17class Event : public Object { 17class Event : public WaitObject {
18public: 18public:
19 std::string GetTypeName() const override { return "Event"; } 19 std::string GetTypeName() const override { return "Event"; }
20 std::string GetName() const override { return name; } 20 std::string GetName() const override { return name; }
@@ -27,16 +27,12 @@ public:
27 27
28 bool locked; ///< Event signal wait 28 bool locked; ///< Event signal wait
29 bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough) 29 bool permanent_locked; ///< Hack - to set event permanent state (for easy passthrough)
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional) 30 std::string name; ///< Name of event (optional)
32 31
33 ResultVal<bool> WaitSynchronization() override { 32 ResultVal<bool> WaitSynchronization() override {
34 bool wait = locked; 33 bool wait = locked;
35 if (locked) { 34 if (locked) {
36 Handle thread = GetCurrentThread()->GetHandle(); 35 AddWaitingThread(GetCurrentThread());
37 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
38 waiting_threads.push_back(thread);
39 }
40 Kernel::WaitCurrentThread(WAITTYPE_EVENT, this); 36 Kernel::WaitCurrentThread(WAITTYPE_EVENT, this);
41 } 37 }
42 if (reset_type != RESETTYPE_STICKY && !permanent_locked) { 38 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
@@ -86,20 +82,12 @@ ResultCode SignalEvent(const Handle handle) {
86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); 82 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
87 83
88 // Resume threads waiting for event to signal 84 // Resume threads waiting for event to signal
89 bool event_caught = false; 85 bool event_caught = evt->ResumeAllWaitingThreads();
90 for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
91 Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]).get();
92 if (thread != nullptr)
93 thread->ResumeFromWait();
94
95 // If any thread is signalled awake by this event, assume the event was "caught" and reset
96 // the event. This will result in the next thread waiting on the event to block. Otherwise,
97 // the event will not be reset, and the next thread to call WaitSynchronization on it will
98 // not block. Not sure if this is correct behavior, but it seems to work.
99 event_caught = true;
100 }
101 evt->waiting_threads.clear();
102 86
87 // If any thread is signalled awake by this event, assume the event was "caught" and reset
88 // the event. This will result in the next thread waiting on the event to block. Otherwise,
89 // the event will not be reset, and the next thread to call WaitSynchronization on it will
90 // not block. Not sure if this is correct behavior, but it seems to work.
103 if (!evt->permanent_locked) { 91 if (!evt->permanent_locked) {
104 evt->locked = event_caught; 92 evt->locked = event_caught;
105 } 93 }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d3684896f..07e96e633 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -18,6 +18,32 @@ SharedPtr<Thread> g_main_thread = nullptr;
18HandleTable g_handle_table; 18HandleTable g_handle_table;
19u64 g_program_id = 0; 19u64 g_program_id = 0;
20 20
21void WaitObject::AddWaitingThread(Thread* thread) {
22 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
23 waiting_threads.push_back(thread);
24 }
25}
26
27Thread* WaitObject::ResumeNextThread() {
28 if (waiting_threads.empty()) return nullptr;
29
30 auto next_thread = waiting_threads.front();
31
32 next_thread->ResumeFromWait();
33 waiting_threads.erase(waiting_threads.begin());
34
35 return next_thread.get();
36}
37
38void WaitObject::ReleaseAllWaitingThreads() {
39 auto waiting_threads_copy = waiting_threads;
40
41 for (auto thread : waiting_threads_copy)
42 thread->ReleaseWaitObject(this);
43
44 waiting_threads.clear();
45}
46
21HandleTable::HandleTable() { 47HandleTable::HandleTable() {
22 next_generation = 1; 48 next_generation = 1;
23 Clear(); 49 Clear();
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 5e5217b78..a9af9de88 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -8,6 +8,8 @@
8 8
9#include <array> 9#include <array>
10#include <string> 10#include <string>
11#include <vector>
12
11#include "common/common.h" 13#include "common/common.h"
12#include "core/hle/result.h" 14#include "core/hle/result.h"
13 15
@@ -92,6 +94,29 @@ inline void intrusive_ptr_release(Object* object) {
92template <typename T> 94template <typename T>
93using SharedPtr = boost::intrusive_ptr<T>; 95using SharedPtr = boost::intrusive_ptr<T>;
94 96
97/// Class that represents a Kernel object that a thread can be waiting on
98class WaitObject : public Object {
99public:
100
101 /**
102 * Add a thread to wait on this object
103 * @param thread Pointer to thread to add
104 */
105 void AddWaitingThread(Thread* thread);
106
107 /**
108 * Resumes the next thread waiting on this object
109 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
110 */
111 Thread* ResumeNextThread();
112
113 /// Releases all threads waiting on this object
114 void ReleaseAllWaitingThreads();
115
116private:
117 std::vector<Thread*> waiting_threads; ///< Threads waiting for this object to become available
118};
119
95/** 120/**
96 * This class allows the creation of Handles, which are references to objects that can be tested 121 * This class allows the creation of Handles, which are references to objects that can be tested
97 * for validity and looked up. Here they are used to pass references to kernel objects to/from the 122 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 853a5dd74..35d829606 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -13,7 +13,7 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class Mutex : public Object { 16class Mutex : public WaitObject {
17public: 17public:
18 std::string GetTypeName() const override { return "Mutex"; } 18 std::string GetTypeName() const override { return "Mutex"; }
19 std::string GetName() const override { return name; } 19 std::string GetName() const override { return name; }
@@ -24,7 +24,6 @@ public:
24 bool initial_locked; ///< Initial lock state when mutex was created 24 bool initial_locked; ///< Initial lock state when mutex was created
25 bool locked; ///< Current locked state 25 bool locked; ///< Current locked state
26 Handle lock_thread; ///< Handle to thread that currently has mutex 26 Handle lock_thread; ///< Handle to thread that currently has mutex
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 27 std::string name; ///< Name of mutex (optional)
29 28
30 ResultVal<bool> WaitSynchronization() override; 29 ResultVal<bool> WaitSynchronization() override;
@@ -45,36 +44,20 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl
45 mutex->lock_thread = thread; 44 mutex->lock_thread = thread;
46} 45}
47 46
48bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) {
49 MutexAcquireLock(mutex, thread_handle);
50
51 Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get();
52 if (thread == nullptr) {
53 LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle);
54 return false;
55 }
56
57 thread->ResumeFromWait();
58 return true;
59}
60
61/** 47/**
62 * Resumes a thread waiting for the specified mutex 48 * Resumes a thread waiting for the specified mutex
63 * @param mutex The mutex that some thread is waiting on 49 * @param mutex The mutex that some thread is waiting on
64 */ 50 */
65void ResumeWaitingThread(Mutex* mutex) { 51void ResumeWaitingThread(Mutex* mutex) {
66 // Find the next waiting thread for the mutex... 52 // Find the next waiting thread for the mutex...
67 if (mutex->waiting_threads.empty()) { 53 auto next_thread = mutex->ResumeNextThread();
54 if (next_thread != nullptr) {
55 MutexAcquireLock(mutex, next_thread->GetHandle());
56 } else {
68 // Reset mutex lock thread handle, nothing is waiting 57 // Reset mutex lock thread handle, nothing is waiting
69 mutex->locked = false; 58 mutex->locked = false;
70 mutex->lock_thread = -1; 59 mutex->lock_thread = -1;
71 } 60 }
72 else {
73 // Resume the next waiting thread and re-lock the mutex
74 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
75 ReleaseMutexForThread(mutex, *iter);
76 mutex->waiting_threads.erase(iter);
77 }
78} 61}
79 62
80void MutexEraseLock(Mutex* mutex) { 63void MutexEraseLock(Mutex* mutex) {
@@ -175,7 +158,7 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
175ResultVal<bool> Mutex::WaitSynchronization() { 158ResultVal<bool> Mutex::WaitSynchronization() {
176 bool wait = locked; 159 bool wait = locked;
177 if (locked) { 160 if (locked) {
178 waiting_threads.push_back(GetCurrentThread()->GetHandle()); 161 AddWaitingThread(GetCurrentThread());
179 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this); 162 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, this);
180 } else { 163 } else {
181 // Lock the mutex when the first thread accesses it 164 // Lock the mutex when the first thread accesses it
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 88ec9a104..af2c465e4 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -12,7 +12,7 @@
12 12
13namespace Kernel { 13namespace Kernel {
14 14
15class Semaphore : public Object { 15class Semaphore : public WaitObject {
16public: 16public:
17 std::string GetTypeName() const override { return "Semaphore"; } 17 std::string GetTypeName() const override { return "Semaphore"; }
18 std::string GetName() const override { return name; } 18 std::string GetName() const override { return name; }
@@ -22,7 +22,6 @@ public:
22 22
23 s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have 23 s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
24 s32 available_count; ///< Number of free slots left in the semaphore 24 s32 available_count; ///< Number of free slots left in the semaphore
25 std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
26 std::string name; ///< Name of semaphore (optional) 25 std::string name; ///< Name of semaphore (optional)
27 26
28 /** 27 /**
@@ -38,7 +37,7 @@ public:
38 37
39 if (wait) { 38 if (wait) {
40 Kernel::WaitCurrentThread(WAITTYPE_SEMA, this); 39 Kernel::WaitCurrentThread(WAITTYPE_SEMA, this);
41 waiting_threads.push(GetCurrentThread()->GetHandle()); 40 AddWaitingThread(GetCurrentThread());
42 } else { 41 } else {
43 --available_count; 42 --available_count;
44 } 43 }
@@ -83,11 +82,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
83 82
84 // Notify some of the threads that the semaphore has been released 83 // Notify some of the threads that the semaphore has been released
85 // stop once the semaphore is full again or there are no more waiting threads 84 // stop once the semaphore is full again or there are no more waiting threads
86 while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { 85 while (semaphore->IsAvailable() && semaphore->ResumeNextThread() != nullptr) {
87 Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()).get();
88 if (thread != nullptr)
89 thread->ResumeFromWait();
90 semaphore->waiting_threads.pop();
91 --semaphore->available_count; 86 --semaphore->available_count;
92 } 87 }
93 88
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index bc86a7c59..845672702 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -25,10 +25,7 @@ namespace Kernel {
25ResultVal<bool> Thread::WaitSynchronization() { 25ResultVal<bool> Thread::WaitSynchronization() {
26 const bool wait = status != THREADSTATUS_DORMANT; 26 const bool wait = status != THREADSTATUS_DORMANT;
27 if (wait) { 27 if (wait) {
28 Thread* thread = GetCurrentThread(); 28 AddWaitingThread(GetCurrentThread());
29 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
30 waiting_threads.push_back(thread);
31 }
32 WaitCurrentThread(WAITTYPE_THREADEND, this); 29 WaitCurrentThread(WAITTYPE_THREADEND, this);
33 } 30 }
34 31
@@ -110,11 +107,7 @@ void Thread::Stop(const char* reason) {
110 107
111 ChangeReadyState(this, false); 108 ChangeReadyState(this, false);
112 status = THREADSTATUS_DORMANT; 109 status = THREADSTATUS_DORMANT;
113 for (auto& waiting_thread : waiting_threads) { 110 ResumeAllWaitingThreads();
114 if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this))
115 waiting_thread->ResumeFromWait();
116 }
117 waiting_threads.clear();
118 111
119 // Stopped threads are never waiting. 112 // Stopped threads are never waiting.
120 wait_type = WAITTYPE_NONE; 113 wait_type = WAITTYPE_NONE;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 8c9f63aa5..daaeb26a4 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -52,7 +52,7 @@ enum WaitType {
52 52
53namespace Kernel { 53namespace Kernel {
54 54
55class Thread : public Kernel::Object { 55class Thread : public WaitObject {
56public: 56public:
57 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, 57 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
58 u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size); 58 u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size);
@@ -99,8 +99,6 @@ public:
99 Object* wait_object; 99 Object* wait_object;
100 VAddr wait_address; 100 VAddr wait_address;
101 101
102 std::vector<SharedPtr<Thread>> waiting_threads;
103
104 std::string name; 102 std::string name;
105 103
106 /// Whether this thread is intended to never actually be executed, i.e. always idle 104 /// Whether this thread is intended to never actually be executed, i.e. always idle
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 3b0452d4d..2d4fa4c01 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -13,7 +13,7 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class Timer : public Object { 16class Timer : public WaitObject {
17public: 17public:
18 std::string GetTypeName() const override { return "Timer"; } 18 std::string GetTypeName() const override { return "Timer"; }
19 std::string GetName() const override { return name; } 19 std::string GetName() const override { return name; }
@@ -24,7 +24,6 @@ public:
24 ResetType reset_type; ///< The ResetType of this timer 24 ResetType reset_type; ///< The ResetType of this timer
25 25
26 bool signaled; ///< Whether the timer has been signaled or not 26 bool signaled; ///< Whether the timer has been signaled or not
27 std::set<Handle> waiting_threads; ///< Threads that are waiting for the timer
28 std::string name; ///< Name of timer (optional) 27 std::string name; ///< Name of timer (optional)
29 28
30 u64 initial_delay; ///< The delay until the timer fires for the first time 29 u64 initial_delay; ///< The delay until the timer fires for the first time
@@ -33,7 +32,7 @@ public:
33 ResultVal<bool> WaitSynchronization() override { 32 ResultVal<bool> WaitSynchronization() override {
34 bool wait = !signaled; 33 bool wait = !signaled;
35 if (wait) { 34 if (wait) {
36 waiting_threads.insert(GetCurrentThread()->GetHandle()); 35 AddWaitingThread(GetCurrentThread());
37 Kernel::WaitCurrentThread(WAITTYPE_TIMER, this); 36 Kernel::WaitCurrentThread(WAITTYPE_TIMER, this);
38 } 37 }
39 return MakeResult<bool>(wait); 38 return MakeResult<bool>(wait);
@@ -92,12 +91,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
92 timer->signaled = true; 91 timer->signaled = true;
93 92
94 // Resume all waiting threads 93 // Resume all waiting threads
95 for (Handle thread_handle : timer->waiting_threads) { 94 timer->ResumeAllWaitingThreads();
96 if (SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(thread_handle))
97 thread->ResumeFromWait();
98 }
99
100 timer->waiting_threads.clear();
101 95
102 if (timer->reset_type == RESETTYPE_ONESHOT) 96 if (timer->reset_type == RESETTYPE_ONESHOT)
103 timer->signaled = false; 97 timer->signaled = false;