summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2017-05-29 15:45:30 -0700
committerGravatar Yuri Kunde Schlesner2017-05-29 16:16:46 -0700
commit64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4 (patch)
treef34182d882d614273dd709f0029039743bc58c21 /src/core
parentKernel: Removed HandleTable::GetWaitObject (diff)
downloadyuzu-64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4.tar.gz
yuzu-64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4.tar.xz
yuzu-64ecf81a3cf6d6e0a4e4e915e1da2f0bcf2f1cb4.zip
Kernel: Move WaitObject to a separate file
Now that HandleTable doesn't directly depend on WaitObject anymore, this can be separated from the main kernel.h header.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/event.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp79
-rw-r--r--src/core/hle/kernel/kernel.h53
-rw-r--r--src/core/hle/kernel/mutex.h1
-rw-r--r--src/core/hle/kernel/semaphore.h1
-rw-r--r--src/core/hle/kernel/server_port.h1
-rw-r--r--src/core/hle/kernel/server_session.h1
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/timer.h1
-rw-r--r--src/core/hle/kernel/wait_object.cpp99
-rw-r--r--src/core/hle/kernel/wait_object.h67
-rw-r--r--src/core/hle/svc.cpp1
13 files changed, 176 insertions, 132 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 7aa81e885..ba24a6e02 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRCS
57 hle/kernel/thread.cpp 57 hle/kernel/thread.cpp
58 hle/kernel/timer.cpp 58 hle/kernel/timer.cpp
59 hle/kernel/vm_manager.cpp 59 hle/kernel/vm_manager.cpp
60 hle/kernel/wait_object.cpp
60 hle/service/ac/ac.cpp 61 hle/service/ac/ac.cpp
61 hle/service/ac/ac_i.cpp 62 hle/service/ac/ac_i.cpp
62 hle/service/ac/ac_u.cpp 63 hle/service/ac/ac_u.cpp
@@ -249,6 +250,7 @@ set(HEADERS
249 hle/kernel/thread.h 250 hle/kernel/thread.h
250 hle/kernel/timer.h 251 hle/kernel/timer.h
251 hle/kernel/vm_manager.h 252 hle/kernel/vm_manager.h
253 hle/kernel/wait_object.h
252 hle/result.h 254 hle/result.h
253 hle/service/ac/ac.h 255 hle/service/ac/ac.h
254 hle/service/ac/ac_i.h 256 hle/service/ac/ac_i.h
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 3e3673508..cc41abb85 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/wait_object.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 7f84e01aa..b0af5b9b8 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -20,85 +20,6 @@ namespace Kernel {
20unsigned int Object::next_object_id; 20unsigned int Object::next_object_id;
21HandleTable g_handle_table; 21HandleTable g_handle_table;
22 22
23void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
24 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
25 if (itr == waiting_threads.end())
26 waiting_threads.push_back(std::move(thread));
27}
28
29void WaitObject::RemoveWaitingThread(Thread* thread) {
30 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
31 // If a thread passed multiple handles to the same object,
32 // the kernel might attempt to remove the thread from the object's
33 // waiting threads list multiple times.
34 if (itr != waiting_threads.end())
35 waiting_threads.erase(itr);
36}
37
38SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
39 Thread* candidate = nullptr;
40 s32 candidate_priority = THREADPRIO_LOWEST + 1;
41
42 for (const auto& thread : waiting_threads) {
43 // The list of waiting threads must not contain threads that are not waiting to be awakened.
44 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
45 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
46 "Inconsistent thread statuses in waiting_threads");
47
48 if (thread->current_priority >= candidate_priority)
49 continue;
50
51 if (ShouldWait(thread.get()))
52 continue;
53
54 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
55 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
56 bool ready_to_run = true;
57 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
58 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
59 [&thread](const SharedPtr<WaitObject>& object) {
60 return object->ShouldWait(thread.get());
61 });
62 }
63
64 if (ready_to_run) {
65 candidate = thread.get();
66 candidate_priority = thread->current_priority;
67 }
68 }
69
70 return candidate;
71}
72
73void WaitObject::WakeupAllWaitingThreads() {
74 while (auto thread = GetHighestPriorityReadyThread()) {
75 if (!thread->IsSleepingOnWaitAll()) {
76 Acquire(thread.get());
77 // Set the output index of the WaitSynchronizationN call to the index of this object.
78 if (thread->wait_set_output) {
79 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
80 thread->wait_set_output = false;
81 }
82 } else {
83 for (auto& object : thread->wait_objects) {
84 object->Acquire(thread.get());
85 }
86 // Note: This case doesn't update the output index of WaitSynchronizationN.
87 }
88
89 for (auto& object : thread->wait_objects)
90 object->RemoveWaitingThread(thread.get());
91 thread->wait_objects.clear();
92
93 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
94 thread->ResumeFromWait();
95 }
96}
97
98const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
99 return waiting_threads;
100}
101
102HandleTable::HandleTable() { 23HandleTable::HandleTable() {
103 next_generation = 1; 24 next_generation = 1;
104 Clear(); 25 Clear();
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 4344264dc..5335a961d 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -17,8 +17,6 @@ namespace Kernel {
17 17
18using Handle = u32; 18using Handle = u32;
19 19
20class Thread;
21
22enum KernelHandle : Handle { 20enum KernelHandle : Handle {
23 CurrentThread = 0xFFFF8000, 21 CurrentThread = 0xFFFF8000,
24 CurrentProcess = 0xFFFF8001, 22 CurrentProcess = 0xFFFF8001,
@@ -133,57 +131,6 @@ inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
133 return nullptr; 131 return nullptr;
134} 132}
135 133
136/// Class that represents a Kernel object that a thread can be waiting on
137class WaitObject : public Object {
138public:
139 /**
140 * Check if the specified thread should wait until the object is available
141 * @param thread The thread about which we're deciding.
142 * @return True if the current thread should wait due to this object being unavailable
143 */
144 virtual bool ShouldWait(Thread* thread) const = 0;
145
146 /// Acquire/lock the object for the specified thread if it is available
147 virtual void Acquire(Thread* thread) = 0;
148
149 /**
150 * Add a thread to wait on this object
151 * @param thread Pointer to thread to add
152 */
153 virtual void AddWaitingThread(SharedPtr<Thread> thread);
154
155 /**
156 * Removes a thread from waiting on this object (e.g. if it was resumed already)
157 * @param thread Pointer to thread to remove
158 */
159 virtual void RemoveWaitingThread(Thread* thread);
160
161 /**
162 * Wake up all threads waiting on this object that can be awoken, in priority order,
163 * and set the synchronization result and output of the thread.
164 */
165 virtual void WakeupAllWaitingThreads();
166
167 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
168 SharedPtr<Thread> GetHighestPriorityReadyThread();
169
170 /// Get a const reference to the waiting threads list for debug use
171 const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
172
173private:
174 /// Threads waiting for this object to become available
175 std::vector<SharedPtr<Thread>> waiting_threads;
176};
177
178// Specialization of DynamicObjectCast for WaitObjects
179template <>
180inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
181 if (object != nullptr && object->IsWaitable()) {
182 return boost::static_pointer_cast<WaitObject>(std::move(object));
183 }
184 return nullptr;
185}
186
187/** 134/**
188 * This class allows the creation of Handles, which are references to objects that can be tested 135 * This class allows the creation of Handles, which are references to objects that can be tested
189 * for validity and looked up. Here they are used to pass references to kernel objects to/from the 136 * 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.h b/src/core/hle/kernel/mutex.h
index c57adf400..bacacd690 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/kernel.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/wait_object.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index cde94f7cc..ca6f908aa 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -8,6 +8,7 @@
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/wait_object.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 6f8bdb6a9..2a24d8412 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -9,6 +9,7 @@
9#include <tuple> 9#include <tuple>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/wait_object.h"
12 13
13namespace Service { 14namespace Service {
14class SessionRequestHandler; 15class SessionRequestHandler;
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index c907d487c..315b80d14 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -11,6 +11,7 @@
11#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/session.h" 12#include "core/hle/kernel/session.h"
13#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
14#include "core/hle/kernel/wait_object.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
15#include "core/hle/service/service.h" 16#include "core/hle/service/service.h"
16#include "core/memory.h" 17#include "core/memory.h"
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 7b5169cfc..6a3566f15 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,6 +12,7 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/wait_object.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16 17
17enum ThreadPriority : s32 { 18enum ThreadPriority : s32 {
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index b0f818933..82552372d 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -6,6 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/wait_object.h"
9 10
10namespace Kernel { 11namespace Kernel {
11 12
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
new file mode 100644
index 000000000..f245eda6c
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -0,0 +1,99 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/config_mem.h"
9#include "core/hle/kernel/errors.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory.h"
12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/kernel/thread.h"
15#include "core/hle/kernel/timer.h"
16#include "core/hle/shared_page.h"
17
18namespace Kernel {
19
20void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
21 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
22 if (itr == waiting_threads.end())
23 waiting_threads.push_back(std::move(thread));
24}
25
26void WaitObject::RemoveWaitingThread(Thread* thread) {
27 auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
28 // If a thread passed multiple handles to the same object,
29 // the kernel might attempt to remove the thread from the object's
30 // waiting threads list multiple times.
31 if (itr != waiting_threads.end())
32 waiting_threads.erase(itr);
33}
34
35SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
36 Thread* candidate = nullptr;
37 s32 candidate_priority = THREADPRIO_LOWEST + 1;
38
39 for (const auto& thread : waiting_threads) {
40 // The list of waiting threads must not contain threads that are not waiting to be awakened.
41 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
42 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
43 "Inconsistent thread statuses in waiting_threads");
44
45 if (thread->current_priority >= candidate_priority)
46 continue;
47
48 if (ShouldWait(thread.get()))
49 continue;
50
51 // A thread is ready to run if it's either in THREADSTATUS_WAIT_SYNCH_ANY or
52 // in THREADSTATUS_WAIT_SYNCH_ALL and the rest of the objects it is waiting on are ready.
53 bool ready_to_run = true;
54 if (thread->status == THREADSTATUS_WAIT_SYNCH_ALL) {
55 ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
56 [&thread](const SharedPtr<WaitObject>& object) {
57 return object->ShouldWait(thread.get());
58 });
59 }
60
61 if (ready_to_run) {
62 candidate = thread.get();
63 candidate_priority = thread->current_priority;
64 }
65 }
66
67 return candidate;
68}
69
70void WaitObject::WakeupAllWaitingThreads() {
71 while (auto thread = GetHighestPriorityReadyThread()) {
72 if (!thread->IsSleepingOnWaitAll()) {
73 Acquire(thread.get());
74 // Set the output index of the WaitSynchronizationN call to the index of this object.
75 if (thread->wait_set_output) {
76 thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
77 thread->wait_set_output = false;
78 }
79 } else {
80 for (auto& object : thread->wait_objects) {
81 object->Acquire(thread.get());
82 }
83 // Note: This case doesn't update the output index of WaitSynchronizationN.
84 }
85
86 for (auto& object : thread->wait_objects)
87 object->RemoveWaitingThread(thread.get());
88 thread->wait_objects.clear();
89
90 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
91 thread->ResumeFromWait();
92 }
93}
94
95const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
96 return waiting_threads;
97}
98
99} // namespace Kernel
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
new file mode 100644
index 000000000..861578186
--- /dev/null
+++ b/src/core/hle/kernel/wait_object.h
@@ -0,0 +1,67 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include <boost/smart_ptr/intrusive_ptr.hpp>
9#include "common/common_types.h"
10#include "core/hle/kernel/kernel.h"
11
12namespace Kernel {
13
14class Thread;
15
16/// Class that represents a Kernel object that a thread can be waiting on
17class WaitObject : public Object {
18public:
19 /**
20 * Check if the specified thread should wait until the object is available
21 * @param thread The thread about which we're deciding.
22 * @return True if the current thread should wait due to this object being unavailable
23 */
24 virtual bool ShouldWait(Thread* thread) const = 0;
25
26 /// Acquire/lock the object for the specified thread if it is available
27 virtual void Acquire(Thread* thread) = 0;
28
29 /**
30 * Add a thread to wait on this object
31 * @param thread Pointer to thread to add
32 */
33 virtual void AddWaitingThread(SharedPtr<Thread> thread);
34
35 /**
36 * Removes a thread from waiting on this object (e.g. if it was resumed already)
37 * @param thread Pointer to thread to remove
38 */
39 virtual void RemoveWaitingThread(Thread* thread);
40
41 /**
42 * Wake up all threads waiting on this object that can be awoken, in priority order,
43 * and set the synchronization result and output of the thread.
44 */
45 virtual void WakeupAllWaitingThreads();
46
47 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
48 SharedPtr<Thread> GetHighestPriorityReadyThread();
49
50 /// Get a const reference to the waiting threads list for debug use
51 const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
52
53private:
54 /// Threads waiting for this object to become available
55 std::vector<SharedPtr<Thread>> waiting_threads;
56};
57
58// Specialization of DynamicObjectCast for WaitObjects
59template <>
60inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
61 if (object != nullptr && object->IsWaitable()) {
62 return boost::static_pointer_cast<WaitObject>(std::move(object));
63 }
64 return nullptr;
65}
66
67} // namespace Kernel
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 243c54c6e..83767677f 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -27,6 +27,7 @@
27#include "core/hle/kernel/thread.h" 27#include "core/hle/kernel/thread.h"
28#include "core/hle/kernel/timer.h" 28#include "core/hle/kernel/timer.h"
29#include "core/hle/kernel/vm_manager.h" 29#include "core/hle/kernel/vm_manager.h"
30#include "core/hle/kernel/wait_object.h"
30#include "core/hle/result.h" 31#include "core/hle/result.h"
31#include "core/hle/service/service.h" 32#include "core/hle/service/service.h"
32 33