diff options
author | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2014-12-21 13:04:08 +0100 |
---|---|---|
committer | Yuri Kunde Schlesner <yuriks@yuriks.net> | 2014-12-28 14:52:55 +0100 |
commit | 7e2903cb74050d846f2da951dff7e84aee13761b (patch) | |
tree | 621c9245d2dd393a9569b1b4192f50a27d831972 /src/core | |
parent | Kernel: Replace GetStaticHandleType by HANDLE_TYPE constants (diff) | |
download | yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar.gz yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar.bz2 yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar.lz yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar.xz yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.tar.zst yuzu-7e2903cb74050d846f2da951dff7e84aee13761b.zip |
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/event.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 118 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.h | 190 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 5 | ||||
-rw-r--r-- | src/core/hle/kernel/semaphore.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 3 | ||||
-rw-r--r-- | src/core/hle/service/fs/archive.cpp | 10 | ||||
-rw-r--r-- | src/core/hle/service/service.cpp | 3 | ||||
-rw-r--r-- | src/core/hle/service/service.h | 5 | ||||
-rw-r--r-- | src/core/hle/svc.cpp | 28 |
13 files changed, 209 insertions, 168 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index acdbc92b3..38705e3cd 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -62,7 +62,8 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3 /// Create an address arbiter AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { AddressArbiter* address_arbiter = new AddressArbiter; - handle = Kernel::g_handle_table.Create(address_arbiter); + // TOOD(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE); address_arbiter->name = name; return address_arbiter; } diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 6a0e294cb..e43c3ee4e 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -129,7 +129,8 @@ ResultCode ClearEvent(Handle handle) { Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { Event* evt = new Event; - handle = Kernel::g_handle_table.Create(evt); + // TOOD(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE); evt->locked = true; evt->permanent_locked = false; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e8bf83a44..e59ed1b57 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -17,73 +17,89 @@ HandleTable g_handle_table; u64 g_program_id = 0; HandleTable::HandleTable() { - next_id = INITIAL_NEXT_ID; + next_generation = 1; + Clear(); } -Handle HandleTable::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; } - LOG_ERROR(Kernel, "Unable to allocate kernel object, too many objects slots in use."); - return 0; -} + next_free_slot = generations[slot]; -bool HandleTable::IsValid(Handle handle) const { - int index = handle - HANDLE_OFFSET; - if (index < 0) - return false; - if (index >= MAX_COUNT) - return false; + u16 generation = next_generation++; - return occupied[index]; + // 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; + intrusive_ptr_add_ref(obj); + objects[slot] = obj; + + Handle handle = generation | (slot << 15); + obj->handle = handle; + return MakeResult<Handle>(handle); } -void HandleTable::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); } -Object* &HandleTable::operator [](Handle handle) -{ - _dbg_assert_msg_(Kernel, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); - return pool[handle - HANDLE_OFFSET]; +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; } -void HandleTable::List() { - for (int i = 0; i < MAX_COUNT; i++) { - if (occupied[i]) { - if (pool[i]) { - LOG_DEBUG(Kernel, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), - pool[i]->GetName().c_str()); - } - } - } +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; } -int HandleTable::GetCount() const { - return std::count(occupied.begin(), occupied.end(), true); +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; + } + + if (!IsValid(handle)) { + return nullptr; + } + return objects[GetSlot(handle)]; } -Object* HandleTable::CreateByIDType(int type) { - LOG_ERROR(Kernel, "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 diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 27c406ad4..7f86fd07d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -12,13 +12,17 @@ typedef u32 Handle; typedef s32 Result; +const Handle INVALID_HANDLE = 0; + namespace Kernel { -// From kernel.h. Declarations duplicated here to avoid a circular header dependency. -class Thread; -Thread* GetCurrentThread(); +// TODO: Verify code +const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, + ErrorSummary::OutOfResource, ErrorLevel::Temporary); +// TOOD: Verify code +const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel); -enum KernelHandle { +enum KernelHandle : Handle { CurrentThread = 0xFFFF8000, CurrentProcess = 0xFFFF8001, }; @@ -61,103 +65,127 @@ public: LOG_ERROR(Kernel, "(UNIMPLEMENTED)"); return UnimplementedFunction(ErrorModule::Kernel); } -}; -class HandleTable : NonCopyable { -public: - HandleTable(); - ~HandleTable() {} +private: + friend void intrusive_ptr_add_ref(Object*); + friend void intrusive_ptr_release(Object*); - // Allocates a handle within the range and inserts the object into the map. - Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); + unsigned int ref_count = 0; +}; - static Object* CreateByIDType(int type); +// Special functions that will later be used by boost::instrusive_ptr to do automatic ref-counting +inline void intrusive_ptr_add_ref(Object* object) { + ++object->ref_count; +} - template <class T> - void Destroy(Handle handle) { - if (Get<T>(handle)) { - occupied[handle - HANDLE_OFFSET] = false; - delete pool[handle - HANDLE_OFFSET]; - } +inline void intrusive_ptr_release(Object* object) { + if (--object->ref_count == 0) { + delete object; } +} - bool IsValid(Handle handle) const; +/** + * 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 + * emulated process. it has been designed so that it follows the same handle format and has + * approximately the same restrictions as the handle manager in the CTR-OS. + * + * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0). + * The slot index is used to index into the arrays in this class to access the data corresponding + * to the Handle. + * + * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter + * is kept and incremented every time a Handle is created. This is the Handle's "generation". The + * value of the counter is stored into the Handle as well as in the handle table (in the + * "generations" array). When looking up a handle, the Handle's generation must match with the + * value stored on the class, otherwise the Handle is considered invalid. + * + * To find free slots when allocating a Handle without needing to scan the entire object array, the + * generations field of unallocated slots is re-purposed as a linked list of indices to free slots. + * When a Handle is created, an index is popped off the list and used for the new Handle. When it + * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is + * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been + * verified and isn't likely to cause any problems. + */ +class HandleTable final : NonCopyable { +public: + HandleTable(); - template <class T> - T* Get(Handle handle) { - if (handle == CurrentThread) { - return reinterpret_cast<T*>(GetCurrentThread()); - } + /** + * Allocates a handle for the given object. + * @return The created Handle or one of the following errors: + * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded. + */ + ResultVal<Handle> Create(Object* obj); - if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { - if (handle != 0) { - LOG_ERROR(Kernel, "Bad object handle %08x", handle); - } - return nullptr; - } else { - Object* t = pool[handle - HANDLE_OFFSET]; - if (t->GetHandleType() != T::HANDLE_TYPE) { - LOG_ERROR(Kernel, "Wrong object type for %08x", handle); - return nullptr; - } - return static_cast<T*>(t); - } - } + /** + * Returns a new handle that points to the same object as the passed in handle. + * @return The duplicated Handle or one of the following errors: + * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. + * - Any errors returned by `Create()`. + */ + ResultVal<Handle> Duplicate(Handle handle); - // ONLY use this when you know the handle is valid. - template <class T> - T *GetFast(Handle handle) { - if (handle == CurrentThread) { - return reinterpret_cast<T*>(GetCurrentThread()); - } + /** + * Closes a handle, removing it from the table and decreasing the object's ref-count. + * @return `RESULT_SUCCESS` or one of the following errors: + * - `ERR_INVALID_HANDLE`: an invalid handle was passed in. + */ + ResultCode Close(Handle handle); - const Handle realHandle = handle - HANDLE_OFFSET; - _dbg_assert_(Kernel, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]); - return static_cast<T*>(pool[realHandle]); - } + /// Checks if a handle is valid and points to an existing object. + bool IsValid(Handle handle) const; - template <class T, typename ArgT> - void Iterate(bool func(T*, ArgT), ArgT arg) { - int type = T::GetStaticIDType(); - for (int i = 0; i < MAX_COUNT; i++) - { - if (!occupied[i]) - continue; - T* t = static_cast<T*>(pool[i]); - if (t->GetIDType() == type) { - if (!func(t, arg)) - break; - } - } - } + /** + * Looks up a handle. + * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid. + */ + Object* GetGeneric(Handle handle) const; - bool GetIDType(Handle handle, HandleType* type) const { - if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || - !occupied[handle - HANDLE_OFFSET]) { - LOG_ERROR(Kernel, "Bad object handle %08X", handle); - return false; + /** + * Looks up a handle while verifying its type. + * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its + * type differs from the handle type `T::HANDLE_TYPE`. + */ + template <class T> + T* Get(Handle handle) const { + Object* object = GetGeneric(handle); + if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { + return static_cast<T*>(object); } - Object* t = pool[handle - HANDLE_OFFSET]; - *type = t->GetHandleType(); - return true; + return nullptr; } - Object* &operator [](Handle handle); - void List(); + /// Closes all handles held in this table. void Clear(); - int GetCount() const; private: + /** + * This is the maximum limit of handles allowed per process in CTR-OS. It can be further + * reduced by ExHeader values, but this is not emulated here. + */ + static const size_t MAX_COUNT = 4096; + + static size_t GetSlot(Handle handle) { return handle >> 15; } + static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; } + + /// Stores the Object referenced by the handle or null if the slot is empty. + std::array<Object*, MAX_COUNT> objects; - enum { - MAX_COUNT = 0x1000, - HANDLE_OFFSET = 0x100, - INITIAL_NEXT_ID = 0x10, - }; + /** + * The value of `next_generation` when the handle was created, used to check for validity. For + * empty slots, contains the index of the next free slot in the list. + */ + std::array<u16, MAX_COUNT> generations; + + /** + * Global counter of the number of created handles. Stored in `generations` when a handle is + * created, and wraps around to 1 when it hits 0x8000. + */ + u16 next_generation; - std::array<Object*, MAX_COUNT> pool; - std::array<bool, MAX_COUNT> occupied; - int next_id; + /// Head of the free slots linked list. + u16 next_free_slot; }; extern HandleTable g_handle_table; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 08462376d..558068c79 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -87,7 +87,7 @@ void ReleaseThreadMutexes(Handle thread) { // Release every mutex that the thread holds, and resume execution on the waiting threads for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { - Mutex* mutex = g_handle_table.GetFast<Mutex>(iter->second); + Mutex* mutex = g_handle_table.Get<Mutex>(iter->second); ResumeWaitingThread(mutex); } @@ -136,7 +136,8 @@ ResultCode ReleaseMutex(Handle handle) { */ Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { Mutex* mutex = new Mutex; - handle = Kernel::g_handle_table.Create(mutex); + // TODO(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE); mutex->locked = mutex->initial_locked = initial_locked; mutex->name = name; diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 1dee15f10..6bc8066a6 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -57,7 +57,8 @@ ResultCode CreateSemaphore(Handle* handle, s32 initial_count, ErrorSummary::WrongArgument, ErrorLevel::Permanent); Semaphore* semaphore = new Semaphore; - *handle = g_handle_table.Create(semaphore); + // TOOD(yuriks): Fix error reporting + *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE); // When the semaphore is created, some slots are reserved for other threads, // and the rest is reserved for the caller thread diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index bd9d947a3..cea1f6fa1 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -32,7 +32,8 @@ public: */ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { SharedMemory* shared_memory = new SharedMemory; - handle = Kernel::g_handle_table.Create(shared_memory); + // TOOD(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE); shared_memory->name = name; return shared_memory; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 2739bdd52..872df2d14 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -341,7 +341,8 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio Thread* thread = new Thread; - handle = Kernel::g_handle_table.Create(thread); + // TOOD(yuriks): Fix error reporting + handle = Kernel::g_handle_table.Create(thread).ValueOr(INVALID_HANDLE); thread_queue.push_back(handle); thread_ready_queue.prepare(priority); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9396b6b26..0e1397cd9 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -77,9 +77,6 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address); /// Arbitrate all threads currently waiting... void ArbitrateAllThreads(u32 arbiter, u32 address); -/// Gets the current thread -Thread* GetCurrentThread(); - /// Gets the current thread handle Handle GetCurrentThreadHandle(); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 5746b58e5..487bf3aa7 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -133,7 +133,7 @@ public: case FileCommand::Close: { LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_handle_table.Destroy<File>(GetHandle()); + backend->Close(); break; } @@ -189,7 +189,7 @@ public: case DirectoryCommand::Close: { LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_handle_table.Destroy<Directory>(GetHandle()); + backend->Close(); break; } @@ -283,7 +283,8 @@ ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSy } auto file = Common::make_unique<File>(std::move(backend), path); - Handle handle = Kernel::g_handle_table.Create(file.release()); + // TOOD(yuriks): Fix error reporting + Handle handle = Kernel::g_handle_table.Create(file.release()).ValueOr(INVALID_HANDLE); return MakeResult<Handle>(handle); } @@ -388,7 +389,8 @@ ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const F } auto directory = Common::make_unique<Directory>(std::move(backend), path); - Handle handle = Kernel::g_handle_table.Create(directory.release()); + // TOOD(yuriks): Fix error reporting + Handle handle = Kernel::g_handle_table.Create(directory.release()).ValueOr(INVALID_HANDLE); return MakeResult<Handle>(handle); } diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e9a7973b3..0f3cc2aa8 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -56,7 +56,8 @@ Manager::~Manager() { /// Add a service to the manager (does not create it though) void Manager::AddService(Interface* service) { - m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service); + // TOOD(yuriks): Fix error reporting + m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service).ValueOr(INVALID_HANDLE); m_services.push_back(service); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 9d5828fd0..28b4ccd17 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -54,7 +54,8 @@ public: /// Allocates a new handle for the service Handle CreateHandle(Kernel::Object *obj) { - Handle handle = Kernel::g_handle_table.Create(obj); + // TODO(yuriks): Fix error reporting + Handle handle = Kernel::g_handle_table.Create(obj).ValueOr(INVALID_HANDLE); m_handles.push_back(handle); return handle; } @@ -62,7 +63,7 @@ public: /// Frees a handle from the service template <class T> void DeleteHandle(const Handle handle) { - Kernel::g_handle_table.Destroy<T>(handle); + Kernel::g_handle_table.Close(handle); m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); } diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index a48ac09a3..25944fc68 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -119,11 +119,9 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) { // TODO(bunnei): Do something with nano_seconds, currently ignoring this bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated - if (!Kernel::g_handle_table.IsValid(handle)) { + Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handle); + if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - } - Kernel::Object* object = Kernel::g_handle_table.GetFast<Kernel::Object>(handle); - _dbg_assert_(Kernel, object != nullptr); LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); @@ -150,10 +148,9 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, // Iterate through each handle, synchronize kernel object for (s32 i = 0; i < handle_count; i++) { - if (!Kernel::g_handle_table.IsValid(handles[i])) { + Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handles[i]); + if (object == nullptr) return InvalidHandle(ErrorModule::Kernel).raw; - } - Kernel::Object* object = Kernel::g_handle_table.GetFast<Kernel::Object>(handles[i]); LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), object->GetName().c_str()); @@ -321,19 +318,12 @@ static Result CreateEvent(Handle* evt, u32 reset_type) { /// Duplicates a kernel handle static Result DuplicateHandle(Handle* out, Handle handle) { - LOG_WARNING(Kernel_SVC, "(STUBBED) called handle=0x%08X", handle); - - // Translate kernel handles -> real handles - if (handle == Kernel::CurrentThread) { - handle = Kernel::GetCurrentThreadHandle(); + ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle); + if (out_h.Succeeded()) { + *out = *out_h; + LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out); } - _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), - "(UNIMPLEMENTED) process handle duplication!"); - - // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate. - *out = handle; - - return 0; + return out_h.Code().raw; } /// Signals an event |