diff options
Diffstat (limited to 'src/core/hle/kernel/handle_table.cpp')
-rw-r--r-- | src/core/hle/kernel/handle_table.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp new file mode 100644 index 000000000..c7322d883 --- /dev/null +++ b/src/core/hle/kernel/handle_table.cpp @@ -0,0 +1,97 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <utility> +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/thread.h" + +namespace Kernel { + +HandleTable g_handle_table; + +HandleTable::HandleTable() { + next_generation = 1; + Clear(); +} + +ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { + DEBUG_ASSERT(obj != nullptr); + + u16 slot = next_free_slot; + if (slot >= generations.size()) { + LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); + return ERR_OUT_OF_HANDLES; + } + next_free_slot = generations[slot]; + + u16 generation = next_generation++; + + // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. + // CTR-OS doesn't use generation 0, so skip straight to 1. + if (next_generation >= (1 << 15)) + next_generation = 1; + + generations[slot] = generation; + objects[slot] = std::move(obj); + + Handle handle = generation | (slot << 15); + return MakeResult<Handle>(handle); +} + +ResultVal<Handle> HandleTable::Duplicate(Handle handle) { + SharedPtr<Object> object = GetGeneric(handle); + if (object == nullptr) { + LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); + return ERR_INVALID_HANDLE; + } + return Create(std::move(object)); +} + +ResultCode HandleTable::Close(Handle handle) { + if (!IsValid(handle)) + return ERR_INVALID_HANDLE; + + u16 slot = GetSlot(handle); + + objects[slot] = nullptr; + + generations[slot] = next_free_slot; + next_free_slot = slot; + return RESULT_SUCCESS; +} + +bool HandleTable::IsValid(Handle handle) const { + size_t slot = GetSlot(handle); + u16 generation = GetGeneration(handle); + + return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; +} + +SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { + if (handle == CurrentThread) { + return GetCurrentThread(); + } else if (handle == CurrentProcess) { + return g_current_process; + } + + if (!IsValid(handle)) { + return nullptr; + } + return objects[GetSlot(handle)]; +} + +void HandleTable::Clear() { + for (u16 i = 0; i < MAX_COUNT; ++i) { + generations[i] = i + 1; + objects[i] = nullptr; + } + next_free_slot = 0; +} + +} // namespace |