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.h190
1 files changed, 109 insertions, 81 deletions
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 27c406ad4..7f86fd07d 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -12,13 +12,17 @@
12typedef u32 Handle; 12typedef u32 Handle;
13typedef s32 Result; 13typedef s32 Result;
14 14
15const Handle INVALID_HANDLE = 0;
16
15namespace Kernel { 17namespace Kernel {
16 18
17// From kernel.h. Declarations duplicated here to avoid a circular header dependency. 19// TODO: Verify code
18class Thread; 20const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
19Thread* GetCurrentThread(); 21 ErrorSummary::OutOfResource, ErrorLevel::Temporary);
22// TOOD: Verify code
23const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel);
20 24
21enum KernelHandle { 25enum KernelHandle : Handle {
22 CurrentThread = 0xFFFF8000, 26 CurrentThread = 0xFFFF8000,
23 CurrentProcess = 0xFFFF8001, 27 CurrentProcess = 0xFFFF8001,
24}; 28};
@@ -61,103 +65,127 @@ public:
61 LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); 65 LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
62 return UnimplementedFunction(ErrorModule::Kernel); 66 return UnimplementedFunction(ErrorModule::Kernel);
63 } 67 }
64};
65 68
66class HandleTable : NonCopyable { 69private:
67public: 70 friend void intrusive_ptr_add_ref(Object*);
68 HandleTable(); 71 friend void intrusive_ptr_release(Object*);
69 ~HandleTable() {}
70 72
71 // Allocates a handle within the range and inserts the object into the map. 73 unsigned int ref_count = 0;
72 Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); 74};
73 75
74 static Object* CreateByIDType(int type); 76// Special functions that will later be used by boost::instrusive_ptr to do automatic ref-counting
77inline void intrusive_ptr_add_ref(Object* object) {
78 ++object->ref_count;
79}
75 80
76 template <class T> 81inline void intrusive_ptr_release(Object* object) {
77 void Destroy(Handle handle) { 82 if (--object->ref_count == 0) {
78 if (Get<T>(handle)) { 83 delete object;
79 occupied[handle - HANDLE_OFFSET] = false;
80 delete pool[handle - HANDLE_OFFSET];
81 }
82 } 84 }
85}
83 86
84 bool IsValid(Handle handle) const; 87/**
88 * This class allows the creation of Handles, which are references to objects that can be tested
89 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
90 * emulated process. it has been designed so that it follows the same handle format and has
91 * approximately the same restrictions as the handle manager in the CTR-OS.
92 *
93 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
94 * The slot index is used to index into the arrays in this class to access the data corresponding
95 * to the Handle.
96 *
97 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
98 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
99 * value of the counter is stored into the Handle as well as in the handle table (in the
100 * "generations" array). When looking up a handle, the Handle's generation must match with the
101 * value stored on the class, otherwise the Handle is considered invalid.
102 *
103 * To find free slots when allocating a Handle without needing to scan the entire object array, the
104 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
105 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
106 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
107 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
108 * verified and isn't likely to cause any problems.
109 */
110class HandleTable final : NonCopyable {
111public:
112 HandleTable();
85 113
86 template <class T> 114 /**
87 T* Get(Handle handle) { 115 * Allocates a handle for the given object.
88 if (handle == CurrentThread) { 116 * @return The created Handle or one of the following errors:
89 return reinterpret_cast<T*>(GetCurrentThread()); 117 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
90 } 118 */
119 ResultVal<Handle> Create(Object* obj);
91 120
92 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 121 /**
93 if (handle != 0) { 122 * Returns a new handle that points to the same object as the passed in handle.
94 LOG_ERROR(Kernel, "Bad object handle %08x", handle); 123 * @return The duplicated Handle or one of the following errors:
95 } 124 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
96 return nullptr; 125 * - Any errors returned by `Create()`.
97 } else { 126 */
98 Object* t = pool[handle - HANDLE_OFFSET]; 127 ResultVal<Handle> Duplicate(Handle handle);
99 if (t->GetHandleType() != T::HANDLE_TYPE) {
100 LOG_ERROR(Kernel, "Wrong object type for %08x", handle);
101 return nullptr;
102 }
103 return static_cast<T*>(t);
104 }
105 }
106 128
107 // ONLY use this when you know the handle is valid. 129 /**
108 template <class T> 130 * Closes a handle, removing it from the table and decreasing the object's ref-count.
109 T *GetFast(Handle handle) { 131 * @return `RESULT_SUCCESS` or one of the following errors:
110 if (handle == CurrentThread) { 132 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
111 return reinterpret_cast<T*>(GetCurrentThread()); 133 */
112 } 134 ResultCode Close(Handle handle);
113 135
114 const Handle realHandle = handle - HANDLE_OFFSET; 136 /// Checks if a handle is valid and points to an existing object.
115 _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); 137 bool IsValid(Handle handle) const;
116 return static_cast<T*>(pool[realHandle]);
117 }
118 138
119 template <class T, typename ArgT> 139 /**
120 void Iterate(bool func(T*, ArgT), ArgT arg) { 140 * Looks up a handle.
121 int type = T::GetStaticIDType(); 141 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid.
122 for (int i = 0; i < MAX_COUNT; i++) 142 */
123 { 143 Object* GetGeneric(Handle handle) const;
124 if (!occupied[i])
125 continue;
126 T* t = static_cast<T*>(pool[i]);
127 if (t->GetIDType() == type) {
128 if (!func(t, arg))
129 break;
130 }
131 }
132 }
133 144
134 bool GetIDType(Handle handle, HandleType* type) const { 145 /**
135 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || 146 * Looks up a handle while verifying its type.
136 !occupied[handle - HANDLE_OFFSET]) { 147 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
137 LOG_ERROR(Kernel, "Bad object handle %08X", handle); 148 * type differs from the handle type `T::HANDLE_TYPE`.
138 return false; 149 */
150 template <class T>
151 T* Get(Handle handle) const {
152 Object* object = GetGeneric(handle);
153 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
154 return static_cast<T*>(object);
139 } 155 }
140 Object* t = pool[handle - HANDLE_OFFSET]; 156 return nullptr;
141 *type = t->GetHandleType();
142 return true;
143 } 157 }
144 158
145 Object* &operator [](Handle handle); 159 /// Closes all handles held in this table.
146 void List();
147 void Clear(); 160 void Clear();
148 int GetCount() const;
149 161
150private: 162private:
163 /**
164 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
165 * reduced by ExHeader values, but this is not emulated here.
166 */
167 static const size_t MAX_COUNT = 4096;
168
169 static size_t GetSlot(Handle handle) { return handle >> 15; }
170 static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
171
172 /// Stores the Object referenced by the handle or null if the slot is empty.
173 std::array<Object*, MAX_COUNT> objects;
151 174
152 enum { 175 /**
153 MAX_COUNT = 0x1000, 176 * The value of `next_generation` when the handle was created, used to check for validity. For
154 HANDLE_OFFSET = 0x100, 177 * empty slots, contains the index of the next free slot in the list.
155 INITIAL_NEXT_ID = 0x10, 178 */
156 }; 179 std::array<u16, MAX_COUNT> generations;
180
181 /**
182 * Global counter of the number of created handles. Stored in `generations` when a handle is
183 * created, and wraps around to 1 when it hits 0x8000.
184 */
185 u16 next_generation;
157 186
158 std::array<Object*, MAX_COUNT> pool; 187 /// Head of the free slots linked list.
159 std::array<bool, MAX_COUNT> occupied; 188 u16 next_free_slot;
160 int next_id;
161}; 189};
162 190
163extern HandleTable g_handle_table; 191extern HandleTable g_handle_table;