handle_table.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <cstddef>
  7. #include <memory>
  8. #include "common/common_types.h"
  9. #include "core/hle/kernel/object.h"
  10. #include "core/hle/result.h"
  11. namespace Kernel {
  12. class KernelCore;
  13. enum KernelHandle : Handle {
  14. InvalidHandle = 0,
  15. CurrentThread = 0xFFFF8000,
  16. CurrentProcess = 0xFFFF8001,
  17. };
  18. /**
  19. * This class allows the creation of Handles, which are references to objects that can be tested
  20. * for validity and looked up. Here they are used to pass references to kernel objects to/from the
  21. * emulated process. it has been designed so that it follows the same handle format and has
  22. * approximately the same restrictions as the handle manager in the CTR-OS.
  23. *
  24. * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
  25. * The slot index is used to index into the arrays in this class to access the data corresponding
  26. * to the Handle.
  27. *
  28. * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
  29. * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
  30. * value of the counter is stored into the Handle as well as in the handle table (in the
  31. * "generations" array). When looking up a handle, the Handle's generation must match with the
  32. * value stored on the class, otherwise the Handle is considered invalid.
  33. *
  34. * To find free slots when allocating a Handle without needing to scan the entire object array, the
  35. * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
  36. * When a Handle is created, an index is popped off the list and used for the new Handle. When it
  37. * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
  38. * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
  39. * verified and isn't likely to cause any problems.
  40. */
  41. class HandleTable final : NonCopyable {
  42. public:
  43. /// This is the maximum limit of handles allowed per process in Horizon
  44. static constexpr std::size_t MAX_COUNT = 1024;
  45. explicit HandleTable(KernelCore& kernel);
  46. ~HandleTable();
  47. /**
  48. * Sets the number of handles that may be in use at one time
  49. * for this handle table.
  50. *
  51. * @param handle_table_size The desired size to limit the handle table to.
  52. *
  53. * @returns an error code indicating if initialization was successful.
  54. * If initialization was not successful, then ERR_OUT_OF_MEMORY
  55. * will be returned.
  56. *
  57. * @pre handle_table_size must be within the range [0, 1024]
  58. */
  59. ResultCode SetSize(s32 handle_table_size);
  60. /**
  61. * Allocates a handle for the given object.
  62. * @return The created Handle or one of the following errors:
  63. * - `ERR_HANDLE_TABLE_FULL`: the maximum number of handles has been exceeded.
  64. */
  65. ResultVal<Handle> Create(std::shared_ptr<Object> obj);
  66. /**
  67. * Returns a new handle that points to the same object as the passed in handle.
  68. * @return The duplicated Handle or one of the following errors:
  69. * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
  70. * - Any errors returned by `Create()`.
  71. */
  72. ResultVal<Handle> Duplicate(Handle handle);
  73. /**
  74. * Closes a handle, removing it from the table and decreasing the object's ref-count.
  75. * @return `RESULT_SUCCESS` or one of the following errors:
  76. * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
  77. */
  78. ResultCode Close(Handle handle);
  79. /// Checks if a handle is valid and points to an existing object.
  80. bool IsValid(Handle handle) const;
  81. /**
  82. * Looks up a handle.
  83. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid.
  84. */
  85. std::shared_ptr<Object> GetGeneric(Handle handle) const;
  86. /**
  87. * Looks up a handle while verifying its type.
  88. * @return Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
  89. * type differs from the requested one.
  90. */
  91. template <class T>
  92. std::shared_ptr<T> Get(Handle handle) const {
  93. return DynamicObjectCast<T>(GetGeneric(handle));
  94. }
  95. /// Closes all handles held in this table.
  96. void Clear();
  97. private:
  98. /// Stores the Object referenced by the handle or null if the slot is empty.
  99. std::array<std::shared_ptr<Object>, MAX_COUNT> objects;
  100. /**
  101. * The value of `next_generation` when the handle was created, used to check for validity. For
  102. * empty slots, contains the index of the next free slot in the list.
  103. */
  104. std::array<u16, MAX_COUNT> generations;
  105. /**
  106. * The limited size of the handle table. This can be specified by process
  107. * capabilities in order to restrict the overall number of handles that
  108. * can be created in a process instance
  109. */
  110. u16 table_size = static_cast<u16>(MAX_COUNT);
  111. /**
  112. * Global counter of the number of created handles. Stored in `generations` when a handle is
  113. * created, and wraps around to 1 when it hits 0x8000.
  114. */
  115. u16 next_generation = 1;
  116. /// Head of the free slots linked list.
  117. u16 next_free_slot = 0;
  118. /// Underlying kernel instance that this handle table operates under.
  119. KernelCore& kernel;
  120. };
  121. } // namespace Kernel