diff options
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r-- | src/core/hle/kernel/address_arbiter.cpp | 15 | ||||
-rw-r--r-- | src/core/hle/kernel/address_arbiter.h | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/archive.cpp | 229 | ||||
-rw-r--r-- | src/core/hle/kernel/archive.h | 41 | ||||
-rw-r--r-- | src/core/hle/kernel/event.cpp | 47 | ||||
-rw-r--r-- | src/core/hle/kernel/event.h | 14 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.h | 54 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.cpp | 52 | ||||
-rw-r--r-- | src/core/hle/kernel/mutex.h | 5 | ||||
-rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 45 | ||||
-rw-r--r-- | src/core/hle/kernel/shared_memory.h | 7 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 154 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.h | 9 |
14 files changed, 321 insertions, 361 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 2b21657d..db571b89 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -25,22 +25,17 @@ public: std::string name; ///< Name of address arbiter object (optional) - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::OS); } }; //////////////////////////////////////////////////////////////////////////////////////////////////// /// Arbitrate an address -Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { +ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { switch (type) { // Signal thread(s) waiting for arbitrate address... @@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va default: ERROR_LOG(KERNEL, "unknown type=%d", type); - return -1; + return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); } - return 0; + return RESULT_SUCCESS; } /// Create an address arbiter diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index a483fe46..8a5fb10b 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -11,7 +11,7 @@ // Address arbiters are an underlying kernel synchronization object that can be created/used via // supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR // applications use them as an underlying mechanism to implement thread-safe barriers, events, and -// semphores. +// semphores. //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -28,7 +28,7 @@ enum class ArbitrationType : u32 { }; /// Arbitrate an address -Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); +ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); /// Create an address arbiter Handle CreateAddressArbiter(const std::string& name = "Unknown"); diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 764082d7..e273444c 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp @@ -9,8 +9,9 @@ #include "core/file_sys/archive.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/directory.h" -#include "core/hle/service/service.h" #include "core/hle/kernel/archive.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -51,15 +52,10 @@ public: std::string name; ///< Name of archive (optional) FileSys::Archive* backend; ///< Archive backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); - + switch (cmd) { // Read from archive... case FileCommand::Read: @@ -99,7 +95,6 @@ public: case FileCommand::Close: { DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_object_pool.Destroy<Archive>(GetHandle()); CloseArchive(backend->GetIdCode()); break; } @@ -107,42 +102,32 @@ public: default: { ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - return -1; + return UnimplementedFunction(ErrorModule::FS); } } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class File : public Object { public: std::string GetTypeName() const override { return "File"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } Kernel::HandleType GetHandleType() const override { return HandleType::File; } - std::string path; ///< Path of the file + FileSys::Path path; ///< Path of the file std::unique_ptr<FileSys::File> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); switch (cmd) { @@ -184,7 +169,8 @@ public: case FileCommand::SetSize: { u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); + DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", + GetTypeName().c_str(), GetName().c_str(), size); backend->SetSize(size); break; } @@ -199,42 +185,33 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; class Directory : public Object { public: std::string GetTypeName() const override { return "Directory"; } - std::string GetName() const override { return path; } + std::string GetName() const override { return path.DebugStr(); } static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } - std::string path; ///< Path of the directory + FileSys::Path path; ///< Path of the directory std::unique_ptr<FileSys::Directory> backend; ///< File backend interface - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { u32* cmd_buff = Service::GetCommandBuffer(); DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); switch (cmd) { @@ -244,8 +221,9 @@ public: { u32 count = cmd_buff[1]; u32 address = cmd_buff[3]; - FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); - DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); + auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); + DEBUG_LOG(KERNEL, "Read %s %s: count=%d", + GetTypeName().c_str(), GetName().c_str(), count); // Number of entries actually read cmd_buff[2] = backend->Read(count, entries); @@ -262,22 +240,18 @@ public: // Unknown command... default: ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); - cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. - return -1; + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; } cmd_buff[1] = 0; // No error - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::FS); } }; @@ -285,108 +259,124 @@ public: std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode -/** - * Opens an archive - * @param id_code IdCode of the archive to open - * @return Handle to archive if it exists, otherwise a null handle (0) - */ -Handle OpenArchive(FileSys::Archive::IdCode id_code) { +ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) { auto itr = g_archive_map.find(id_code); if (itr == g_archive_map.end()) { - return 0; + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); } - return itr->second; + + return MakeResult<Handle>(itr->second); } -/** - * Closes an archive - * @param id_code IdCode of the archive to open - * @return Result of operation, 0 on success, otherwise error code - */ -Result CloseArchive(FileSys::Archive::IdCode id_code) { - if (1 != g_archive_map.erase(id_code)) { - ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); - return -1; +ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { + auto itr = g_archive_map.find(id_code); + if (itr == g_archive_map.end()) { + ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code); + return InvalidHandle(ErrorModule::FS); } INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); - return 0; + return RESULT_SUCCESS; } /** * Mounts an archive * @param archive Pointer to the archive to mount - * @return Result of operation, 0 on success, otherwise error code */ -Result MountArchive(Archive* archive) { +ResultCode MountArchive(Archive* archive) { FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); - if (0 != OpenArchive(id_code)) { + ResultVal<Handle> archive_handle = OpenArchive(id_code); + if (archive_handle.Succeeded()) { ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); - return -1; + return archive_handle.Code(); } g_archive_map[id_code] = archive->GetHandle(); INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); - return 0; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param handle Handle to newly created archive object - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Newly created Archive object - */ -Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) { +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { Archive* archive = new Archive; - handle = Kernel::g_object_pool.Create(archive); + Handle handle = Kernel::g_object_pool.Create(archive); archive->name = name; archive->backend = backend; - MountArchive(archive); + ResultCode result = MountArchive(archive); + if (result.IsError()) { + return result; + } - return archive; + return RESULT_SUCCESS; } -/** - * Creates an Archive - * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Handle to newly created Archive object - */ -Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { - Handle handle; - CreateArchive(handle, backend, name); - return handle; -} +ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { + // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create + // the archive file handles at app loading, and then keep them persistent throughout execution. + // Archives file handles are just reused and not actually freed until emulation shut down. + // Verify if real hardware works this way, or if new handles are created each time + if (path.GetType() == FileSys::Binary) + // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend + // design. While the functionally of this is OK, our implementation decision to separate + // normal files from archive file pointers is very likely wrong. + // See https://github.com/citra-emu/citra/issues/205 + return MakeResult<Handle>(archive_handle); -/** - * Open a File from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @param mode Mode under which to open the File - * @return Opened File object - */ -Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { File* file = new File; Handle handle = Kernel::g_object_pool.Create(file); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } file->path = path; file->backend = archive->backend->OpenFile(path, mode); - if (!file->backend) + if (!file->backend) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult<Handle>(handle); +} + +/** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteFile(path)) return 0; + return -1; +} - return handle; +/** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->DeleteDirectory(path)) + return 0; + return -1; } /** * Create a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Opened Directory object + * @return Whether creation succeeded */ -Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { +Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); if (archive == nullptr) return -1; @@ -401,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ -Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { +ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { Directory* directory = new Directory; Handle handle = Kernel::g_object_pool.Create(directory); - Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } directory->path = path; directory->backend = archive->backend->OpenDirectory(path); - return handle; + return MakeResult<Handle>(handle); } /// Initialize archives diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 0230996b..6fc4f0f2 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h @@ -6,8 +6,9 @@ #include "common/common_types.h" -#include "core/hle/kernel/kernel.h" #include "core/file_sys/archive.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Kernel namespace @@ -17,33 +18,47 @@ namespace Kernel { /** * Opens an archive * @param id_code IdCode of the archive to open - * @return Handle to archive if it exists, otherwise a null handle (0) + * @return Handle to the opened archive */ -Handle OpenArchive(FileSys::Archive::IdCode id_code); +ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code); /** * Closes an archive * @param id_code IdCode of the archive to open - * @return true if it worked fine */ -Result CloseArchive(FileSys::Archive::IdCode id_code); +ResultCode CloseArchive(FileSys::Archive::IdCode id_code); /** * Creates an Archive * @param backend File system backend interface to the archive - * @param name Optional name of Archive - * @return Handle to newly created Archive object + * @param name Name of Archive */ -Handle CreateArchive(FileSys::Archive* backend, const std::string& name); +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); /** * Open a File from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the File inside of the Archive * @param mode Mode under which to open the File - * @return Opened File object + * @return Handle to the opened File object + */ +ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); + +/** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ +Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); + +/** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded */ -Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); +Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /** * Create a Directory from an Archive @@ -51,15 +66,15 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const * @param path Path to the Directory inside of the Archive * @return Whether creation of directory succeeded */ -Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); +Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /** * Open a Directory from an Archive * @param archive_handle Handle to an open Archive object * @param path Path to the Directory inside of the Archive - * @return Opened Directory object + * @return Handle to the opened File object */ -Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); +ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 45ed79be..28808020 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <map> #include <algorithm> @@ -30,13 +30,8 @@ public: std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event std::string name; ///< Name of event (optional) - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { - *wait = locked; + ResultVal<bool> WaitSynchronization() override { + bool wait = locked; if (locked) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { @@ -47,7 +42,7 @@ public: if (reset_type != RESETTYPE_STICKY && !permanent_locked) { locked = true; } - return 0; + return MakeResult<bool>(wait); } }; @@ -57,12 +52,12 @@ public: * @param permanent_locked Boolean permanent locked value to set event * @return Result of operation, 0 on success, otherwise error code */ -Result SetPermanentLock(Handle handle, const bool permanent_locked) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); evt->permanent_locked = permanent_locked; - return 0; + return RESULT_SUCCESS; } /** @@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) { * @param locked Boolean locked value to set event * @return Result of operation, 0 on success, otherwise error code */ -Result SetEventLocked(const Handle handle, const bool locked) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SetEventLocked(const Handle handle, const bool locked) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!evt->permanent_locked) { evt->locked = locked; } - return 0; + return RESULT_SUCCESS; } /** @@ -86,16 +81,16 @@ Result SetEventLocked(const Handle handle, const bool locked) { * @param handle Handle to event to signal * @return Result of operation, 0 on success, otherwise error code */ -Result SignalEvent(const Handle handle) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode SignalEvent(const Handle handle) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); // Resume threads waiting for event to signal bool event_caught = false; for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { ResumeThreadFromWait( evt->waiting_threads[i]); - // If any thread is signalled awake by this event, assume the event was "caught" and reset + // If any thread is signalled awake by this event, assume the event was "caught" and reset // the event. This will result in the next thread waiting on the event to block. Otherwise, // the event will not be reset, and the next thread to call WaitSynchronization on it will // not block. Not sure if this is correct behavior, but it seems to work. @@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) { if (!evt->permanent_locked) { evt->locked = event_caught; } - return 0; + return RESULT_SUCCESS; } /** @@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) { * @param handle Handle to event to clear * @return Result of operation, 0 on success, otherwise error code */ -Result ClearEvent(Handle handle) { - Event* evt = g_object_pool.GetFast<Event>(handle); - _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); +ResultCode ClearEvent(Handle handle) { + Event* evt = g_object_pool.Get<Event>(handle); + if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!evt->permanent_locked) { evt->locked = true; } - return 0; + return RESULT_SUCCESS; } /** diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index c39b3318..73aec4e7 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -15,31 +15,27 @@ namespace Kernel { * Changes whether an event is locked or not * @param handle Handle to event to change * @param locked Boolean locked value to set event - * @return Result of operation, 0 on success, otherwise error code */ -Result SetEventLocked(const Handle handle, const bool locked); +ResultCode SetEventLocked(const Handle handle, const bool locked); /** * Hackish function to set an events permanent lock state, used to pass through synch blocks * @param handle Handle to event to change * @param permanent_locked Boolean permanent locked value to set event - * @return Result of operation, 0 on success, otherwise error code */ -Result SetPermanentLock(Handle handle, const bool permanent_locked); +ResultCode SetPermanentLock(Handle handle, const bool permanent_locked); /** * Signals an event * @param handle Handle to event to signal - * @return Result of operation, 0 on success, otherwise error code */ -Result SignalEvent(const Handle handle); +ResultCode SignalEvent(const Handle handle); /** * Clears an event * @param handle Handle to event to clear - * @return Result of operation, 0 on success, otherwise error code */ -Result ClearEvent(Handle handle); +ResultCode ClearEvent(Handle handle); /** * Creates an event diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 88cbc1af..018000ab 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "common/common.h" @@ -68,7 +68,7 @@ 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(), + INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), pool[i]->GetName().c_str()); } } @@ -110,7 +110,7 @@ void Shutdown() { */ 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 diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 867d1b89..8d3937ce 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -1,12 +1,13 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once #include <array> #include <string> #include "common/common.h" +#include "core/hle/result.h" typedef u32 Handle; typedef s32 Result; @@ -34,7 +35,7 @@ enum class HandleType : u32 { Archive = 12, Directory = 13, }; - + enum { DEFAULT_STACK_SIZE = 0x4000, }; @@ -52,21 +53,19 @@ public: virtual Kernel::HandleType GetHandleType() const = 0; /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code + * Synchronize kernel object. + * @return True if the current thread should wait as a result of the sync */ - virtual Result SyncRequest(bool* wait) { + virtual ResultVal<bool> SyncRequest() { ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); - return -1; + return UnimplementedFunction(ErrorModule::Kernel); } /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code + * Wait for kernel object to synchronize. + * @return True if the current thread should wait as a result of the wait */ - virtual Result WaitSynchronization(bool* wait) = 0; + virtual ResultVal<bool> WaitSynchronization() = 0; }; class ObjectPool : NonCopyable { @@ -80,38 +79,29 @@ public: static Object* CreateByIDType(int type); template <class T> - u32 Destroy(Handle handle) { - u32 error; - if (Get<T>(handle, error)) { + void Destroy(Handle handle) { + if (Get<T>(handle)) { occupied[handle - HANDLE_OFFSET] = false; delete pool[handle - HANDLE_OFFSET]; } - return error; - }; + } bool IsValid(Handle handle); template <class T> - T* Get(Handle handle, u32& outError) { + T* Get(Handle handle) { if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { - // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP - if (handle != 0 && (u32)handle != 0x80020001) { + if (handle != 0) { WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); } - outError = 0;//T::GetMissingErrorCode(); - return 0; + return nullptr; } else { - // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, - // it just acted as a static case and everything worked. This means that we will never - // see the Wrong type object error below, but we'll just have to live with that danger. - T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]); - if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) { + Object* t = pool[handle - HANDLE_OFFSET]; + if (t->GetHandleType() != T::GetStaticHandleType()) { WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); - outError = 0;//T::GetMissingErrorCode(); - return 0; + return nullptr; } - outError = 0;//SCE_KERNEL_ERROR_OK; - return t; + return static_cast<T*>(t); } } @@ -139,7 +129,7 @@ public: } bool GetIDType(Handle handle, HandleType* type) const { - if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || + if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || !occupied[handle - HANDLE_OFFSET]) { ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); return false; @@ -155,7 +145,7 @@ public: int GetCount(); private: - + enum { MAX_COUNT = 0x1000, HANDLE_OFFSET = 0x100, diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index fcfd061a..d07e9761 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <map> #include <vector> @@ -27,31 +27,20 @@ public: std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex std::string name; ///< Name of mutex (optional) - /** - * Synchronize kernel object - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result SyncRequest(bool* wait) override { + ResultVal<bool> SyncRequest() override { // TODO(bunnei): ImplementMe locked = true; - return 0; + return MakeResult<bool>(false); } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe - *wait = locked; - + bool wait = locked; if (locked) { Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); } - return 0; + return MakeResult<bool>(wait); } }; @@ -99,35 +88,36 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) { bool ReleaseMutex(Mutex* mutex) { MutexEraseLock(mutex); - bool woke_threads = false; // Find the next waiting thread for the mutex... - while (!woke_threads && !mutex->waiting_threads.empty()) { + while (!mutex->waiting_threads.empty()) { std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); - woke_threads |= ReleaseMutexForThread(mutex, *iter); + ReleaseMutexForThread(mutex, *iter); mutex->waiting_threads.erase(iter); } + // Reset mutex lock thread handle, nothing is waiting - if (!woke_threads) { - mutex->locked = false; - mutex->lock_thread = -1; - } - return woke_threads; + mutex->locked = false; + mutex->lock_thread = -1; + + return true; } /** * Releases a mutex * @param handle Handle to mutex to release */ -Result ReleaseMutex(Handle handle) { - Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); - - _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!"); +ResultCode ReleaseMutex(Handle handle) { + Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle); + if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); if (!ReleaseMutex(mutex)) { - return -1; + // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure + // what error condition this is supposed to be signaling. + return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel, + ErrorSummary::NothingHappened, ErrorLevel::Temporary); } - return 0; + return RESULT_SUCCESS; } /** diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 7d7b5137..155449f9 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -13,9 +13,8 @@ namespace Kernel { /** * Releases a mutex * @param handle Handle to mutex to release - * @return Result of operation, 0 on success, otherwise error code */ -Result ReleaseMutex(Handle handle); +ResultCode ReleaseMutex(Handle handle); /** * Creates a mutex diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index f538c655..cfcc0e0b 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include "common/common.h" @@ -16,15 +16,10 @@ public: static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { + ResultVal<bool> WaitSynchronization() override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); - return 0; + return UnimplementedFunction(ErrorModule::OS); } u32 base_address; ///< Address of shared memory block in RAM @@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { return shared_memory; } -/** - * Creates a shared memory object - * @param name Optional name of shared memory object - * @return Handle of newly created shared memory object - */ Handle CreateSharedMemory(const std::string& name) { Handle handle; CreateSharedMemory(handle, name); @@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) { * @param other_permissions Memory block map other permissions (specified by SVC field) * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, +ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, MemoryPermission other_permissions) { if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", handle, address); - return -1; + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, + ErrorSummary::InvalidArgument, ErrorLevel::Permanent); } - SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); - _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); + SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); + if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); shared_memory->base_address = address; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; - return 0; + return RESULT_SUCCESS; } -/** - * Gets a pointer to the shared memory block - * @param handle Shared memory block handle - * @param offset Offset from the start of the shared memory block to get pointer - * @return Pointer to the shared memory block from the specified offset - */ -u8* GetSharedMemoryPointer(Handle handle, u32 offset) { - SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); - _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); +ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { + SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); + if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); if (0 != shared_memory->base_address) - return Memory::GetPointer(shared_memory->base_address + offset); + return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); - return nullptr; + // TODO(yuriks): Verify error code. + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, + ErrorSummary::InvalidState, ErrorLevel::Permanent); } } // namespace diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 5312b885..304cf5b6 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once @@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown"); * @param address Address in system memory to map shared memory block to * @param permissions Memory block map permissions (specified by SVC field) * @param other_permissions Memory block map other permissions (specified by SVC field) - * @return Result of operation, 0 on success, otherwise error code */ -Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, +ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions, MemoryPermission other_permissions); /** @@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, * @param offset Offset from the start of the shared memory block to get pointer * @return Pointer to the shared memory block from the specified offset */ -u8* GetSharedMemoryPointer(Handle handle, u32 offset); +ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset); } // namespace diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e15590c4..f5979590 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #include <algorithm> #include <list> @@ -11,10 +11,11 @@ #include "common/thread_queue_list.h" #include "core/core.h" -#include "core/mem_map.h" #include "core/hle/hle.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" +#include "core/hle/result.h" +#include "core/mem_map.h" namespace Kernel { @@ -33,21 +34,17 @@ public: inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } - /** - * Wait for kernel object to synchronize - * @param wait Boolean wait set if current thread should wait as a result of sync operation - * @return Result of operation, 0 on success, otherwise error code - */ - Result WaitSynchronization(bool* wait) override { - if (status != THREADSTATUS_DORMANT) { + ResultVal<bool> WaitSynchronization() override { + const bool wait = status != THREADSTATUS_DORMANT; + if (wait) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { waiting_threads.push_back(thread); } WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); - *wait = true; } - return 0; + + return MakeResult<bool>(wait); } ThreadContext context; @@ -71,17 +68,17 @@ public: }; // Lists all thread ids that aren't deleted/etc. -std::vector<Handle> g_thread_queue; +static std::vector<Handle> thread_queue; // Lists only ready thread ids. -Common::ThreadQueueList<Handle> g_thread_ready_queue; +static Common::ThreadQueueList<Handle> thread_ready_queue; -Handle g_current_thread_handle; -Thread* g_current_thread; +static Handle current_thread_handle; +static Thread* current_thread; /// Gets the current thread inline Thread* GetCurrentThread() { - return g_current_thread; + return current_thread; } /// Gets the current thread handle @@ -91,8 +88,8 @@ Handle GetCurrentThreadHandle() { /// Sets the current thread inline void SetCurrentThread(Thread* t) { - g_current_thread = t; - g_current_thread_handle = t->GetHandle(); + current_thread = t; + current_thread_handle = t->GetHandle(); } /// Saves the current CPU context @@ -113,7 +110,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) { t->context.pc = t->context.reg_15 = t->entry_point; t->context.sp = t->stack_top; t->context.cpsr = 0x1F; // Usermode - + // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be // agnostic of the CPU core. @@ -131,40 +128,35 @@ void ChangeReadyState(Thread* t, bool ready) { Handle handle = t->GetHandle(); if (t->IsReady()) { if (!ready) { - g_thread_ready_queue.remove(t->current_priority, handle); + thread_ready_queue.remove(t->current_priority, handle); } } else if (ready) { if (t->IsRunning()) { - g_thread_ready_queue.push_front(t->current_priority, handle); + thread_ready_queue.push_front(t->current_priority, handle); } else { - g_thread_ready_queue.push_back(t->current_priority, handle); + thread_ready_queue.push_back(t->current_priority, handle); } t->status = THREADSTATUS_READY; } } /// Verify that a thread has not been released from waiting -inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - - if (type != thread->wait_type || wait_handle != thread->wait_handle) - return false; - - return true; +inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { + _dbg_assert_(KERNEL, thread != nullptr); + return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting()); } /// Stops the current thread -void StopThread(Handle handle, const char* reason) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - +ResultCode StopThread(Handle handle, const char* reason) { + Thread* thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); + ChangeReadyState(thread, false); thread->status = THREADSTATUS_DORMANT; - for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { - const Handle waiting_thread = thread->waiting_threads[i]; + for (Handle waiting_handle : thread->waiting_threads) { + Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { - ResumeThreadFromWait(waiting_thread); + ResumeThreadFromWait(waiting_handle); } } thread->waiting_threads.clear(); @@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) { // Stopped threads are never waiting. thread->wait_type = WAITTYPE_NONE; thread->wait_handle = 0; + + return RESULT_SUCCESS; } /// Changes a threads state @@ -181,7 +175,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) { } ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); t->status = new_status; - + if (new_status == THREADSTATUS_WAIT) { if (t->wait_type == WAITTYPE_NONE) { ERROR_LOG(KERNEL, "Waittype none not allowed"); @@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { s32 priority = THREADPRIO_LOWEST; // Iterate through threads, find highest priority thread that is waiting to be arbitrated... - for (const auto& handle : g_thread_queue) { + for (Handle handle : thread_queue) { + Thread* thread = g_object_pool.Get<Thread>(handle); // TODO(bunnei): Verify arbiter address... - if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) + if (!VerifyWait(thread, WAITTYPE_ARB, arbiter)) continue; - Thread* thread = g_object_pool.GetFast<Thread>(handle); + if (thread == nullptr) + continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. if(thread->current_priority <= priority) { highest_priority_thread = handle; priority = thread->current_priority; @@ -216,12 +212,13 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) { /// Arbitrate all threads currently waiting void ArbitrateAllThreads(u32 arbiter, u32 address) { - + // Iterate through threads, find highest priority thread that is waiting to be arbitrated... - for (const auto& handle : g_thread_queue) { + for (Handle handle : thread_queue) { + Thread* thread = g_object_pool.Get<Thread>(handle); // TODO(bunnei): Verify arbiter address... - if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) + if (VerifyWait(thread, WAITTYPE_ARB, arbiter)) ResumeThreadFromWait(handle); } } @@ -238,11 +235,11 @@ void CallThread(Thread* t) { /// Switches CPU context to that of the specified thread void SwitchContext(Thread* t) { Thread* cur = GetCurrentThread(); - + // Save context for current thread if (cur) { SaveContext(cur->context); - + if (cur->IsRunning()) { ChangeReadyState(cur, true); } @@ -263,16 +260,16 @@ void SwitchContext(Thread* t) { Thread* NextThread() { Handle next; Thread* cur = GetCurrentThread(); - + if (cur && cur->IsRunning()) { - next = g_thread_ready_queue.pop_first_better(cur->current_priority); + next = thread_ready_queue.pop_first_better(cur->current_priority); } else { - next = g_thread_ready_queue.pop_first(); + next = thread_ready_queue.pop_first(); } if (next == 0) { return nullptr; } - return Kernel::g_object_pool.GetFast<Thread>(next); + return Kernel::g_object_pool.Get<Thread>(next); } /** @@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle) { - u32 error; - Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error); + Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); if (thread) { thread->status &= ~THREADSTATUS_WAIT; if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { @@ -306,9 +302,9 @@ void DebugThreadQueue() { return; } INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); - for (u32 i = 0; i < g_thread_queue.size(); i++) { - Handle handle = g_thread_queue[i]; - s32 priority = g_thread_ready_queue.contains(handle); + for (u32 i = 0; i < thread_queue.size(); i++) { + Handle handle = thread_queue[i]; + s32 priority = thread_ready_queue.contains(handle); if (priority != -1) { INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); } @@ -319,15 +315,15 @@ void DebugThreadQueue() { Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size) { - _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), + _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), "CreateThread priority=%d, outside of allowable range!", priority) Thread* thread = new Thread; handle = Kernel::g_object_pool.Create(thread); - g_thread_queue.push_back(handle); - g_thread_ready_queue.prepare(priority); + thread_queue.push_back(handle); + thread_ready_queue.prepare(priority); thread->status = THREADSTATUS_DORMANT; thread->entry_point = entry_point; @@ -351,7 +347,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 return -1; } if ((u32)stack_size < 0x200) { - ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, + ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, stack_size); return -1; } @@ -368,7 +364,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 return -1; } Handle handle; - Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, + Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, stack_size); ResetThread(thread, arg, 0); @@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3 } /// Get the priority of the thread specified by handle -u32 GetThreadPriority(const Handle handle) { - Thread* thread = g_object_pool.GetFast<Thread>(handle); - _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); - return thread->current_priority; +ResultVal<u32> GetThreadPriority(const Handle handle) { + Thread* thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); + + return MakeResult<u32>(thread->current_priority); } /// Set the priority of the thread specified by handle -Result SetThreadPriority(Handle handle, s32 priority) { +ResultCode SetThreadPriority(Handle handle, s32 priority) { Thread* thread = nullptr; if (!handle) { thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? } else { - thread = g_object_pool.GetFast<Thread>(handle); + thread = g_object_pool.Get<Thread>(handle); + if (thread == nullptr) { + return InvalidHandle(ErrorModule::Kernel); + } } _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); @@ -405,37 +405,37 @@ Result SetThreadPriority(Handle handle, s32 priority) { // Change thread priority s32 old = thread->current_priority; - g_thread_ready_queue.remove(old, handle); + thread_ready_queue.remove(old, handle); thread->current_priority = priority; - g_thread_ready_queue.prepare(thread->current_priority); + thread_ready_queue.prepare(thread->current_priority); // Change thread status to "ready" and push to ready queue if (thread->IsRunning()) { thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; } if (thread->IsReady()) { - g_thread_ready_queue.push_back(thread->current_priority, handle); + thread_ready_queue.push_back(thread->current_priority, handle); } - return 0; + return RESULT_SUCCESS; } /// Sets up the primary application thread Handle SetupMainThread(s32 priority, int stack_size) { Handle handle; - + // Initialize new "main" thread - Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, + Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); - + ResetThread(thread, 0, 0); - + // If running another thread already, set it to "ready" state Thread* cur = GetCurrentThread(); if (cur && cur->IsRunning()) { ChangeReadyState(cur, true); } - + // Run new "main" thread SetCurrentThread(thread); thread->status = THREADSTATUS_RUNNING; @@ -452,12 +452,12 @@ void Reschedule() { HLE::g_reschedule = false; if (next > 0) { INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); - + SwitchContext(next); // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. - // This results in the current thread yielding on a VBLANK once, and then it will be + // This results in the current thread yielding on a VBLANK once, and then it will be // immediately placed back in the queue for execution. if (prev->wait_type == WAITTYPE_VBLANK) { ResumeThreadFromWait(prev->GetHandle()); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 39fa38b7..ce63a70d 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -1,11 +1,12 @@ // Copyright 2014 Citra Emulator Project / PPSSPP Project // Licensed under GPLv2 -// Refer to the license.txt file included. +// Refer to the license.txt file included. #pragma once #include "common/common_types.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" enum ThreadPriority { THREADPRIO_HIGHEST = 0, ///< Highest thread priority @@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE); void Reschedule(); /// Stops the current thread -void StopThread(Handle thread, const char* reason); +ResultCode StopThread(Handle thread, const char* reason); /// Resumes a thread from waiting by marking it as "ready" void ResumeThreadFromWait(Handle handle); @@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa void WaitThread_Synchronization(); /// Get the priority of the thread specified by handle -u32 GetThreadPriority(const Handle handle); +ResultVal<u32> GetThreadPriority(const Handle handle); /// Set the priority of the thread specified by handle -Result SetThreadPriority(Handle handle, s32 priority); +ResultCode SetThreadPriority(Handle handle, s32 priority); /// Initialize threading void ThreadingInit(); |