diff options
Diffstat (limited to 'src/core/hle/kernel/kernel.h')
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 181 |
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 | ||
| 16 | namespace Kernel { | 13 | namespace Kernel { |
| 17 | 14 | ||
| 18 | using Handle = u32; | 15 | using Handle = u32; |
| 19 | 16 | ||
| 20 | class Thread; | ||
| 21 | |||
| 22 | enum KernelHandle : Handle { | ||
| 23 | CurrentThread = 0xFFFF8000, | ||
| 24 | CurrentProcess = 0xFFFF8001, | ||
| 25 | }; | ||
| 26 | |||
| 27 | enum class HandleType : u32 { | 17 | enum class HandleType : u32 { |
| 28 | Unknown, | 18 | Unknown, |
| 29 | Event, | 19 | Event, |
| @@ -121,170 +111,17 @@ inline void intrusive_ptr_release(Object* object) { | |||
| 121 | template <typename T> | 111 | template <typename T> |
| 122 | using SharedPtr = boost::intrusive_ptr<T>; | 112 | using SharedPtr = boost::intrusive_ptr<T>; |
| 123 | 113 | ||
| 124 | /// Class that represents a Kernel object that a thread can be waiting on | ||
| 125 | class WaitObject : public Object { | ||
| 126 | public: | ||
| 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 | |||
| 161 | private: | ||
| 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 | */ |
| 189 | class HandleTable final : NonCopyable { | 118 | template <typename T> |
| 190 | public: | 119 | inline 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 | |||
| 254 | private: | ||
| 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 | |||
| 287 | extern HandleTable g_handle_table; | ||
| 288 | 125 | ||
| 289 | /// Initialize the kernel with the specified system mode. | 126 | /// Initialize the kernel with the specified system mode. |
| 290 | void Init(u32 system_mode); | 127 | void Init(u32 system_mode); |