summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/kernel.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.h')
-rw-r--r--src/core/hle/kernel/kernel.h181
1 files changed, 9 insertions, 172 deletions
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 94f2025a0..9cf288b08 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,26 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <array>
9#include <cstddef> 7#include <cstddef>
10#include <string> 8#include <string>
11#include <vector> 9#include <utility>
12#include <boost/smart_ptr/intrusive_ptr.hpp> 10#include <boost/smart_ptr/intrusive_ptr.hpp>
13#include "common/common_types.h" 11#include "common/common_types.h"
14#include "core/hle/result.h"
15 12
16namespace Kernel { 13namespace Kernel {
17 14
18using Handle = u32; 15using Handle = u32;
19 16
20class Thread;
21
22enum KernelHandle : Handle {
23 CurrentThread = 0xFFFF8000,
24 CurrentProcess = 0xFFFF8001,
25};
26
27enum class HandleType : u32 { 17enum class HandleType : u32 {
28 Unknown, 18 Unknown,
29 Event, 19 Event,
@@ -121,170 +111,17 @@ inline void intrusive_ptr_release(Object* object) {
121template <typename T> 111template <typename T>
122using SharedPtr = boost::intrusive_ptr<T>; 112using SharedPtr = boost::intrusive_ptr<T>;
123 113
124/// Class that represents a Kernel object that a thread can be waiting on
125class WaitObject : public Object {
126public:
127 /**
128 * Check if the specified thread should wait until the object is available
129 * @param thread The thread about which we're deciding.
130 * @return True if the current thread should wait due to this object being unavailable
131 */
132 virtual bool ShouldWait(Thread* thread) const = 0;
133
134 /// Acquire/lock the object for the specified thread if it is available
135 virtual void Acquire(Thread* thread) = 0;
136
137 /**
138 * Add a thread to wait on this object
139 * @param thread Pointer to thread to add
140 */
141 virtual void AddWaitingThread(SharedPtr<Thread> thread);
142
143 /**
144 * Removes a thread from waiting on this object (e.g. if it was resumed already)
145 * @param thread Pointer to thread to remove
146 */
147 virtual void RemoveWaitingThread(Thread* thread);
148
149 /**
150 * Wake up all threads waiting on this object that can be awoken, in priority order,
151 * and set the synchronization result and output of the thread.
152 */
153 virtual void WakeupAllWaitingThreads();
154
155 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
156 SharedPtr<Thread> GetHighestPriorityReadyThread();
157
158 /// Get a const reference to the waiting threads list for debug use
159 const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
160
161private:
162 /// Threads waiting for this object to become available
163 std::vector<SharedPtr<Thread>> waiting_threads;
164};
165
166/** 114/**
167 * This class allows the creation of Handles, which are references to objects that can be tested 115 * Attempts to downcast the given Object pointer to a pointer to T.
168 * for validity and looked up. Here they are used to pass references to kernel objects to/from the 116 * @return Derived pointer to the object, or `nullptr` if `object` isn't of type T.
169 * emulated process. it has been designed so that it follows the same handle format and has
170 * approximately the same restrictions as the handle manager in the CTR-OS.
171 *
172 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
173 * The slot index is used to index into the arrays in this class to access the data corresponding
174 * to the Handle.
175 *
176 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
177 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
178 * value of the counter is stored into the Handle as well as in the handle table (in the
179 * "generations" array). When looking up a handle, the Handle's generation must match with the
180 * value stored on the class, otherwise the Handle is considered invalid.
181 *
182 * To find free slots when allocating a Handle without needing to scan the entire object array, the
183 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
184 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
185 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
186 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
187 * verified and isn't likely to cause any problems.
188 */ 117 */
189class HandleTable final : NonCopyable { 118template <typename T>
190public: 119inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
191 HandleTable(); 120 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
192 121 return boost::static_pointer_cast<T>(std::move(object));
193 /**
194 * Allocates a handle for the given object.
195 * @return The created Handle or one of the following errors:
196 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
197 */
198 ResultVal<Handle> Create(SharedPtr<Object> obj);
199
200 /**
201 * Returns a new handle that points to the same object as the passed in handle.
202 * @return The duplicated Handle or one of the following errors:
203 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
204 * - Any errors returned by `Create()`.
205 */
206 ResultVal<Handle> Duplicate(Handle handle);
207
208 /**
209 * Closes a handle, removing it from the table and decreasing the object's ref-count.
210 * @return `RESULT_SUCCESS` or one of the following errors:
211 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
212 */
213 ResultCode Close(Handle handle);
214
215 /// Checks if a handle is valid and points to an existing object.
216 bool IsValid(Handle handle) const;
217
218 /**
219 * Looks up a handle.
220 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
221 */
222 SharedPtr<Object> GetGeneric(Handle handle) const;
223
224 /**
225 * Looks up a handle while verifying its type.
226 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
227 * type differs from the handle type `T::HANDLE_TYPE`.
228 */
229 template <class T>
230 SharedPtr<T> Get(Handle handle) const {
231 SharedPtr<Object> object = GetGeneric(handle);
232 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
233 return boost::static_pointer_cast<T>(std::move(object));
234 }
235 return nullptr;
236 }
237
238 /**
239 * Looks up a handle while verifying that it is an object that a thread can wait on
240 * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or it is
241 * not a waitable object.
242 */
243 SharedPtr<WaitObject> GetWaitObject(Handle handle) const {
244 SharedPtr<Object> object = GetGeneric(handle);
245 if (object != nullptr && object->IsWaitable()) {
246 return boost::static_pointer_cast<WaitObject>(std::move(object));
247 }
248 return nullptr;
249 }
250
251 /// Closes all handles held in this table.
252 void Clear();
253
254private:
255 /**
256 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
257 * reduced by ExHeader values, but this is not emulated here.
258 */
259 static const size_t MAX_COUNT = 4096;
260
261 static u16 GetSlot(Handle handle) {
262 return handle >> 15;
263 }
264 static u16 GetGeneration(Handle handle) {
265 return handle & 0x7FFF;
266 } 122 }
267 123 return nullptr;
268 /// Stores the Object referenced by the handle or null if the slot is empty. 124}
269 std::array<SharedPtr<Object>, MAX_COUNT> objects;
270
271 /**
272 * The value of `next_generation` when the handle was created, used to check for validity. For
273 * empty slots, contains the index of the next free slot in the list.
274 */
275 std::array<u16, MAX_COUNT> generations;
276
277 /**
278 * Global counter of the number of created handles. Stored in `generations` when a handle is
279 * created, and wraps around to 1 when it hits 0x8000.
280 */
281 u16 next_generation;
282
283 /// Head of the free slots linked list.
284 u16 next_free_slot;
285};
286
287extern HandleTable g_handle_table;
288 125
289/// Initialize the kernel with the specified system mode. 126/// Initialize the kernel with the specified system mode.
290void Init(u32 system_mode); 127void Init(u32 system_mode);