core: hle: kernel: k_handle_table: Refresh.
This commit is contained in:
parent
1f21fa866d
commit
6636b81573
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue