core: hle: kernel: k_handle_table: Refresh.

This commit is contained in:
bunnei 2022-10-29 14:26:39 -07:00
parent 1f21fa866d
commit 6636b81573
2 changed files with 87 additions and 54 deletions

View File

@ -5,14 +5,11 @@
namespace Kernel { namespace Kernel {
KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
KHandleTable::~KHandleTable() = default;
Result KHandleTable::Finalize() { Result KHandleTable::Finalize() {
// Get the table and clear our record of it. // Get the table and clear our record of it.
u16 saved_table_size = 0; u16 saved_table_size = 0;
{ {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
std::swap(m_table_size, saved_table_size); std::swap(m_table_size, saved_table_size);
@ -25,28 +22,28 @@ Result KHandleTable::Finalize() {
} }
} }
return ResultSuccess; R_SUCCEED();
} }
bool KHandleTable::Remove(Handle handle) { bool KHandleTable::Remove(Handle handle) {
// Don't allow removal of a pseudo-handle. // Don't allow removal of a pseudo-handle.
if (Svc::IsPseudoHandle(handle)) { if (Svc::IsPseudoHandle(handle)) [[unlikely]] {
return false; return false;
} }
// Handles must not have reserved bits set. // Handles must not have reserved bits set.
const auto handle_pack = HandlePack(handle); const auto handle_pack = HandlePack(handle);
if (handle_pack.reserved != 0) { if (handle_pack.reserved != 0) [[unlikely]] {
return false; return false;
} }
// Find the object and free the entry. // Find the object and free the entry.
KAutoObject* obj = nullptr; KAutoObject* obj = nullptr;
{ {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
if (this->IsValidHandle(handle)) { if (this->IsValidHandle(handle)) [[likely]] {
const auto index = handle_pack.index; const auto index = handle_pack.index;
obj = m_objects[index]; obj = m_objects[index];
@ -57,13 +54,13 @@ bool KHandleTable::Remove(Handle handle) {
} }
// Close the object. // Close the object.
kernel.UnregisterInUseObject(obj); m_kernel.UnregisterInUseObject(obj);
obj->Close(); obj->Close();
return true; return true;
} }
Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) { Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
// Never exceed our capacity. // Never exceed our capacity.
@ -82,22 +79,22 @@ Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
*out_handle = EncodeHandle(static_cast<u16>(index), linear_id); *out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
} }
return ResultSuccess; R_SUCCEED();
} }
Result KHandleTable::Reserve(Handle* out_handle) { Result KHandleTable::Reserve(Handle* out_handle) {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
// Never exceed our capacity. // Never exceed our capacity.
R_UNLESS(m_count < m_table_size, ResultOutOfHandles); R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
*out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId()); *out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
return ResultSuccess; R_SUCCEED();
} }
void KHandleTable::Unreserve(Handle handle) { void KHandleTable::Unreserve(Handle handle) {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
// Unpack the handle. // Unpack the handle.
@ -108,7 +105,7 @@ void KHandleTable::Unreserve(Handle handle) {
ASSERT(reserved == 0); ASSERT(reserved == 0);
ASSERT(linear_id != 0); ASSERT(linear_id != 0);
if (index < m_table_size) { if (index < m_table_size) [[likely]] {
// NOTE: This code does not check the linear id. // NOTE: This code does not check the linear id.
ASSERT(m_objects[index] == nullptr); ASSERT(m_objects[index] == nullptr);
this->FreeEntry(index); this->FreeEntry(index);
@ -116,7 +113,7 @@ void KHandleTable::Unreserve(Handle handle) {
} }
void KHandleTable::Register(Handle handle, KAutoObject* obj) { void KHandleTable::Register(Handle handle, KAutoObject* obj) {
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
// Unpack the handle. // Unpack the handle.
@ -127,7 +124,7 @@ void KHandleTable::Register(Handle handle, KAutoObject* obj) {
ASSERT(reserved == 0); ASSERT(reserved == 0);
ASSERT(linear_id != 0); ASSERT(linear_id != 0);
if (index < m_table_size) { if (index < m_table_size) [[likely]] {
// Set the entry. // Set the entry.
ASSERT(m_objects[index] == nullptr); ASSERT(m_objects[index] == nullptr);

View File

@ -21,33 +21,38 @@ namespace Kernel {
class KernelCore; class KernelCore;
class KHandleTable { class KHandleTable {
public:
YUZU_NON_COPYABLE(KHandleTable); YUZU_NON_COPYABLE(KHandleTable);
YUZU_NON_MOVEABLE(KHandleTable); YUZU_NON_MOVEABLE(KHandleTable);
public:
static constexpr size_t MaxTableSize = 1024; static constexpr size_t MaxTableSize = 1024;
explicit KHandleTable(KernelCore& kernel_); public:
~KHandleTable(); explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
Result Initialize(s32 size) { Result Initialize(s32 size) {
// Check that the table size is valid.
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
// Lock.
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
// Initialize all fields. // Initialize all fields.
m_max_count = 0; m_max_count = 0;
m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size); m_table_size = static_cast<s16>((size <= 0) ? MaxTableSize : size);
m_next_linear_id = MinLinearId; m_next_linear_id = MinLinearId;
m_count = 0; m_count = 0;
m_free_head_index = -1; m_free_head_index = -1;
// Free all entries. // Free all entries.
for (s16 i = 0; i < static_cast<s16>(m_table_size); ++i) { for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
m_objects[i] = nullptr; m_objects[i] = nullptr;
m_entry_infos[i].next_free_index = i - 1; m_entry_infos[i].next_free_index = static_cast<s16>(i - 1);
m_free_head_index = i; m_free_head_index = i;
} }
return ResultSuccess; R_SUCCEED();
} }
size_t GetTableSize() const { size_t GetTableSize() const {
@ -66,13 +71,13 @@ public:
template <typename T = KAutoObject> template <typename T = KAutoObject>
KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const { KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
// Lock and look up in table. // Lock and look up in table.
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
if constexpr (std::is_same_v<T, KAutoObject>) { if constexpr (std::is_same<T, KAutoObject>::value) {
return this->GetObjectImpl(handle); return this->GetObjectImpl(handle);
} else { } else {
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) { if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) [[likely]] {
return obj->DynamicCast<T*>(); return obj->DynamicCast<T*>();
} else { } else {
return nullptr; return nullptr;
@ -85,13 +90,13 @@ public:
// Handle pseudo-handles. // Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) { if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) { if (handle == Svc::PseudoHandle::CurrentProcess) {
auto* const cur_process = kernel.CurrentProcess(); auto* const cur_process = m_kernel.CurrentProcess();
ASSERT(cur_process != nullptr); ASSERT(cur_process != nullptr);
return cur_process; return cur_process;
} }
} else if constexpr (std::derived_from<KThread, T>) { } else if constexpr (std::derived_from<KThread, T>) {
if (handle == Svc::PseudoHandle::CurrentThread) { if (handle == Svc::PseudoHandle::CurrentThread) {
auto* const cur_thread = GetCurrentThreadPointer(kernel); auto* const cur_thread = GetCurrentThreadPointer(m_kernel);
ASSERT(cur_thread != nullptr); ASSERT(cur_thread != nullptr);
return cur_thread; return cur_thread;
} }
@ -100,6 +105,37 @@ public:
return this->template GetObjectWithoutPseudoHandle<T>(handle); return this->template GetObjectWithoutPseudoHandle<T>(handle);
} }
KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(Handle handle) const {
// Lock and look up in table.
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
return this->GetObjectImpl(handle);
}
KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const {
// Handle pseudo-handles.
ASSERT(cur_thread != nullptr);
if (handle == Svc::PseudoHandle::CurrentProcess) {
auto* const cur_process =
static_cast<KAutoObject*>(static_cast<void*>(cur_thread->GetOwnerProcess()));
ASSERT(cur_process != nullptr);
return cur_process;
}
if (handle == Svc::PseudoHandle::CurrentThread) {
return static_cast<KAutoObject*>(cur_thread);
}
return GetObjectForIpcWithoutPseudoHandle(handle);
}
KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const {
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
return this->GetObjectByIndexImpl(out_handle, index);
}
Result Reserve(Handle* out_handle); Result Reserve(Handle* out_handle);
void Unreserve(Handle handle); void Unreserve(Handle handle);
@ -112,7 +148,7 @@ public:
size_t num_opened; size_t num_opened;
{ {
// Lock the table. // Lock the table.
KScopedDisableDispatch dd(kernel); KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock); KScopedSpinLock lk(m_lock);
for (num_opened = 0; num_opened < num_handles; num_opened++) { for (num_opened = 0; num_opened < num_handles; num_opened++) {
// Get the current handle. // Get the current handle.
@ -120,13 +156,13 @@ public:
// Get the object for the current handle. // Get the object for the current handle.
KAutoObject* cur_object = this->GetObjectImpl(cur_handle); KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
if (cur_object == nullptr) { if (cur_object == nullptr) [[unlikely]] {
break; break;
} }
// Cast the current object to the desired type. // Cast the current object to the desired type.
T* cur_t = cur_object->DynamicCast<T*>(); T* cur_t = cur_object->DynamicCast<T*>();
if (cur_t == nullptr) { if (cur_t == nullptr) [[unlikely]] {
break; break;
} }
@ -137,7 +173,7 @@ public:
} }
// If we converted every object, succeed. // If we converted every object, succeed.
if (num_opened == num_handles) { if (num_opened == num_handles) [[likely]] {
return true; return true;
} }
@ -191,21 +227,21 @@ private:
ASSERT(reserved == 0); ASSERT(reserved == 0);
// Validate our indexing information. // Validate our indexing information.
if (raw_value == 0) { if (raw_value == 0) [[unlikely]] {
return false; return false;
} }
if (linear_id == 0) { if (linear_id == 0) [[unlikely]] {
return false; return false;
} }
if (index >= m_table_size) { if (index >= m_table_size) [[unlikely]] {
return false; return false;
} }
// Check that there's an object, and our serial id is correct. // Check that there's an object, and our serial id is correct.
if (m_objects[index] == nullptr) { if (m_objects[index] == nullptr) [[unlikely]] {
return false; return false;
} }
if (m_entry_infos[index].GetLinearId() != linear_id) { if (m_entry_infos[index].GetLinearId() != linear_id) [[unlikely]] {
return false; return false;
} }
@ -215,11 +251,11 @@ private:
KAutoObject* GetObjectImpl(Handle handle) const { KAutoObject* GetObjectImpl(Handle handle) const {
// Handles must not have reserved bits set. // Handles must not have reserved bits set.
const auto handle_pack = HandlePack(handle); const auto handle_pack = HandlePack(handle);
if (handle_pack.reserved != 0) { if (handle_pack.reserved != 0) [[unlikely]] {
return nullptr; return nullptr;
} }
if (this->IsValidHandle(handle)) { if (this->IsValidHandle(handle)) [[likely]] {
return m_objects[handle_pack.index]; return m_objects[handle_pack.index];
} else { } else {
return nullptr; return nullptr;
@ -227,9 +263,8 @@ private:
} }
KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const { KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
// Index must be in bounds. // Index must be in bounds.
if (index >= m_table_size) { if (index >= m_table_size) [[unlikely]] {
return nullptr; return nullptr;
} }
@ -244,18 +279,15 @@ private:
private: private:
union HandlePack { union HandlePack {
HandlePack() = default; constexpr HandlePack() = default;
HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {} constexpr HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
u32 raw; u32 raw{};
BitField<0, 15, u32> index; BitField<0, 15, u32> index;
BitField<15, 15, u32> linear_id; BitField<15, 15, u32> linear_id;
BitField<30, 2, u32> reserved; BitField<30, 2, u32> reserved;
}; };
static constexpr u16 MinLinearId = 1;
static constexpr u16 MaxLinearId = 0x7FFF;
static constexpr Handle EncodeHandle(u16 index, u16 linear_id) { static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
HandlePack handle{}; HandlePack handle{};
handle.index.Assign(index); handle.index.Assign(index);
@ -264,6 +296,10 @@ private:
return handle.raw; return handle.raw;
} }
private:
static constexpr u16 MinLinearId = 1;
static constexpr u16 MaxLinearId = 0x7FFF;
union EntryInfo { union EntryInfo {
u16 linear_id; u16 linear_id;
s16 next_free_index; s16 next_free_index;
@ -271,21 +307,21 @@ private:
constexpr u16 GetLinearId() const { constexpr u16 GetLinearId() const {
return linear_id; return linear_id;
} }
constexpr s16 GetNextFreeIndex() const { constexpr s32 GetNextFreeIndex() const {
return next_free_index; return next_free_index;
} }
}; };
private: private:
KernelCore& m_kernel;
std::array<EntryInfo, MaxTableSize> m_entry_infos{}; std::array<EntryInfo, MaxTableSize> m_entry_infos{};
std::array<KAutoObject*, MaxTableSize> m_objects{}; std::array<KAutoObject*, MaxTableSize> m_objects{};
s32 m_free_head_index{-1}; mutable KSpinLock m_lock;
s32 m_free_head_index{};
u16 m_table_size{}; u16 m_table_size{};
u16 m_max_count{}; u16 m_max_count{};
u16 m_next_linear_id{MinLinearId}; u16 m_next_linear_id{};
u16 m_count{}; u16 m_count{};
mutable KSpinLock m_lock;
KernelCore& kernel;
}; };
} // namespace Kernel } // namespace Kernel