Kernel: Start using boost::intrusive_ptr for lifetime management

master
Yuri Kunde Schlesner 2014-12-29 10:55:30 +07:00
parent d751de7341
commit 8ad41775cc
13 changed files with 96 additions and 91 deletions

2
externals/boost vendored

@ -1 +1 @@
Subproject commit 97052c28acb141dbf3c5e14114af99045344b695 Subproject commit a1afc91d3aaa3da06bdbc13c78613e1466653405

@ -30,7 +30,7 @@ public:
/// Arbitrate an address /// Arbitrate an address
ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) {
Object* object = Kernel::g_handle_table.GetGeneric(handle); Object* object = Kernel::g_handle_table.GetGeneric(handle).get();
if (object == nullptr) if (object == nullptr)
return InvalidHandle(ErrorModule::Kernel); return InvalidHandle(ErrorModule::Kernel);

@ -53,7 +53,7 @@ public:
* @return Result of operation, 0 on success, otherwise error code * @return Result of operation, 0 on success, otherwise error code
*/ */
ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
Event* evt = g_handle_table.Get<Event>(handle); Event* evt = g_handle_table.Get<Event>(handle).get();
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
evt->permanent_locked = permanent_locked; evt->permanent_locked = permanent_locked;
@ -67,7 +67,7 @@ ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
* @return Result of operation, 0 on success, otherwise error code * @return Result of operation, 0 on success, otherwise error code
*/ */
ResultCode SetEventLocked(const Handle handle, const bool locked) { ResultCode SetEventLocked(const Handle handle, const bool locked) {
Event* evt = g_handle_table.Get<Event>(handle); Event* evt = g_handle_table.Get<Event>(handle).get();
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
if (!evt->permanent_locked) { if (!evt->permanent_locked) {
@ -82,13 +82,13 @@ ResultCode SetEventLocked(const Handle handle, const bool locked) {
* @return Result of operation, 0 on success, otherwise error code * @return Result of operation, 0 on success, otherwise error code
*/ */
ResultCode SignalEvent(const Handle handle) { ResultCode SignalEvent(const Handle handle) {
Event* evt = g_handle_table.Get<Event>(handle); Event* evt = g_handle_table.Get<Event>(handle).get();
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
// Resume threads waiting for event to signal // Resume threads waiting for event to signal
bool event_caught = false; bool event_caught = false;
for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]); Thread* thread = Kernel::g_handle_table.Get<Thread>(evt->waiting_threads[i]).get();
if (thread != nullptr) if (thread != nullptr)
thread->ResumeFromWait(); thread->ResumeFromWait();
@ -112,7 +112,7 @@ ResultCode SignalEvent(const Handle handle) {
* @return Result of operation, 0 on success, otherwise error code * @return Result of operation, 0 on success, otherwise error code
*/ */
ResultCode ClearEvent(Handle handle) { ResultCode ClearEvent(Handle handle) {
Event* evt = g_handle_table.Get<Event>(handle); Event* evt = g_handle_table.Get<Event>(handle).get();
if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
if (!evt->permanent_locked) { if (!evt->permanent_locked) {

@ -14,7 +14,7 @@
namespace Kernel { namespace Kernel {
Thread* g_main_thread = nullptr; SharedPtr<Thread> g_main_thread = nullptr;
HandleTable g_handle_table; HandleTable g_handle_table;
u64 g_program_id = 0; u64 g_program_id = 0;
@ -23,7 +23,7 @@ HandleTable::HandleTable() {
Clear(); Clear();
} }
ResultVal<Handle> HandleTable::Create(Object* obj) { ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
_dbg_assert_(Kernel, obj != nullptr); _dbg_assert_(Kernel, obj != nullptr);
u16 slot = next_free_slot; u16 slot = next_free_slot;
@ -39,23 +39,23 @@ ResultVal<Handle> HandleTable::Create(Object* obj) {
// CTR-OS doesn't use generation 0, so skip straight to 1. // CTR-OS doesn't use generation 0, so skip straight to 1.
if (next_generation >= (1 << 15)) next_generation = 1; if (next_generation >= (1 << 15)) next_generation = 1;
generations[slot] = generation;
intrusive_ptr_add_ref(obj);
objects[slot] = obj;
Handle handle = generation | (slot << 15); Handle handle = generation | (slot << 15);
if (obj->handle == INVALID_HANDLE) if (obj->handle == INVALID_HANDLE)
obj->handle = handle; obj->handle = handle;
generations[slot] = generation;
objects[slot] = std::move(obj);
return MakeResult<Handle>(handle); return MakeResult<Handle>(handle);
} }
ResultVal<Handle> HandleTable::Duplicate(Handle handle) { ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
Object* object = GetGeneric(handle); SharedPtr<Object> object = GetGeneric(handle);
if (object == nullptr) { if (object == nullptr) {
LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle); LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
} }
return Create(object); return Create(std::move(object));
} }
ResultCode HandleTable::Close(Handle handle) { ResultCode HandleTable::Close(Handle handle) {
@ -65,7 +65,6 @@ ResultCode HandleTable::Close(Handle handle) {
size_t slot = GetSlot(handle); size_t slot = GetSlot(handle);
u16 generation = GetGeneration(handle); u16 generation = GetGeneration(handle);
intrusive_ptr_release(objects[slot]);
objects[slot] = nullptr; objects[slot] = nullptr;
generations[generation] = next_free_slot; generations[generation] = next_free_slot;
@ -80,7 +79,7 @@ bool HandleTable::IsValid(Handle handle) const {
return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
} }
Object* HandleTable::GetGeneric(Handle handle) const { SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
if (handle == CurrentThread) { if (handle == CurrentThread) {
return GetCurrentThread(); return GetCurrentThread();
} else if (handle == CurrentProcess) { } else if (handle == CurrentProcess) {
@ -97,8 +96,6 @@ Object* HandleTable::GetGeneric(Handle handle) const {
void HandleTable::Clear() { void HandleTable::Clear() {
for (size_t i = 0; i < MAX_COUNT; ++i) { for (size_t i = 0; i < MAX_COUNT; ++i) {
generations[i] = i + 1; generations[i] = i + 1;
if (objects[i] != nullptr)
intrusive_ptr_release(objects[i]);
objects[i] = nullptr; objects[i] = nullptr;
} }
next_free_slot = 0; next_free_slot = 0;
@ -126,7 +123,7 @@ bool LoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point); Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far // 0x30 is the typical main thread priority I've seen used so far
g_main_thread = Kernel::SetupMainThread(0x30); g_main_thread = Kernel::SetupMainThread(0x30, Kernel::DEFAULT_STACK_SIZE);
// Setup the idle thread // Setup the idle thread
Kernel::SetupIdleThread(); Kernel::SetupIdleThread();

@ -4,6 +4,8 @@
#pragma once #pragma once
#include <boost/intrusive_ptr.hpp>
#include <array> #include <array>
#include <string> #include <string>
#include "common/common.h" #include "common/common.h"
@ -76,7 +78,7 @@ private:
unsigned int ref_count = 0; unsigned int ref_count = 0;
}; };
// Special functions that will later be used by boost::instrusive_ptr to do automatic ref-counting // Special functions used by boost::instrusive_ptr to do automatic ref-counting
inline void intrusive_ptr_add_ref(Object* object) { inline void intrusive_ptr_add_ref(Object* object) {
++object->ref_count; ++object->ref_count;
} }
@ -87,6 +89,9 @@ inline void intrusive_ptr_release(Object* object) {
} }
} }
template <typename T>
using SharedPtr = boost::intrusive_ptr<T>;
/** /**
* This class allows the creation of Handles, which are references to objects that can be tested * This class allows the creation of Handles, which are references to objects that can be tested
* for validity and looked up. Here they are used to pass references to kernel objects to/from the * for validity and looked up. Here they are used to pass references to kernel objects to/from the
@ -119,7 +124,7 @@ public:
* @return The created Handle or one of the following errors: * @return The created Handle or one of the following errors:
* - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded. * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
*/ */
ResultVal<Handle> Create(Object* obj); ResultVal<Handle> Create(SharedPtr<Object> obj);
/** /**
* Returns a new handle that points to the same object as the passed in handle. * Returns a new handle that points to the same object as the passed in handle.
@ -143,7 +148,7 @@ public:
* Looks up a handle. * Looks up a handle.
* @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid. * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid.
*/ */
Object* GetGeneric(Handle handle) const; SharedPtr<Object> GetGeneric(Handle handle) const;
/** /**
* Looks up a handle while verifying its type. * Looks up a handle while verifying its type.
@ -151,10 +156,10 @@ public:
* type differs from the handle type `T::HANDLE_TYPE`. * type differs from the handle type `T::HANDLE_TYPE`.
*/ */
template <class T> template <class T>
T* Get(Handle handle) const { SharedPtr<T> Get(Handle handle) const {
Object* object = GetGeneric(handle); SharedPtr<Object> object = GetGeneric(handle);
if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
return static_cast<T*>(object); return boost::static_pointer_cast<T>(std::move(object));
} }
return nullptr; return nullptr;
} }
@ -173,7 +178,7 @@ private:
static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; } static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
/// Stores the Object referenced by the handle or null if the slot is empty. /// Stores the Object referenced by the handle or null if the slot is empty.
std::array<Object*, MAX_COUNT> objects; std::array<SharedPtr<Object>, MAX_COUNT> objects;
/** /**
* The value of `next_generation` when the handle was created, used to check for validity. For * The value of `next_generation` when the handle was created, used to check for validity. For
@ -192,7 +197,7 @@ private:
}; };
extern HandleTable g_handle_table; extern HandleTable g_handle_table;
extern Thread* g_main_thread; extern SharedPtr<Thread> g_main_thread;
/// The ID code of the currently running game /// The ID code of the currently running game
/// TODO(Subv): This variable should not be here, /// TODO(Subv): This variable should not be here,

@ -48,7 +48,7 @@ void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThread()->GetHandl
bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) { bool ReleaseMutexForThread(Mutex* mutex, Handle thread_handle) {
MutexAcquireLock(mutex, thread_handle); MutexAcquireLock(mutex, thread_handle);
Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle); Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle).get();
if (thread == nullptr) { if (thread == nullptr) {
LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle); LOG_ERROR(Kernel, "Called with invalid handle: %08X", thread_handle);
return false; return false;
@ -94,7 +94,7 @@ void ReleaseThreadMutexes(Handle thread) {
// Release every mutex that the thread holds, and resume execution on the waiting threads // Release every mutex that the thread holds, and resume execution on the waiting threads
for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
Mutex* mutex = g_handle_table.Get<Mutex>(iter->second); Mutex* mutex = g_handle_table.Get<Mutex>(iter->second).get();
ResumeWaitingThread(mutex); ResumeWaitingThread(mutex);
} }
@ -122,7 +122,7 @@ bool ReleaseMutex(Mutex* mutex) {
* @param handle Handle to mutex to release * @param handle Handle to mutex to release
*/ */
ResultCode ReleaseMutex(Handle handle) { ResultCode ReleaseMutex(Handle handle) {
Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle); Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle).get();
if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
if (!ReleaseMutex(mutex)) { if (!ReleaseMutex(mutex)) {

@ -70,7 +70,7 @@ ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
} }
ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) { ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle); Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle).get();
if (semaphore == nullptr) if (semaphore == nullptr)
return InvalidHandle(ErrorModule::Kernel); return InvalidHandle(ErrorModule::Kernel);
@ -84,7 +84,7 @@ ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
// Notify some of the threads that the semaphore has been released // Notify some of the threads that the semaphore has been released
// stop once the semaphore is full again or there are no more waiting threads // stop once the semaphore is full again or there are no more waiting threads
while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) { while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) {
Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()); Thread* thread = Kernel::g_handle_table.Get<Thread>(semaphore->waiting_threads.front()).get();
if (thread != nullptr) if (thread != nullptr)
thread->ResumeFromWait(); thread->ResumeFromWait();
semaphore->waiting_threads.pop(); semaphore->waiting_threads.pop();

@ -61,7 +61,7 @@ ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent); ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
} }
SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get();
if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
shared_memory->base_address = address; shared_memory->base_address = address;
@ -72,7 +72,7 @@ ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions
} }
ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle).get();
if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
if (0 != shared_memory->base_address) if (0 != shared_memory->base_address)

