k_handle_table.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <array>
  5. #include "common/assert.h"
  6. #include "common/bit_field.h"
  7. #include "common/common_types.h"
  8. #include "core/hle/kernel/k_auto_object.h"
  9. #include "core/hle/kernel/k_spin_lock.h"
  10. #include "core/hle/kernel/k_thread.h"
  11. #include "core/hle/kernel/kernel.h"
  12. #include "core/hle/kernel/svc_common.h"
  13. #include "core/hle/kernel/svc_results.h"
  14. #include "core/hle/result.h"
  15. namespace Kernel {
  16. class KernelCore;
  17. class KHandleTable {
  18. YUZU_NON_COPYABLE(KHandleTable);
  19. YUZU_NON_MOVEABLE(KHandleTable);
  20. public:
  21. static constexpr size_t MaxTableSize = 1024;
  22. public:
  23. explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
  24. Result Initialize(s32 size) {
  25. // Check that the table size is valid.
  26. R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
  27. // Lock.
  28. KScopedDisableDispatch dd{m_kernel};
  29. KScopedSpinLock lk(m_lock);
  30. // Initialize all fields.
  31. m_max_count = 0;
  32. m_table_size = static_cast<s16>((size <= 0) ? MaxTableSize : size);
  33. m_next_linear_id = MinLinearId;
  34. m_count = 0;
  35. m_free_head_index = -1;
  36. // Free all entries.
  37. for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
  38. m_objects[i] = nullptr;
  39. m_entry_infos[i].next_free_index = static_cast<s16>(i - 1);
  40. m_free_head_index = i;
  41. }
  42. R_SUCCEED();
  43. }
  44. size_t GetTableSize() const {
  45. return m_table_size;
  46. }
  47. size_t GetCount() const {
  48. return m_count;
  49. }
  50. size_t GetMaxCount() const {
  51. return m_max_count;
  52. }
  53. Result Finalize();
  54. bool Remove(Handle handle);
  55. template <typename T = KAutoObject>
  56. KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
  57. // Lock and look up in table.
  58. KScopedDisableDispatch dd{m_kernel};
  59. KScopedSpinLock lk(m_lock);
  60. if constexpr (std::is_same<T, KAutoObject>::value) {
  61. return this->GetObjectImpl(handle);
  62. } else {
  63. if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) [[likely]] {
  64. return obj->DynamicCast<T*>();
  65. } else {
  66. return nullptr;
  67. }
  68. }
  69. }
  70. template <typename T = KAutoObject>
  71. KScopedAutoObject<T> GetObject(Handle handle) const {
  72. // Handle pseudo-handles.
  73. if constexpr (std::derived_from<KProcess, T>) {
  74. if (handle == Svc::PseudoHandle::CurrentProcess) {
  75. auto* const cur_process = m_kernel.CurrentProcess();
  76. ASSERT(cur_process != nullptr);
  77. return cur_process;
  78. }
  79. } else if constexpr (std::derived_from<KThread, T>) {
  80. if (handle == Svc::PseudoHandle::CurrentThread) {
  81. auto* const cur_thread = GetCurrentThreadPointer(m_kernel);
  82. ASSERT(cur_thread != nullptr);
  83. return cur_thread;
  84. }
  85. }
  86. return this->template GetObjectWithoutPseudoHandle<T>(handle);
  87. }
  88. KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(Handle handle) const {
  89. // Lock and look up in table.
  90. KScopedDisableDispatch dd{m_kernel};
  91. KScopedSpinLock lk(m_lock);
  92. return this->GetObjectImpl(handle);
  93. }
  94. KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const {
  95. // Handle pseudo-handles.
  96. ASSERT(cur_thread != nullptr);
  97. if (handle == Svc::PseudoHandle::CurrentProcess) {
  98. auto* const cur_process =
  99. static_cast<KAutoObject*>(static_cast<void*>(cur_thread->GetOwnerProcess()));
  100. ASSERT(cur_process != nullptr);
  101. return cur_process;
  102. }
  103. if (handle == Svc::PseudoHandle::CurrentThread) {
  104. return static_cast<KAutoObject*>(cur_thread);
  105. }
  106. return GetObjectForIpcWithoutPseudoHandle(handle);
  107. }
  108. KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const {
  109. KScopedDisableDispatch dd{m_kernel};
  110. KScopedSpinLock lk(m_lock);
  111. return this->GetObjectByIndexImpl(out_handle, index);
  112. }
  113. Result Reserve(Handle* out_handle);
  114. void Unreserve(Handle handle);
  115. Result Add(Handle* out_handle, KAutoObject* obj);
  116. void Register(Handle handle, KAutoObject* obj);
  117. template <typename T>
  118. bool GetMultipleObjects(T** out, const Handle* handles, size_t num_handles) const {
  119. // Try to convert and open all the handles.
  120. size_t num_opened;
  121. {
  122. // Lock the table.
  123. KScopedDisableDispatch dd{m_kernel};
  124. KScopedSpinLock lk(m_lock);
  125. for (num_opened = 0; num_opened < num_handles; num_opened++) {
  126. // Get the current handle.
  127. const auto cur_handle = handles[num_opened];
  128. // Get the object for the current handle.
  129. KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
  130. if (cur_object == nullptr) [[unlikely]] {
  131. break;
  132. }
  133. // Cast the current object to the desired type.
  134. T* cur_t = cur_object->DynamicCast<T*>();
  135. if (cur_t == nullptr) [[unlikely]] {
  136. break;
  137. }
  138. // Open a reference to the current object.
  139. cur_t->Open();
  140. out[num_opened] = cur_t;
  141. }
  142. }
  143. // If we converted every object, succeed.
  144. if (num_opened == num_handles) [[likely]] {
  145. return true;
  146. }
  147. // If we didn't convert entry object, close the ones we opened.
  148. for (size_t i = 0; i < num_opened; i++) {
  149. out[i]->Close();
  150. }
  151. return false;
  152. }
  153. private:
  154. s32 AllocateEntry() {
  155. ASSERT(m_count < m_table_size);
  156. const auto index = m_free_head_index;
  157. m_free_head_index = m_entry_infos[index].GetNextFreeIndex();
  158. m_max_count = std::max(m_max_count, ++m_count);
  159. return index;
  160. }
  161. void FreeEntry(s32 index) {
  162. ASSERT(m_count > 0);
  163. m_objects[index] = nullptr;
  164. m_entry_infos[index].next_free_index = static_cast<s16>(m_free_head_index);
  165. m_free_head_index = index;
  166. --m_count;
  167. }
  168. u16 AllocateLinearId() {
  169. const u16 id = m_next_linear_id++;
  170. if (m_next_linear_id > MaxLinearId) {
  171. m_next_linear_id = MinLinearId;
  172. }
  173. return id;
  174. }
  175. bool IsValidHandle(Handle handle) const {
  176. // Unpack the handle.
  177. const auto handle_pack = HandlePack(handle);
  178. const auto raw_value = handle_pack.raw;
  179. const auto index = handle_pack.index;
  180. const auto linear_id = handle_pack.linear_id;
  181. const auto reserved = handle_pack.reserved;
  182. ASSERT(reserved == 0);
  183. // Validate our indexing information.
  184. if (raw_value == 0) [[unlikely]] {
  185. return false;
  186. }
  187. if (linear_id == 0) [[unlikely]] {
  188. return false;
  189. }
  190. if (index >= m_table_size) [[unlikely]] {
  191. return false;
  192. }
  193. // Check that there's an object, and our serial id is correct.
  194. if (m_objects[index] == nullptr) [[unlikely]] {
  195. return false;
  196. }
  197. if (m_entry_infos[index].GetLinearId() != linear_id) [[unlikely]] {
  198. return false;
  199. }
  200. return true;
  201. }
  202. KAutoObject* GetObjectImpl(Handle handle) const {
  203. // Handles must not have reserved bits set.
  204. const auto handle_pack = HandlePack(handle);
  205. if (handle_pack.reserved != 0) [[unlikely]] {
  206. return nullptr;
  207. }
  208. if (this->IsValidHandle(handle)) [[likely]] {
  209. return m_objects[handle_pack.index];
  210. } else {
  211. return nullptr;
  212. }
  213. }
  214. KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
  215. // Index must be in bounds.
  216. if (index >= m_table_size) [[unlikely]] {
  217. return nullptr;
  218. }
  219. // Ensure entry has an object.
  220. if (KAutoObject* obj = m_objects[index]; obj != nullptr) {
  221. *out_handle = EncodeHandle(static_cast<u16>(index), m_entry_infos[index].GetLinearId());
  222. return obj;
  223. } else {
  224. return nullptr;
  225. }
  226. }
  227. private:
  228. union HandlePack {
  229. constexpr HandlePack() = default;
  230. constexpr HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
  231. u32 raw{};
  232. BitField<0, 15, u32> index;
  233. BitField<15, 15, u32> linear_id;
  234. BitField<30, 2, u32> reserved;
  235. };
  236. static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
  237. HandlePack handle{};
  238. handle.index.Assign(index);
  239. handle.linear_id.Assign(linear_id);
  240. handle.reserved.Assign(0);
  241. return handle.raw;
  242. }
  243. private:
  244. static constexpr u16 MinLinearId = 1;
  245. static constexpr u16 MaxLinearId = 0x7FFF;
  246. union EntryInfo {
  247. u16 linear_id;
  248. s16 next_free_index;
  249. constexpr u16 GetLinearId() const {
  250. return linear_id;
  251. }
  252. constexpr s32 GetNextFreeIndex() const {
  253. return next_free_index;
  254. }
  255. };
  256. private:
  257. KernelCore& m_kernel;
  258. std::array<EntryInfo, MaxTableSize> m_entry_infos{};
  259. std::array<KAutoObject*, MaxTableSize> m_objects{};
  260. mutable KSpinLock m_lock;
  261. s32 m_free_head_index{};
  262. u16 m_table_size{};
  263. u16 m_max_count{};
  264. u16 m_next_linear_id{};
  265. u16 m_count{};
  266. };
  267. } // namespace Kernel