aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/kernel/kernel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/kernel.cpp')
-rw-r--r--src/core/hle/kernel/kernel.cpp139
1 files changed, 74 insertions, 65 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 018000ab..e59ed1b5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1,106 +1,117 @@
-// Copyright 2014 Citra Emulator Project / PPSSPP Project
-// Licensed under GPLv2
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+
#include "common/common.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
-#include "core/hle/kernel/archive.h"
namespace Kernel {
Handle g_main_thread = 0;
-ObjectPool g_object_pool;
+HandleTable g_handle_table;
+u64 g_program_id = 0;
-ObjectPool::ObjectPool() {
- next_id = INITIAL_NEXT_ID;
+HandleTable::HandleTable() {
+ next_generation = 1;
+ Clear();
}
-Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
- if (range_top > MAX_COUNT) {
- range_top = MAX_COUNT;
- }
- if (next_id >= range_bottom && next_id < range_top) {
- range_bottom = next_id++;
- }
- for (int i = range_bottom; i < range_top; i++) {
- if (!occupied[i]) {
- occupied[i] = true;
- pool[i] = obj;
- pool[i]->handle = i + HANDLE_OFFSET;
- return i + HANDLE_OFFSET;
- }
+ResultVal<Handle> HandleTable::Create(Object* obj) {
+ _dbg_assert_(Kernel, 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;
}
- ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
- return 0;
-}
+ next_free_slot = generations[slot];
+
+ u16 generation = next_generation++;
-bool ObjectPool::IsValid(Handle handle) {
- int index = handle - HANDLE_OFFSET;
- if (index < 0)
- return false;
- if (index >= MAX_COUNT)
- return false;
+ // 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;
- return occupied[index];
+ generations[slot] = generation;
+ intrusive_ptr_add_ref(obj);
+ objects[slot] = obj;
+
+ Handle handle = generation | (slot << 15);
+ obj->handle = handle;
+ return MakeResult<Handle>(handle);
}
-void ObjectPool::Clear() {
- for (int i = 0; i < MAX_COUNT; i++) {
- //brutally clear everything, no validation
- if (occupied[i])
- delete pool[i];
- occupied[i] = false;
+ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
+ Object* object = GetGeneric(handle);
+ if (object == nullptr) {
+ LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
+ return ERR_INVALID_HANDLE;
}
- pool.fill(nullptr);
- next_id = INITIAL_NEXT_ID;
+ return Create(object);
+}
+
+ResultCode HandleTable::Close(Handle handle) {
+ if (!IsValid(handle))
+ return ERR_INVALID_HANDLE;
+
+ size_t slot = GetSlot(handle);
+ u16 generation = GetGeneration(handle);
+
+ intrusive_ptr_release(objects[slot]);
+ objects[slot] = nullptr;
+
+ generations[generation] = next_free_slot;
+ next_free_slot = slot;
+ return RESULT_SUCCESS;
}
-Object* &ObjectPool::operator [](Handle handle)
-{
- _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
- return pool[handle - HANDLE_OFFSET];
+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;
}
-void ObjectPool::List() {
- for (int i = 0; i < MAX_COUNT; i++) {
- if (occupied[i]) {
- if (pool[i]) {
- INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(),
- pool[i]->GetName().c_str());
- }
- }
+Object* HandleTable::GetGeneric(Handle handle) const {
+ if (handle == CurrentThread) {
+ // TODO(yuriks) Directly return the pointer once this is possible.
+ handle = GetCurrentThreadHandle();
+ } else if (handle == CurrentProcess) {
+ LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
+ return nullptr;
}
-}
-int ObjectPool::GetCount() {
- int count = 0;
- for (int i = 0; i < MAX_COUNT; i++) {
- if (occupied[i])
- count++;
+ if (!IsValid(handle)) {
+ return nullptr;
}
- return count;
+ return objects[GetSlot(handle)];
}
-Object* ObjectPool::CreateByIDType(int type) {
- ERROR_LOG(COMMON, "Unimplemented: %d.", type);
- return nullptr;
+void HandleTable::Clear() {
+ for (size_t i = 0; i < MAX_COUNT; ++i) {
+ generations[i] = i + 1;
+ if (objects[i] != nullptr)
+ intrusive_ptr_release(objects[i]);
+ objects[i] = nullptr;
+ }
+ next_free_slot = 0;
}
/// Initialize the kernel
void Init() {
Kernel::ThreadingInit();
- Kernel::ArchiveInit();
}
/// Shutdown the kernel
void Shutdown() {
Kernel::ThreadingShutdown();
- Kernel::ArchiveShutdown();
- g_object_pool.Clear(); // Free all kernel objects
+ g_handle_table.Clear(); // Free all kernel objects
}
/**
@@ -109,8 +120,6 @@ void Shutdown() {
* @return True on success, otherwise false
*/
bool LoadExec(u32 entry_point) {
- Init();
-
Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far