2017-05-29 23:45:42 +00:00
|
|
|
// 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"
|
2018-03-13 21:49:59 +00:00
|
|
|
#include "core/core.h"
|
2017-05-29 23:45:42 +00:00
|
|
|
#include "core/hle/kernel/handle_table.h"
|
2020-12-03 02:08:35 +00:00
|
|
|
#include "core/hle/kernel/k_scheduler.h"
|
2020-12-31 07:01:08 +00:00
|
|
|
#include "core/hle/kernel/k_thread.h"
|
2020-07-15 17:18:03 +00:00
|
|
|
#include "core/hle/kernel/kernel.h"
|
2017-05-29 23:45:42 +00:00
|
|
|
#include "core/hle/kernel/process.h"
|
2021-02-12 23:43:01 +00:00
|
|
|
#include "core/hle/kernel/svc_results.h"
|
2017-05-29 23:45:42 +00:00
|
|
|
|
|
|
|
namespace Kernel {
|
2018-11-21 23:30:58 +00:00
|
|
|
namespace {
|
|
|
|
constexpr u16 GetSlot(Handle handle) {
|
2019-02-25 14:53:18 +00:00
|
|
|
return static_cast<u16>(handle >> 15);
|
2018-11-21 23:30:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
constexpr u16 GetGeneration(Handle handle) {
|
2019-02-25 14:53:18 +00:00
|
|
|
return static_cast<u16>(handle & 0x7FFF);
|
2018-11-21 23:30:58 +00:00
|
|
|
}
|
|
|
|
} // Anonymous namespace
|
2017-05-29 23:45:42 +00:00
|
|
|
|
2020-07-15 17:18:03 +00:00
|
|
|
HandleTable::HandleTable(KernelCore& kernel) : kernel{kernel} {
|
2017-05-29 23:45:42 +00:00
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
2018-11-21 23:22:24 +00:00
|
|
|
HandleTable::~HandleTable() = default;
|
|
|
|
|
2019-02-25 15:13:52 +00:00
|
|
|
ResultCode HandleTable::SetSize(s32 handle_table_size) {
|
|
|
|
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
|
2020-04-29 04:53:53 +00:00
|
|
|
LOG_ERROR(Kernel, "Handle table size {} is greater than {}", handle_table_size, MAX_COUNT);
|
2021-02-12 23:43:01 +00:00
|
|
|
return ResultOutOfMemory;
|
2019-02-25 15:13:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Values less than or equal to zero indicate to use the maximum allowable
|
|
|
|
// size for the handle table in the actual kernel, so we ignore the given
|
|
|
|
// value in that case, since we assume this by default unless this function
|
|
|
|
// is called.
|
|
|
|
if (handle_table_size > 0) {
|
|
|
|
table_size = static_cast<u16>(handle_table_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
return RESULT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-04-04 02:11:46 +00:00
|
|
|
ResultCode HandleTable::Add(Handle* out_handle, KAutoObject* obj, u16 type) {
|
|
|
|
ASSERT(obj != nullptr);
|
|
|
|
|
|
|
|
const u16 slot = next_free_slot;
|
|
|
|
if (slot >= table_size) {
|
|
|
|
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
|
2021-04-11 18:41:48 +00:00
|
|
|
return ResultOutOfHandles;
|
2021-04-04 02:11:46 +00:00
|
|
|
}
|
|
|
|
next_free_slot = generations[slot];
|
|
|
|
|
|
|
|
const u16 generation = next_generation++;
|
|
|
|
|
|
|
|
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
|
|
|
// Horizon OS uses zero to represent an invalid handle, so skip to 1.
|
|
|
|
if (next_generation >= (1 << 15)) {
|
|
|
|
next_generation = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
generations[slot] = generation;
|
2021-04-21 05:18:56 +00:00
|
|
|
objects[slot] = obj;
|
2021-04-04 02:11:46 +00:00
|
|
|
obj->Open();
|
|
|
|
|
|
|
|
*out_handle = generation | (slot << 15);
|
|
|
|
|
|
|
|
return RESULT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2017-05-29 23:45:42 +00:00
|
|
|
ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
|
2021-04-21 05:18:56 +00:00
|
|
|
auto object = GetObject(handle);
|
|
|
|
if (object.IsNull()) {
|
2018-07-02 16:13:26 +00:00
|
|
|
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: {:08X}", handle);
|
2021-02-12 23:43:01 +00:00
|
|
|
return ResultInvalidHandle;
|
2017-05-29 23:45:42 +00:00
|
|
|
}
|
2021-04-21 05:18:56 +00:00
|
|
|
|
|
|
|
Handle out_handle{};
|
|
|
|
R_TRY(Add(&out_handle, object.GetPointerUnsafe()));
|
|
|
|
|
|
|
|
return MakeResult(out_handle);
|
2017-05-29 23:45:42 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 02:11:46 +00:00
|
|
|
bool HandleTable::Remove(Handle handle) {
|
2019-02-25 16:06:00 +00:00
|
|
|
if (!IsValid(handle)) {
|
2020-04-29 04:53:53 +00:00
|
|
|
LOG_ERROR(Kernel, "Handle is not valid! handle={:08X}", handle);
|
2021-04-04 02:11:46 +00:00
|
|
|
return {};
|
2019-02-25 16:06:00 +00:00
|
|
|
}
|
2017-05-29 23:45:42 +00:00
|
|
|
|
2019-02-25 16:06:00 +00:00
|
|
|
const u16 slot = GetSlot(handle);
|
2017-05-29 23:45:42 +00:00
|
|
|
|
2021-04-04 02:11:46 +00:00
|
|
|
if (objects[slot]) {
|
|
|
|
objects[slot]->Close();
|
|
|
|
}
|
|
|
|
|
2017-05-29 23:45:42 +00:00
|
|
|
objects[slot] = nullptr;
|
|
|
|
|
|
|
|
generations[slot] = next_free_slot;
|
|
|
|
next_free_slot = slot;
|
2021-04-04 02:11:46 +00:00
|
|
|
|
|
|
|
return true;
|
2017-05-29 23:45:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HandleTable::IsValid(Handle handle) const {
|
2019-02-25 16:06:00 +00:00
|
|
|
const std::size_t slot = GetSlot(handle);
|
|
|
|
const u16 generation = GetGeneration(handle);
|
2021-04-21 05:18:56 +00:00
|
|
|
const bool is_object_valid = (objects[slot] != nullptr);
|
2021-04-04 02:11:46 +00:00
|
|
|
return slot < table_size && is_object_valid && generations[slot] == generation;
|
2017-05-29 23:45:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void HandleTable::Clear() {
|
2019-02-25 15:13:52 +00:00
|
|
|
for (u16 i = 0; i < table_size; ++i) {
|
2020-10-13 12:10:50 +00:00
|
|
|
generations[i] = static_cast<u16>(i + 1);
|
2017-05-29 23:45:42 +00:00
|
|
|
objects[i] = nullptr;
|
|
|
|
}
|
|
|
|
next_free_slot = 0;
|
|
|
|
}
|
|
|
|
|
2018-01-20 07:48:02 +00:00
|
|
|
} // namespace Kernel
|