@ -36,7 +36,7 @@ ResultVal<bool> Thread::WaitSynchronization() {
} }
// Lists all thread ids that aren't deleted/etc. // Lists all thread ids that aren't deleted/etc.
static std::vector<Thread*> thread_list; // TODO(yuriks): Owned static std::vector<SharedPtr<Thread>> thread_list;
// Lists only ready thread ids. // Lists only ready thread ids.
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> thread_ready_queue; static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> thread_ready_queue;
@ -110,8 +110,8 @@ void Thread::Stop(const char* reason) {
ChangeReadyState(this, false); ChangeReadyState(this, false);
status = THREADSTATUS_DORMANT; status = THREADSTATUS_DORMANT;
for (Thread* waiting_thread : waiting_threads) { for (auto& waiting_thread : waiting_threads) {
if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, this)) if (CheckWaitType(waiting_thread.get(), WAITTYPE_THREADEND, this))
waiting_thread->ResumeFromWait(); waiting_thread->ResumeFromWait();
} }
waiting_threads.clear(); waiting_threads.clear();
@ -143,15 +143,15 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) {
s32 priority = THREADPRIO_LOWEST; s32 priority = THREADPRIO_LOWEST;
// Iterate through threads, find highest priority thread that is waiting to be arbitrated... // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
for (Thread* thread : thread_list) { for (auto& thread : thread_list) {
if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) if (!CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address))
continue; continue;
if (thread == nullptr) if (thread == nullptr)
continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
if(thread->current_priority <= priority) { if(thread->current_priority <= priority) {
highest_priority_thread = thread; highest_priority_thread = thread.get();
priority = thread->current_priority; priority = thread->current_priority;
} }
} }
@ -168,8 +168,8 @@ Thread* ArbitrateHighestPriorityThread(Object* arbiter, u32 address) {
void ArbitrateAllThreads(Object* arbiter, u32 address) { void ArbitrateAllThreads(Object* arbiter, u32 address) {
// Iterate through threads, find highest priority thread that is waiting to be arbitrated... // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
for (Thread* thread : thread_list) { for (auto& thread : thread_list) {
if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address)) if (CheckWaitType(thread.get(), WAITTYPE_ARB, arbiter, address))
thread->ResumeFromWait(); thread->ResumeFromWait();
} }
} }
@ -241,7 +241,7 @@ static int ThreadWakeupEventType = -1;
/// Callback that will wake up the thread it was scheduled for /// Callback that will wake up the thread it was scheduled for
static void ThreadWakeupCallback(u64 parameter, int cycles_late) { static void ThreadWakeupCallback(u64 parameter, int cycles_late) {
Handle handle = static_cast<Handle>(parameter); Handle handle = static_cast<Handle>(parameter);
Thread* thread = Kernel::g_handle_table.Get<Thread>(handle); SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(handle);
if (thread == nullptr) { if (thread == nullptr) {
LOG_ERROR(Kernel, "Thread doesn't exist %u", handle); LOG_ERROR(Kernel, "Thread doesn't exist %u", handle);
return; return;
@ -278,20 +278,18 @@ static void DebugThreadQueue() {
return; return;
} }
LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle()); LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThread()->GetHandle());
for (Thread* t : thread_list) { for (auto& t : thread_list) {
s32 priority = thread_ready_queue.contains(t); s32 priority = thread_ready_queue.contains(t.get());
if (priority != -1) { if (priority != -1) {
LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle()); LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, t->GetHandle());
} }
} }
} }
ResultVal<Thread*> Thread::Create(const char* name, u32 entry_point, s32 priority, u32 arg, ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size) { u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size) {
_dbg_assert_(Kernel, name != nullptr); if (stack_size < 0x200) {
LOG_ERROR(Kernel, "(name=%s): invalid stack_size=0x%08X", name.c_str(), stack_size);
if ((u32)stack_size < 0x200) {
LOG_ERROR(Kernel, "(name=%s): invalid stack_size=0x%08X", name, stack_size);
// TODO: Verify error // TODO: Verify error
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Kernel, return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent); ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
@ -300,27 +298,26 @@ ResultVal<Thread*> Thread::Create(const char* name, u32 entry_point, s32 priorit
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
name, priority, new_priority); name.c_str(), priority, new_priority);
// TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
// validity of this // validity of this
priority = new_priority; priority = new_priority;
} }
if (!Memory::GetPointer(entry_point)) { if (!Memory::GetPointer(entry_point)) {
LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point); LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
// TODO: Verify error // TODO: Verify error
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent); ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
} }
Thread* thread = new Thread; SharedPtr<Thread> thread(new Thread);
// TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for // TODO(yuriks): Thread requires a handle to be inserted into the various scheduling queues for
// the time being. Create a handle here, it will be copied to the handle field in // the time being. Create a handle here, it will be copied to the handle field in
// the object and use by the rest of the code. This should be removed when other // the object and use by the rest of the code. This should be removed when other
// code doesn't rely on the handle anymore. // code doesn't rely on the handle anymore.
ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread); ResultVal<Handle> handle = Kernel::g_handle_table.Create(thread);
// TODO(yuriks): Plug memory leak
if (handle.Failed()) if (handle.Failed())
return handle.Code(); return handle.Code();
@ -337,12 +334,12 @@ ResultVal<Thread*> Thread::Create(const char* name, u32 entry_point, s32 priorit
thread->wait_type = WAITTYPE_NONE; thread->wait_type = WAITTYPE_NONE;
thread->wait_object = nullptr; thread->wait_object = nullptr;
thread->wait_address = 0; thread->wait_address = 0;
thread->name = name; thread->name = std::move(name);
ResetThread(thread, arg, 0); ResetThread(thread.get(), arg, 0);
CallThread(thread); CallThread(thread.get());
return MakeResult<Thread*>(thread); return MakeResult<SharedPtr<Thread>>(std::move(thread));
} }
/// Set the priority of the thread specified by handle /// Set the priority of the thread specified by handle
@ -376,20 +373,20 @@ Handle SetupIdleThread() {
auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0, auto thread_res = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE); THREADPROCESSORID_0, 0, Kernel::DEFAULT_STACK_SIZE);
_dbg_assert_(Kernel, thread_res.Succeeded()); _dbg_assert_(Kernel, thread_res.Succeeded());
Thread* thread = *thread_res; SharedPtr<Thread> thread = std::move(*thread_res);
thread->idle = true; thread->idle = true;
CallThread(thread); CallThread(thread.get());
return thread->GetHandle(); return thread->GetHandle();
} }
Thread* SetupMainThread(s32 priority, int stack_size) { SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size) {
// Initialize new "main" thread // Initialize new "main" thread
ResultVal<Thread*> thread_res = Thread::Create("main", Core::g_app_core->GetPC(), priority, 0, auto thread_res = Thread::Create("main", Core::g_app_core->GetPC(), priority, 0,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
// TODO(yuriks): Propagate error // TODO(yuriks): Propagate error
_dbg_assert_(Kernel, thread_res.Succeeded()); _dbg_assert_(Kernel, thread_res.Succeeded());
Thread* thread = *thread_res; SharedPtr<Thread> thread = std::move(*thread_res);
// If running another thread already, set it to "ready" state // If running another thread already, set it to "ready" state
Thread* cur = GetCurrentThread(); Thread* cur = GetCurrentThread();
@ -398,7 +395,7 @@ Thread* SetupMainThread(s32 priority, int stack_size) {
} }
// Run new "main" thread // Run new "main" thread
current_thread = thread; current_thread = thread.get();
thread->status = THREADSTATUS_RUNNING; thread->status = THREADSTATUS_RUNNING;
Core::g_app_core->LoadContext(thread->context); Core::g_app_core->LoadContext(thread->context);
@ -418,7 +415,7 @@ void Reschedule() {
} else { } else {
LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle()); LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
for (Thread* thread : thread_list) { for (auto& thread : thread_list) {
LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X", LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type,
(thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE)); (thread->wait_object ? thread->wait_object->GetHandle() : INVALID_HANDLE));

@ -54,8 +54,8 @@ namespace Kernel {
class Thread : public Kernel::Object { class Thread : public Kernel::Object {
public: public:
static ResultVal<Thread*> Create(const char* name, u32 entry_point, s32 priority, u32 arg, static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size = Kernel::DEFAULT_STACK_SIZE); u32 arg, s32 processor_id, VAddr stack_top, u32 stack_size);
std::string GetName() const override { return name; } std::string GetName() const override { return name; }
std::string GetTypeName() const override { return "Thread"; } std::string GetTypeName() const override { return "Thread"; }
@ -99,7 +99,7 @@ public:
Object* wait_object; Object* wait_object;
VAddr wait_address; VAddr wait_address;
std::vector<Thread*> waiting_threads; // TODO(yuriks): Owned std::vector<SharedPtr<Thread>> waiting_threads;
std::string name; std::string name;
@ -111,7 +111,7 @@ private:
}; };
/// Sets up the primary application thread /// Sets up the primary application thread
Thread* SetupMainThread(s32 priority, int stack_size = Kernel::DEFAULT_STACK_SIZE); SharedPtr<Thread> SetupMainThread(s32 priority, u32 stack_size);
/// Reschedules to the next available thread (call after current thread is suspended) /// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(); void Reschedule();

@ -66,7 +66,7 @@ ResultCode CreateTimer(Handle* handle, const ResetType reset_type, const std::st
} }
ResultCode ClearTimer(Handle handle) { ResultCode ClearTimer(Handle handle) {
Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
if (timer == nullptr) if (timer == nullptr)
return InvalidHandle(ErrorModule::Kernel); return InvalidHandle(ErrorModule::Kernel);
@ -80,7 +80,7 @@ static int TimerCallbackEventType = -1;
/// The timer callback event, called when a timer is fired /// The timer callback event, called when a timer is fired
static void TimerCallback(u64 timer_handle, int cycles_late) { static void TimerCallback(u64 timer_handle, int cycles_late) {
Timer* timer = Kernel::g_handle_table.Get<Timer>(timer_handle); SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(timer_handle);
if (timer == nullptr) { if (timer == nullptr) {
LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle); LOG_CRITICAL(Kernel, "Callback fired for invalid timer %u", timer_handle);
@ -93,7 +93,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
// Resume all waiting threads // Resume all waiting threads
for (Handle thread_handle : timer->waiting_threads) { for (Handle thread_handle : timer->waiting_threads) {
if (Thread* thread = Kernel::g_handle_table.Get<Thread>(thread_handle)) if (SharedPtr<Thread> thread = Kernel::g_handle_table.Get<Thread>(thread_handle))
thread->ResumeFromWait(); thread->ResumeFromWait();
} }
@ -111,7 +111,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
} }
ResultCode SetTimer(Handle handle, s64 initial, s64 interval) { ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
if (timer == nullptr) if (timer == nullptr)
return InvalidHandle(ErrorModule::Kernel); return InvalidHandle(ErrorModule::Kernel);
@ -125,7 +125,7 @@ ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
} }
ResultCode CancelTimer(Handle handle) { ResultCode CancelTimer(Handle handle) {
Timer* timer = Kernel::g_handle_table.Get<Timer>(handle); SharedPtr<Timer> timer = Kernel::g_handle_table.Get<Timer>(handle);
if (timer == nullptr) if (timer == nullptr)
return InvalidHandle(ErrorModule::Kernel); return InvalidHandle(ErrorModule::Kernel);

@ -59,7 +59,8 @@ void Manager::DeleteService(const std::string& port_name) {
} }
Interface* Manager::FetchFromHandle(Handle handle) { Interface* Manager::FetchFromHandle(Handle handle) {
return Kernel::g_handle_table.Get<Interface>(handle); // TODO(yuriks): This function is very suspicious and should probably be exterminated.
return Kernel::g_handle_table.Get<Interface>(handle).get();
} }
Interface* Manager::FetchFromPortName(const std::string& port_name) { Interface* Manager::FetchFromPortName(const std::string& port_name) {

@ -25,6 +25,8 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace SVC // Namespace SVC
using Kernel::SharedPtr;
namespace SVC { namespace SVC {
enum ControlMemoryOperation { enum ControlMemoryOperation {
@ -94,7 +96,7 @@ static Result ConnectToPort(Handle* out, const char* port_name) {
/// Synchronize to an OS service /// Synchronize to an OS service
static Result SendSyncRequest(Handle handle) { static Result SendSyncRequest(Handle handle) {
Kernel::Session* session = Kernel::g_handle_table.Get<Kernel::Session>(handle); SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
if (session == nullptr) { if (session == nullptr) {
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;
} }
@ -121,12 +123,12 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
// TODO(bunnei): Do something with nano_seconds, currently ignoring this // TODO(bunnei): Do something with nano_seconds, currently ignoring this
bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handle); SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handle);
if (object == nullptr) if (object == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;
LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
object->GetName().c_str(), nano_seconds); object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
ResultVal<bool> wait = object->WaitSynchronization(); ResultVal<bool> wait = object->WaitSynchronization();
@ -151,12 +153,12 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
// Iterate through each handle, synchronize kernel object // Iterate through each handle, synchronize kernel object
for (s32 i = 0; i < handle_count; i++) { for (s32 i = 0; i < handle_count; i++) {
Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handles[i]); SharedPtr<Kernel::Object> object = Kernel::g_handle_table.GetGeneric(handles[i]);
if (object == nullptr) if (object == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;
LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i],
object->GetName().c_str()); object->GetTypeName().c_str(), object->GetName().c_str());
// TODO(yuriks): Verify how the real function behaves when an error happens here // TODO(yuriks): Verify how the real function behaves when an error happens here
ResultVal<bool> wait_result = object->WaitSynchronization(); ResultVal<bool> wait_result = object->WaitSynchronization();
@ -223,6 +225,8 @@ static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit,
/// Creates a new thread /// Creates a new thread
static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
using Kernel::Thread;
std::string name; std::string name;
if (Symbols::HasSymbol(entry_point)) { if (Symbols::HasSymbol(entry_point)) {
TSymbol symbol = Symbols::GetSymbol(entry_point); TSymbol symbol = Symbols::GetSymbol(entry_point);
@ -231,12 +235,13 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top
name = Common::StringFromFormat("unknown-%08x", entry_point); name = Common::StringFromFormat("unknown-%08x", entry_point);
} }
ResultVal<Kernel::Thread*> thread_res = Kernel::Thread::Create(name.c_str(), entry_point, priority, arg, ResultVal<SharedPtr<Thread>> thread_res = Kernel::Thread::Create(
processor_id, stack_top); name, entry_point, priority, arg, processor_id, stack_top, Kernel::DEFAULT_STACK_SIZE);
if (thread_res.Failed()) if (thread_res.Failed())
return thread_res.Code().raw; return thread_res.Code().raw;
Kernel::Thread* thread = *thread_res; SharedPtr<Thread> thread = std::move(*thread_res);
// TODO(yuriks): Create new handle instead of using built-in
Core::g_app_core->SetReg(1, thread->GetHandle()); Core::g_app_core->SetReg(1, thread->GetHandle());
LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
@ -261,7 +266,7 @@ static void ExitThread() {
/// Gets the priority for the specified thread /// Gets the priority for the specified thread
static Result GetThreadPriority(s32* priority, Handle handle) { static Result GetThreadPriority(s32* priority, Handle handle) {
const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr) if (thread == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;
@ -271,7 +276,7 @@ static Result GetThreadPriority(s32* priority, Handle handle) {
/// Sets the priority for the specified thread /// Sets the priority for the specified thread
static Result SetThreadPriority(Handle handle, s32 priority) { static Result SetThreadPriority(Handle handle, s32 priority) {
Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr) if (thread == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;
@ -298,7 +303,7 @@ static Result ReleaseMutex(Handle handle) {
static Result GetThreadId(u32* thread_id, Handle handle) { static Result GetThreadId(u32* thread_id, Handle handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle); LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
const Kernel::Thread* thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle); const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr) if (thread == nullptr)
return InvalidHandle(ErrorModule::Kernel).raw; return InvalidHandle(ErrorModule::Kernel).raw;