From 266db1336d5e3d3a7790fae5e7096f19b978c393 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 13 May 2016 17:01:48 +0300 Subject: [PATCH] The rest --- Utilities/Atomic.h | 17 +- Utilities/AutoPause.h | 2 + Utilities/Config.cpp | 2 +- Utilities/Config.h | 4 +- Utilities/File.cpp | 350 +++----- Utilities/File.h | 30 +- Utilities/GSL.h | 8 +- Utilities/Log.cpp | 18 +- Utilities/Log.h | 36 +- Utilities/Macro.h | 15 +- Utilities/Semaphore.h | 2 +- Utilities/SharedMutex.cpp | 28 + Utilities/SharedMutex.h | 67 +- Utilities/SleepQueue.h | 20 +- Utilities/StrFmt.cpp | 1 + Utilities/StrFmt.h | 5 +- Utilities/Thread.cpp | 177 +++- Utilities/Thread.h | 261 ++++-- Utilities/VirtualMemory.cpp | 12 +- Utilities/lockless.h | 105 +++ Utilities/sync.h | 192 +++++ Utilities/types.h | 12 +- rpcs3/CMakeLists.txt | 2 +- rpcs3/Emu/Audio/AudioDumper.cpp | 2 +- rpcs3/Emu/CPU/CPUThread.cpp | 46 +- rpcs3/Emu/CPU/CPUThread.h | 63 +- rpcs3/Emu/IPC.h | 88 ++ rpcs3/Emu/IdManager.cpp | 9 +- rpcs3/Emu/IdManager.h | 179 ++-- rpcs3/Emu/Memory/Memory.cpp | 4 +- rpcs3/Emu/Memory/vm.cpp | 75 +- rpcs3/Emu/Memory/vm.h | 45 +- rpcs3/Emu/Memory/vm_ptr.h | 92 +- rpcs3/Emu/Memory/vm_ref.h | 9 +- rpcs3/Emu/Memory/vm_var.h | 12 +- rpcs3/Emu/Memory/wait_engine.cpp | 141 ++- rpcs3/Emu/Memory/wait_engine.h | 67 +- rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp | 10 +- rpcs3/Emu/RSX/CgBinaryProgram.h | 2 +- rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp | 6 +- rpcs3/Emu/RSX/Common/BufferUtils.cpp | 16 +- .../RSX/Common/FragmentProgramDecompiler.cpp | 20 +- rpcs3/Emu/RSX/Common/ProgramStateCache.h | 2 +- rpcs3/Emu/RSX/Common/ShaderParam.h | 2 +- rpcs3/Emu/RSX/Common/TextureUtils.cpp | 2 +- .../RSX/Common/VertexProgramDecompiler.cpp | 2 + rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp | 6 +- rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp | 2 +- .../D3D12/D3D12FragmentProgramDecompiler.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp | 10 +- rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h | 1 + rpcs3/Emu/RSX/D3D12/D3D12Overlay.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp | 2 +- rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp | 2 +- .../D3D12/D3D12VertexProgramDecompiler.cpp | 2 +- rpcs3/Emu/RSX/GL/GLVertexProgram.cpp | 2 + rpcs3/Emu/RSX/RSXThread.cpp | 8 +- rpcs3/Emu/RSX/RSXThread.h | 16 +- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 2 +- rpcs3/Emu/RSX/rsx_methods.cpp | 6 +- rpcs3/Emu/RSX/rsx_utils.h | 12 +- rpcs3/Emu/System.cpp | 60 +- rpcs3/Gui/ConLogFrame.cpp | 20 +- rpcs3/Gui/ConLogFrame.h | 4 +- rpcs3/Gui/GameViewer.cpp | 2 + rpcs3/Gui/InterpreterDisAsm.cpp | 18 +- rpcs3/Gui/KernelExplorer.cpp | 197 ++--- rpcs3/Gui/MainFrame.cpp | 2 + rpcs3/Gui/SettingsDialog.cpp | 1 + rpcs3/Loader/ELF.h | 73 +- rpcs3/Loader/PSF.cpp | 119 +-- rpcs3/Loader/PSF.h | 37 +- rpcs3/Loader/TROPUSR.cpp | 2 +- rpcs3/Loader/TRP.cpp | 2 +- rpcs3/emucore.vcxproj | 268 +++--- rpcs3/emucore.vcxproj.filters | 816 +++++++++--------- rpcs3/stdafx.h | 14 +- 81 files changed, 2247 insertions(+), 1731 deletions(-) create mode 100644 Utilities/lockless.h create mode 100644 Utilities/sync.h create mode 100644 rpcs3/Emu/IPC.h diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h index 6790d56400..4022164be4 100644 --- a/Utilities/Atomic.h +++ b/Utilities/Atomic.h @@ -1,6 +1,7 @@ #pragma once #include "types.h" +#include "Platform.h" // Helper class, provides access to compiler-specific atomic intrinsics template @@ -744,9 +745,9 @@ public: while (true) { - func(_new = old, args...); + func((_new = old), args...); - if (atomic_storage::compare_exchange(m_data, old, _new)) return old; + if (LIKELY(atomic_storage::compare_exchange(m_data, old, _new))) return old; } } @@ -765,9 +766,9 @@ public: while (true) { - func(_new = old, args...); + func((_new = old), args...); - if (atomic_storage::compare_exchange(m_data, old, _new)) return _new; + if (LIKELY(atomic_storage::compare_exchange(m_data, old, _new))) return _new; } } @@ -786,9 +787,9 @@ public: while (true) { - RT&& result = func(_new = old, args...); + RT&& result = func((_new = old), args...); - if (atomic_storage::compare_exchange(m_data, old, _new)) return std::move(result); + if (LIKELY(atomic_storage::compare_exchange(m_data, old, _new))) return std::move(result); } } @@ -800,9 +801,9 @@ public: while (true) { - func(_new = old, args...); + func((_new = old), args...); - if (atomic_storage::compare_exchange(m_data, old, _new)) return; + if (LIKELY(atomic_storage::compare_exchange(m_data, old, _new))) return; } } diff --git a/Utilities/AutoPause.h b/Utilities/AutoPause.h index 13a2f0c133..87f3ea48cc 100644 --- a/Utilities/AutoPause.h +++ b/Utilities/AutoPause.h @@ -1,5 +1,7 @@ #pragma once +#include + // Regarded as a Debugger Enchantment namespace debug { diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index e7368683c3..32330188ee 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -5,7 +5,7 @@ namespace cfg { - _log::channel cfg("CFG", _log::level::notice); + logs::channel cfg("CFG", logs::level::notice); entry_base::entry_base(type _type) : m_type(_type) diff --git a/Utilities/Config.h b/Utilities/Config.h index d9b0d76938..2463321e7c 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -179,7 +179,7 @@ namespace cfg for (const auto& v : init) { // Ensure elements are unique - ASSERT(map.emplace(v.first, v.second).second); + VERIFY(map.emplace(v.first, v.second).second); } return map; @@ -529,4 +529,4 @@ namespace cfg } // Registered log channel -#define LOG_CHANNEL(name) _log::channel name(#name, _log::level::notice); namespace _log { cfg::enum_entry<_log::level, true> name(cfg::root.log, #name, ::name.enabled); } +#define LOG_CHANNEL(name) extern logs::channel name; namespace logs { static cfg::enum_entry name(cfg::root.log, #name, ::name.enabled); } diff --git a/Utilities/File.cpp b/Utilities/File.cpp index ea24c4d26f..573b251b83 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -69,6 +69,19 @@ static time_t to_time(const FILETIME& ft) return to_time(v); } +static fs::error to_error(DWORD e) +{ + switch (e) + { + case ERROR_FILE_NOT_FOUND: return fs::error::noent; + case ERROR_PATH_NOT_FOUND: return fs::error::noent; + case ERROR_ALREADY_EXISTS: return fs::error::exist; + case ERROR_FILE_EXISTS: return fs::error::exist; + case ERROR_NEGATIVE_SEEK: return fs::error::inval; + default: throw fmt::exception("Unknown Win32 error: %u.", e); + } +} + #else #include @@ -87,11 +100,22 @@ static time_t to_time(const FILETIME& ft) #include #endif +static fs::error to_error(int e) +{ + switch (e) + { + case ENOENT: return fs::error::noent; + case EEXIST: return fs::error::exist; + case EINVAL: return fs::error::inval; + default: throw fmt::exception("Unknown system error: %d.", e); + } +} + #endif namespace fs { - thread_local uint error = 0; + thread_local error g_tls_error = error::ok; class device_manager final { @@ -146,7 +170,7 @@ std::shared_ptr fs::get_virtual_device(const std::string& path) std::shared_ptr fs::set_virtual_device(const std::string& name, const std::shared_ptr& device) { - Expects(name.size() > 2 && name[0] == '/' && name[1] == '/' && name.find('/', 2) == -1); + EXPECTS(name.size() > 2 && name[0] == '/' && name[1] == '/' && name.find('/', 2) == -1); return get_device_manager().set_device(name, device); } @@ -178,26 +202,26 @@ std::string fs::get_parent_dir(const std::string& path) static const auto test_get_parent_dir = []() -> bool { // Success: - ASSERT(fs::get_parent_dir("/x/y///") == "/x"); - ASSERT(fs::get_parent_dir("/x/y/") == "/x"); - ASSERT(fs::get_parent_dir("/x/y") == "/x"); - ASSERT(fs::get_parent_dir("x:/y") == "x:"); - ASSERT(fs::get_parent_dir("//x/y") == "//x"); + VERIFY(fs::get_parent_dir("/x/y///") == "/x"); + VERIFY(fs::get_parent_dir("/x/y/") == "/x"); + VERIFY(fs::get_parent_dir("/x/y") == "/x"); + VERIFY(fs::get_parent_dir("x:/y") == "x:"); + VERIFY(fs::get_parent_dir("//x/y") == "//x"); // Failure: - ASSERT(fs::get_parent_dir("").empty()); - ASSERT(fs::get_parent_dir("x/").empty()); - ASSERT(fs::get_parent_dir("x").empty()); - ASSERT(fs::get_parent_dir("x///").empty()); - ASSERT(fs::get_parent_dir("/x/").empty()); - ASSERT(fs::get_parent_dir("/x").empty()); - ASSERT(fs::get_parent_dir("/").empty()); - ASSERT(fs::get_parent_dir("//").empty()); - ASSERT(fs::get_parent_dir("//x").empty()); - ASSERT(fs::get_parent_dir("//x/").empty()); - ASSERT(fs::get_parent_dir("///").empty()); - ASSERT(fs::get_parent_dir("///x").empty()); - ASSERT(fs::get_parent_dir("///x/").empty()); + VERIFY(fs::get_parent_dir("").empty()); + VERIFY(fs::get_parent_dir("x/").empty()); + VERIFY(fs::get_parent_dir("x").empty()); + VERIFY(fs::get_parent_dir("x///").empty()); + VERIFY(fs::get_parent_dir("/x/").empty()); + VERIFY(fs::get_parent_dir("/x").empty()); + VERIFY(fs::get_parent_dir("/").empty()); + VERIFY(fs::get_parent_dir("//").empty()); + VERIFY(fs::get_parent_dir("//x").empty()); + VERIFY(fs::get_parent_dir("//x/").empty()); + VERIFY(fs::get_parent_dir("///").empty()); + VERIFY(fs::get_parent_dir("///x").empty()); + VERIFY(fs::get_parent_dir("///x/").empty()); return false; }(); @@ -213,14 +237,7 @@ bool fs::stat(const std::string& path, stat_t& info) WIN32_FILE_ATTRIBUTE_DATA attrs; if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs)) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -234,7 +251,7 @@ bool fs::stat(const std::string& path, stat_t& info) struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -260,14 +277,7 @@ bool fs::exists(const std::string& path) #ifdef _WIN32 if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -276,7 +286,7 @@ bool fs::exists(const std::string& path) struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -296,7 +306,7 @@ bool fs::is_file(const std::string& path) if (info.is_directory) { - fs::error = EEXIST; + g_tls_error = error::exist; return false; } @@ -307,21 +317,14 @@ bool fs::is_file(const std::string& path) const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } #else struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } #endif @@ -333,7 +336,7 @@ bool fs::is_file(const std::string& path) if (S_ISDIR(file_info.st_mode)) #endif { - fs::error = EEXIST; + g_tls_error = error::exist; return false; } @@ -352,7 +355,7 @@ bool fs::is_dir(const std::string& path) if (info.is_directory == false) { - fs::error = EEXIST; + g_tls_error = error::exist; return false; } @@ -363,21 +366,14 @@ bool fs::is_dir(const std::string& path) const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); if (attrs == INVALID_FILE_ATTRIBUTES) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } #else struct ::stat file_info; if (::stat(path.c_str(), &file_info) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } #endif @@ -388,7 +384,7 @@ bool fs::is_dir(const std::string& path) if (!S_ISDIR(file_info.st_mode)) #endif { - fs::error = EEXIST; + g_tls_error = error::exist; return false; } @@ -405,14 +401,7 @@ bool fs::create_dir(const std::string& path) #ifdef _WIN32 if (!CreateDirectoryW(to_wchar(path).get(), NULL)) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_ALREADY_EXISTS: fs::error = EEXIST; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -420,7 +409,7 @@ bool fs::create_dir(const std::string& path) #else if (::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -450,13 +439,7 @@ bool fs::remove_dir(const std::string& path) #ifdef _WIN32 if (!RemoveDirectoryW(to_wchar(path).get())) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -464,7 +447,7 @@ bool fs::remove_dir(const std::string& path) #else if (::rmdir(path.c_str()) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -489,13 +472,7 @@ bool fs::rename(const std::string& from, const std::string& to) #ifdef _WIN32 if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get())) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -503,7 +480,7 @@ bool fs::rename(const std::string& from, const std::string& to) #else if (::rename(from.c_str(), to.c_str()) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -523,13 +500,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit #ifdef _WIN32 if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite)) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -540,7 +511,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit const int input = ::open(from.c_str(), O_RDONLY); if (input == -1) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -550,7 +521,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit const int err = errno; ::close(input); - fs::error = err; + g_tls_error = to_error(err); return false; } @@ -569,7 +540,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit ::close(input); ::close(output); - fs::error = err; + g_tls_error = to_error(err); return false; } @@ -589,14 +560,7 @@ bool fs::remove_file(const std::string& path) #ifdef _WIN32 if (!DeleteFileW(to_wchar(path).get())) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -604,7 +568,7 @@ bool fs::remove_file(const std::string& path) #else if (::unlink(path.c_str()) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -624,14 +588,7 @@ bool fs::truncate_file(const std::string& path, u64 length) const auto handle = CreateFileW(to_wchar(path).get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -641,13 +598,7 @@ bool fs::truncate_file(const std::string& path, u64 length) // Seek and truncate if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN) || !SetEndOfFile(handle)) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break; - default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length); - } - + g_tls_error = to_error(GetLastError()); CloseHandle(handle); return false; } @@ -657,7 +608,7 @@ bool fs::truncate_file(const std::string& path, u64 length) #else if (::truncate(path.c_str(), length) != 0) { - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -672,7 +623,7 @@ void fs::file::xnull() const void fs::file::xfail() const { - throw fmt::exception("Unexpected fs::file error %u", fs::error); + throw fmt::exception("Unexpected fs::error %u", g_tls_error); } bool fs::file::open(const std::string& path, bitset_t mode) @@ -704,7 +655,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) { if (mode & fs::excl) { - fs::error = EINVAL; + g_tls_error = error::inval; return false; } @@ -715,15 +666,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) if (handle == INVALID_HANDLE_VALUE) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_FILE_EXISTS: fs::error = EEXIST; break; - default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -747,12 +690,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) FILE_BASIC_INFO basic_info; if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } stat_t info; @@ -773,47 +711,22 @@ bool fs::file::open(const std::string& path, bitset_t mode) pos.QuadPart = 0; if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); - } - + g_tls_error = to_error(GetLastError()); return false; } pos.QuadPart = length; if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break; - default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); - } - + g_tls_error = to_error(GetLastError()); return false; } const BOOL result = SetEndOfFile(m_handle); // change file size - if (!result) + if (!result || !SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN)) // restore position { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); - } - } - - if (!SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN) && result) // restore position - { - if (DWORD error = GetLastError()) - { - throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } return result != FALSE; @@ -823,16 +736,12 @@ bool fs::file::open(const std::string& path, bitset_t mode) { // TODO (call ReadFile multiple times if count is too big) const int size = ::narrow(count, "Too big count" HERE); - Expects(size >= 0); + EXPECTS(size >= 0); DWORD nread; if (!ReadFile(m_handle, buffer, size, &nread, NULL)) { - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } return nread; @@ -842,16 +751,12 @@ bool fs::file::open(const std::string& path, bitset_t mode) { // TODO (call WriteFile multiple times if count is too big) const int size = ::narrow(count, "Too big count" HERE); - Expects(size >= 0); + EXPECTS(size >= 0); DWORD nwritten; if (!WriteFile(m_handle, buffer, size, &nwritten, NULL)) { - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } return nwritten; @@ -870,11 +775,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) if (!SetFilePointerEx(m_handle, pos, &pos, mode)) { - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } return pos.QuadPart; @@ -885,11 +786,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) LARGE_INTEGER size; if (!GetFileSizeEx(m_handle, &size)) { - switch (DWORD error = GetLastError()) - { - case 0: - default: throw fmt::exception("Win32 error: %u." HERE, error); - } + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } return size.QuadPart; @@ -913,8 +810,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) if (fd == -1) { - // TODO: errno - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -938,11 +834,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) struct ::stat file_info; if (::fstat(m_fd, &file_info) != 0) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } stat_t info; @@ -960,12 +852,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) { if (::ftruncate(m_fd, length) != 0) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } - + g_tls_error = to_error(errno); return false; } @@ -977,11 +864,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) const auto result = ::read(m_fd, buffer, count); if (result == -1) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } return result; @@ -992,11 +875,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) const auto result = ::write(m_fd, buffer, count); if (result == -1) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } return result; @@ -1013,11 +892,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) const auto result = ::lseek(m_fd, offset, mode); if (result == -1) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } return result; @@ -1028,11 +903,7 @@ bool fs::file::open(const std::string& path, bitset_t mode) struct ::stat file_info; if (::fstat(m_fd, &file_info) != 0) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } return file_info.st_size; @@ -1049,7 +920,7 @@ fs::file::file(const void* ptr, std::size_t size) { class memory_stream : public file_base { - u64 m_pos{}; // TODO: read/seek could modify m_pos atomically + u64 m_pos{}; const char* const m_ptr; const u64 m_size; @@ -1063,26 +934,26 @@ fs::file::file(const void* ptr, std::size_t size) fs::stat_t stat() override { - throw std::logic_error("memory_stream doesn't support stat()"); + throw std::logic_error("Not supported" HERE); } bool trunc(u64 length) override { - throw std::logic_error("memory_stream doesn't support trunc()"); + throw std::logic_error("Not allowed" HERE); } u64 read(void* buffer, u64 count) override { const u64 start = m_pos; const u64 end = seek(count, fs::seek_cur); - const u64 read_size = end >= start ? end - start : throw std::logic_error("memory_stream::read(): overflow"); + const u64 read_size = end >= start ? end - start : throw std::logic_error("Stream overflow" HERE); std::memcpy(buffer, m_ptr + start, read_size); return read_size; } u64 write(const void* buffer, u64 count) override { - throw std::logic_error("memory_stream is not writable"); + throw std::logic_error("Not allowed" HERE); } u64 seek(s64 offset, fs::seek_mode whence) override @@ -1091,7 +962,7 @@ fs::file::file(const void* ptr, std::size_t size) whence == fs::seek_set ? m_pos = std::min(offset, m_size) : whence == fs::seek_cur ? m_pos = std::min(offset + m_pos, m_size) : whence == fs::seek_end ? m_pos = std::min(offset + m_size, m_size) : - throw std::logic_error("memory_stream::seek(): invalid whence"); + throw fmt::exception("Invalid whence (0x%x)" HERE, whence); } u64 size() override @@ -1127,14 +998,7 @@ bool fs::dir::open(const std::string& path) if (handle == INVALID_HANDLE_VALUE) { - // TODO: convert Win32 error code to errno - switch (DWORD error = GetLastError()) - { - case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break; - case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break; - default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); - } - + g_tls_error = to_error(GetLastError()); return false; } @@ -1179,11 +1043,12 @@ bool fs::dir::open(const std::string& path) WIN32_FIND_DATAW found; if (!FindNextFileW(m_handle, &found)) { - switch (DWORD error = GetLastError()) + if (ERROR_NO_MORE_FILES == GetLastError()) { - case ERROR_NO_MORE_FILES: return false; - default: throw fmt::exception("Unknown Win32 error: %u." HERE, error); + return false; } + + throw fmt::exception("Win32 error: %u." HERE, GetLastError()); } add_entry(found); @@ -1205,8 +1070,7 @@ bool fs::dir::open(const std::string& path) if (!ptr) { - // TODO: errno - fs::error = errno; + g_tls_error = to_error(errno); return false; } @@ -1236,11 +1100,7 @@ bool fs::dir::open(const std::string& path) struct ::stat file_info; if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0) { - switch (int error = errno) - { - case 0: - default: throw fmt::exception("Unknown error: %d." HERE, error); - } + throw fmt::exception("System error: %d." HERE, errno); } info.name = found->d_name; diff --git a/Utilities/File.h b/Utilities/File.h index 0c6e0284ee..5fd7645fd4 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -10,9 +10,6 @@ namespace fs { - // Error code returned - extern thread_local uint error; - // File open mode flags enum struct open_mode : u32 { @@ -265,6 +262,13 @@ namespace fs return read(&str[0], str.size()) == str.size(); } + // Read std::string + bool read(std::string& str, std::size_t size) const + { + str.resize(size); + return read(&str[0], size) == size; + } + // Read POD, sizeof(T) is used template std::enable_if_t::value && !std::is_pointer::value, bool> read(T& data) const @@ -279,6 +283,14 @@ namespace fs return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size(); } + // Read POD std::vector + template + std::enable_if_t::value && !std::is_pointer::value, bool> read(std::vector& vec, std::size_t size) const + { + vec.resize(size); + return read(vec.data(), sizeof(T) * size) == sizeof(T) * size; + } + // Read POD (experimental) template std::enable_if_t::value && !std::is_pointer::value, T> read() const @@ -432,4 +444,16 @@ namespace fs // Get size of all files recursively u64 get_dir_size(const std::string& path); + + enum class error : uint + { + ok = 0, + + inval, + noent, + exist, + }; + + // Error code returned + extern thread_local error g_tls_error; } diff --git a/Utilities/GSL.h b/Utilities/GSL.h index aa74c93610..6d4df0873f 100644 --- a/Utilities/GSL.h +++ b/Utilities/GSL.h @@ -3,12 +3,8 @@ #define GSL_THROW_ON_CONTRACT_VIOLATION #pragma push_macro("new") -#pragma push_macro("Expects") -#pragma push_macro("Ensures") #undef new +#include +#pragma pop_macro("new") #undef Expects #undef Ensures -#include -#pragma pop_macro("Ensures") -#pragma pop_macro("Expects") -#pragma pop_macro("new") diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 3a48116d9f..b1d7718c55 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -8,7 +8,11 @@ // Thread-specific log prefix provider thread_local std::string(*g_tls_log_prefix)() = nullptr; -namespace _log +#ifndef _MSC_VER +constexpr DECLARE(bijective::map); +#endif + +namespace logs { struct listener { @@ -65,7 +69,7 @@ namespace _log channel ARMv7("ARMv7"); } -void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const char* fmt...) +void logs::channel::broadcast(const logs::channel& ch, logs::level sev, const char* fmt...) { va_list args; va_start(args, fmt); @@ -75,13 +79,13 @@ void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const ch [[noreturn]] extern void catch_all_exceptions(); -_log::file_writer::file_writer(const std::string& name) +logs::file_writer::file_writer(const std::string& name) { try { if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) { - throw fmt::exception("Can't create log file %s (error %d)", name, fs::error); + throw fmt::exception("Can't create log file %s (error %d)", name, fs::g_tls_error); } } catch (...) @@ -90,17 +94,17 @@ _log::file_writer::file_writer(const std::string& name) } } -void _log::file_writer::log(const std::string& text) +void logs::file_writer::log(const std::string& text) { m_file.write(text); } -std::size_t _log::file_writer::size() const +std::size_t logs::file_writer::size() const { return m_file.pos(); } -void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text) +void logs::file_listener::log(const logs::channel& ch, logs::level sev, const std::string& text) { std::string msg; msg.reserve(text.size() + 200); diff --git a/Utilities/Log.h b/Utilities/Log.h index 4a6d72e35b..0918e74554 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -3,7 +3,7 @@ #include "types.h" #include "Atomic.h" -namespace _log +namespace logs { enum class level : uint { @@ -79,27 +79,27 @@ namespace _log } template<> -struct bijective<_log::level, const char*> +struct bijective { - static constexpr bijective_pair<_log::level, const char*> map[] + static constexpr bijective_pair map[] { - { _log::level::always, "Nothing" }, - { _log::level::fatal, "Fatal" }, - { _log::level::error, "Error" }, - { _log::level::todo, "TODO" }, - { _log::level::success, "Success" }, - { _log::level::warning, "Warning" }, - { _log::level::notice, "Notice" }, - { _log::level::trace, "Trace" }, + { logs::level::always, "Nothing" }, + { logs::level::fatal, "Fatal" }, + { logs::level::error, "Error" }, + { logs::level::todo, "TODO" }, + { logs::level::success, "Success" }, + { logs::level::warning, "Warning" }, + { logs::level::notice, "Notice" }, + { logs::level::trace, "Trace" }, }; }; // Legacy: -#define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__) -#define LOG_NOTICE(ch, fmt, ...) _log::ch.notice (fmt, ##__VA_ARGS__) -#define LOG_WARNING(ch, fmt, ...) _log::ch.warning(fmt, ##__VA_ARGS__) -#define LOG_ERROR(ch, fmt, ...) _log::ch.error (fmt, ##__VA_ARGS__) -#define LOG_TODO(ch, fmt, ...) _log::ch.todo (fmt, ##__VA_ARGS__) -#define LOG_TRACE(ch, fmt, ...) _log::ch.trace (fmt, ##__VA_ARGS__) -#define LOG_FATAL(ch, fmt, ...) _log::ch.fatal (fmt, ##__VA_ARGS__) +#define LOG_SUCCESS(ch, fmt, ...) logs::ch.success(fmt, ##__VA_ARGS__) +#define LOG_NOTICE(ch, fmt, ...) logs::ch.notice (fmt, ##__VA_ARGS__) +#define LOG_WARNING(ch, fmt, ...) logs::ch.warning(fmt, ##__VA_ARGS__) +#define LOG_ERROR(ch, fmt, ...) logs::ch.error (fmt, ##__VA_ARGS__) +#define LOG_TODO(ch, fmt, ...) logs::ch.todo (fmt, ##__VA_ARGS__) +#define LOG_TRACE(ch, fmt, ...) logs::ch.trace (fmt, ##__VA_ARGS__) +#define LOG_FATAL(ch, fmt, ...) logs::ch.fatal (fmt, ##__VA_ARGS__) diff --git a/Utilities/Macro.h b/Utilities/Macro.h index 7e08fa83de..13ed979921 100644 --- a/Utilities/Macro.h +++ b/Utilities/Macro.h @@ -41,6 +41,7 @@ constexpr std::uint32_t size32(const T(&)[Size]) #define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment") #define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big") #define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align) +#define CHECK_STORAGE(type, storage) static_assert(sizeof(type) <= sizeof(storage) && alignof(type) <= alignof(decltype(storage)), #type " is too small") // Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t #define SIZE_32(type) static_cast(sizeof(type)) @@ -60,20 +61,22 @@ constexpr std::uint32_t size32(const T(&)[Size]) #define STRINGIZE_DETAIL(x) #x #define STRINGIZE(x) STRINGIZE_DETAIL(x) -// Macro set, allows to hide "return" in simple lambda expressions. +// Macro set, wraps an expression into lambda #define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; } #define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; } #define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; } +#define return_ return + #define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")" // Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro). -#define ASSERT(expr) if (!(expr)) throw std::runtime_error("Assertion failed: " #expr HERE) +#define VERIFY(expr) do { if (!(expr)) throw std::runtime_error("Verification failed: " #expr HERE); } while (0) -// Expects() and Ensures() are intended to check function arguments and results. -// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification. -#define Expects ASSERT -#define Ensures ASSERT +// EXPECTS() and ENSURES() are intended to check function arguments and results. +// Expressions are not guaranteed to evaluate. +#define EXPECTS(expr) do { if (!(expr)) throw std::runtime_error("Precondition failed: " #expr HERE); } while (0) +#define ENSURES(expr) do { if (!(expr)) throw std::runtime_error("Postcondition failed: " #expr HERE); } while (0) #define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__ diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index 4042cbbcbc..5ecde9a44c 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -35,7 +35,7 @@ public: bool try_wait() { - return LIKELY(m_value.compare_and_swap_test(1, 0)); + return m_value.compare_and_swap_test(1, 0); } void post() diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp index b6b30c3b6f..1a97b8d472 100644 --- a/Utilities/SharedMutex.cpp +++ b/Utilities/SharedMutex.cpp @@ -140,6 +140,34 @@ void shared_mutex::unlock_notify() } } +void shared_mutex::lock_upgrade_hard() +{ + unlock_shared(); + lock(); +} + +void shared_mutex::lock_degrade_hard() +{ + initialize_once(); + + std::unique_lock lock(m_data->mutex); + + m_ctrl -= SM_WRITER_LOCK - 1; + + if (m_data->rq_size) + { + // Notify all readers + lock.unlock(); + m_data->rcv.notify_all(); + } + else if (m_data->wq_size) + { + // Notify next exclusive owner + lock.unlock(); + m_data->wcv.notify_one(); + } +} + void shared_mutex::initialize_once() { if (UNLIKELY(!m_data)) diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h index b1200cffad..0d69d36e07 100644 --- a/Utilities/SharedMutex.h +++ b/Utilities/SharedMutex.h @@ -32,6 +32,9 @@ class shared_mutex final void lock_hard(); void unlock_notify(); + void lock_upgrade_hard(); + void lock_degrade_hard(); + public: constexpr shared_mutex() = default; @@ -42,15 +45,9 @@ public: bool try_lock_shared() { - auto ctrl = m_ctrl.load(); + const u32 ctrl = m_ctrl.load(); - if (UNLIKELY(ctrl >= SM_READER_MAX)) - { - ctrl = 0; - } - - // Weak attempt - return LIKELY(m_ctrl.compare_and_swap_test(ctrl, ctrl + 1)); + return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1); } void lock_shared() @@ -72,12 +69,12 @@ public: bool try_lock() { - return LIKELY(m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)); + return !m_ctrl && m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK); } void lock() { - if (UNLIKELY(!try_lock())) + if (UNLIKELY(!m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK))) { lock_hard(); } @@ -85,11 +82,39 @@ public: void unlock() { - if (UNLIKELY(m_ctrl.fetch_sub(SM_WRITER_LOCK) != SM_WRITER_LOCK)) + m_ctrl &= ~SM_WRITER_LOCK; + + if (UNLIKELY(m_ctrl)) { unlock_notify(); } } + + bool try_lock_upgrade() + { + return m_ctrl == 1 && m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK); + } + + bool try_lock_degrade() + { + return m_ctrl == SM_WRITER_LOCK && m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1); + } + + void lock_upgrade() + { + if (UNLIKELY(!m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK))) + { + lock_upgrade_hard(); + } + } + + void lock_degrade() + { + if (UNLIKELY(!m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1))) + { + lock_degrade_hard(); + } + } }; //! Simplified shared (reader) lock implementation. @@ -133,3 +158,23 @@ public: m_mutex.unlock(); } }; + +// Exclusive (writer) lock in the scope of shared (reader) lock. +class upgraded_lock final +{ + shared_mutex& m_mutex; + +public: + upgraded_lock(const writer_lock&) = delete; + + upgraded_lock(shared_mutex& mutex) + : m_mutex(mutex) + { + m_mutex.lock_upgrade(); + } + + ~upgraded_lock() + { + m_mutex.lock_degrade(); + } +}; diff --git a/Utilities/SleepQueue.h b/Utilities/SleepQueue.h index fc97baad52..aa5120bb78 100644 --- a/Utilities/SleepQueue.h +++ b/Utilities/SleepQueue.h @@ -59,17 +59,27 @@ public: // Remove thread from the sleep queue void leave() { - auto it = std::find(m_queue.begin(), m_queue.end(), &m_thread); - - if (it != m_queue.end()) + for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++) { - m_queue.erase(it); + if (*it == &m_thread) + { + m_queue.erase(it); + return; + } } } // Check whether the thread exists in the sleep queue explicit operator bool() const { - return std::find(m_queue.begin(), m_queue.end(), &m_thread) != m_queue.end(); + for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++) + { + if (*it == &m_thread) + { + return true; + } + } + + return false; } }; diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 8d61b09b25..274ca09f19 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -5,6 +5,7 @@ #include #include #include +#include std::string v128::to_hex() const { diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index b2dbe5551a..124222b799 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include "Platform.h" #include "types.h" @@ -14,7 +14,7 @@ namespace fmt // Formatting function template - inline std::string format(const char* fmt, const Args&... args) noexcept + inline std::string format(const char* fmt, const Args&... args) { return unsafe_format(fmt, ::unveil::get(args)...); } @@ -34,7 +34,6 @@ namespace fmt class exception : public exception_base { public: - // Formatting constructor template exception(const char* fmt, const Args&... args) : exception_base(fmt, ::unveil::get(args)...) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 4ab6439fac..94e8cb1684 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1263,9 +1263,11 @@ const bool s_self_test = []() -> bool return true; }(); +#include #include #include #include +#include thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; @@ -1278,17 +1280,20 @@ struct thread_ctrl::internal task_stack atexit; std::exception_ptr exception; // Caught exception + + std::chrono::high_resolution_clock::time_point time_limit; }; -// Temporarily until better interface is implemented -extern std::condition_variable& get_current_thread_cv() -{ - return thread_ctrl::get_current()->get_data()->cond; -} +thread_local thread_ctrl::internal* g_tls_internal = nullptr; extern std::mutex& get_current_thread_mutex() { - return thread_ctrl::get_current()->get_data()->mutex; + return g_tls_internal->mutex; +} + +extern std::condition_variable& get_current_thread_cv() +{ + return g_tls_internal->cond; } // TODO @@ -1296,10 +1301,64 @@ extern atomic_t g_thread_count(0); extern thread_local std::string(*g_tls_log_prefix)(); +void thread_ctrl::start(const std::shared_ptr& ctrl, task_stack task) +{ + reinterpret_cast(ctrl->m_thread) = std::thread([ctrl, task = std::move(task)] + { + try + { + ctrl->initialize(); + task.exec(); + } + catch (...) + { + ctrl->initialize_once(); + ctrl->m_data->exception = std::current_exception(); + } + + ctrl->finalize(); + }); +} + +void thread_ctrl::wait_start(u64 timeout) +{ + initialize_once(); + + m_data->time_limit = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(timeout); +} + +bool thread_ctrl::wait_wait(u64 timeout) +{ + initialize_once(); + + std::unique_lock lock(m_data->mutex, std::adopt_lock); + + if (timeout && m_data->cond.wait_until(lock, m_data->time_limit) == std::cv_status::timeout) + { + lock.release(); + return false; + } + + m_data->cond.wait(lock); + lock.release(); + return true; +} + +void thread_ctrl::test() +{ + if (m_data && m_data->exception) + { + std::rethrow_exception(m_data->exception); + } +} + void thread_ctrl::initialize() { + initialize_once(); // TODO (temporarily) + // Initialize TLS variable g_tls_this_thread = this; + g_tls_internal = this->m_data; g_tls_log_prefix = [] { @@ -1339,12 +1398,6 @@ void thread_ctrl::initialize() #endif } -void thread_ctrl::set_exception() noexcept -{ - initialize_once(); - m_data->exception = std::current_exception(); -} - void thread_ctrl::finalize() noexcept { // TODO @@ -1355,30 +1408,43 @@ void thread_ctrl::finalize() noexcept --g_thread_count; -#ifdef _MSC_VER +#ifdef _WIN32 ULONG64 time; - QueryThreadCycleTime(m_thread.native_handle(), &time); + QueryThreadCycleTime(GetCurrentThread(), &time); LOG_NOTICE(GENERAL, "Thread time: %f Gc", time / 1000000000.); #endif } -task_stack& thread_ctrl::get_atexit() const +void thread_ctrl::push_atexit(task_stack task) { initialize_once(); - return m_data->atexit; + m_data->atexit.push(std::move(task)); +} + +thread_ctrl::thread_ctrl(std::string&& name) + : m_name(std::move(name)) +{ + CHECK_STORAGE(std::thread, m_thread); + +#pragma push_macro("new") +#undef new + new (&m_thread) std::thread; +#pragma pop_macro("new") } thread_ctrl::~thread_ctrl() { - if (m_thread.joinable()) + if (reinterpret_cast(m_thread).joinable()) { - m_thread.detach(); + reinterpret_cast(m_thread).detach(); } delete m_data; + + reinterpret_cast(m_thread).~thread(); } -void thread_ctrl::initialize_once() const +void thread_ctrl::initialize_once() { if (UNLIKELY(!m_data)) { @@ -1393,33 +1459,37 @@ void thread_ctrl::initialize_once() const void thread_ctrl::join() { - if (LIKELY(m_thread.joinable())) + // Increase contention counter + const u32 _j = m_joining++; + + if (LIKELY(_j >= 0x80000000)) { - // Increase contention counter - if (UNLIKELY(m_joining++)) + // Already joined (signal condition) + m_joining = 0x80000000; + } + else if (LIKELY(_j == 0)) + { + // Winner joins the thread + reinterpret_cast(m_thread).join(); + + // Notify others if necessary + if (UNLIKELY(m_joining.exchange(0x80000000) != 1)) { - // Hard way initialize_once(); - std::unique_lock lock(m_data->mutex); - m_data->join.wait(lock, WRAP_EXPR(!m_thread.joinable())); + // Serialize for reliable notification + m_data->mutex.lock(); + m_data->mutex.unlock(); + m_data->join.notify_all(); } - else - { - // Winner joins the thread - m_thread.join(); + } + else + { + // Hard way + initialize_once(); - // Notify others if necessary - if (UNLIKELY(m_joining > 1)) - { - initialize_once(); - - // Serialize for reliable notification - m_data->mutex.lock(); - m_data->mutex.unlock(); - m_data->join.notify_all(); - } - } + std::unique_lock lock(m_data->mutex); + m_data->join.wait(lock, WRAP_EXPR(m_joining >= 0x80000000)); } if (UNLIKELY(m_data && m_data->exception)) @@ -1428,7 +1498,18 @@ void thread_ctrl::join() } } -void thread_ctrl::lock_notify() const +void thread_ctrl::lock() +{ + initialize_once(); + m_data->mutex.lock(); +} + +void thread_ctrl::unlock() +{ + m_data->mutex.unlock(); +} + +void thread_ctrl::lock_notify() { if (UNLIKELY(g_tls_this_thread == this)) { @@ -1443,16 +1524,19 @@ void thread_ctrl::lock_notify() const m_data->cond.notify_one(); } -void thread_ctrl::notify() const +void thread_ctrl::notify() { - initialize_once(); m_data->cond.notify_one(); } -thread_ctrl::internal* thread_ctrl::get_data() const +void thread_ctrl::set_exception(std::exception_ptr e) { - initialize_once(); - return m_data; + m_data->exception = e; +} + +void thread_ctrl::sleep(u64 useconds) +{ + std::this_thread::sleep_for(std::chrono::microseconds(useconds)); } @@ -1462,7 +1546,6 @@ named_thread::named_thread() named_thread::~named_thread() { - LOG_TRACE(GENERAL, "%s", __func__); } std::string named_thread::get_name() const diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 2bf7b63566..46782c8c98 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -1,8 +1,8 @@ #pragma once +#include #include #include -#include #include "Platform.h" #include "Atomic.h" @@ -28,38 +28,41 @@ class task_stack } }; + template + struct task_type : task_base + { + std::remove_reference_t func; + + task_type(F&& func) + : func(std::forward(func)) + { + } + + void exec() override + { + func(); + task_base::exec(); + } + }; + std::unique_ptr m_stack; public: + task_stack() = default; + template - void push(F&& func) + task_stack(F&& func) + : m_stack(new task_type(std::forward(func))) { - struct task_t : task_base - { - std::remove_reference_t func; + } - task_t(F&& func) - : func(std::forward(func)) - { - } - - void exec() override - { - func(); - task_base::exec(); - } - }; - - auto _top = new task_t(std::forward(func)); + void push(task_stack stack) + { + auto _top = stack.m_stack.release(); auto _next = m_stack.release(); m_stack.reset(_top); -#ifndef _MSC_VER + while (UNLIKELY(_top->next)) _top = _top->next.get(); _top->next.reset(_next); -#else - auto& next = _top->next; - next.release(); - next.reset(_next); -#endif } void reset() @@ -79,42 +82,48 @@ public: // Thread control class class thread_ctrl final { +public: // TODO struct internal; +private: static thread_local thread_ctrl* g_tls_this_thread; - // Thread handle - std::thread m_thread; + // Thread handle storage + std::aligned_storage_t<16> m_thread; // Thread join contention counter - atomic_t m_joining{}; + atomic_t m_joining{}; + + // Thread internals + atomic_t m_data{}; // Fixed name std::string m_name; - // Thread internals - mutable atomic_t m_data{}; + // Start thread + static void start(const std::shared_ptr&, task_stack); // Called at the thread start void initialize(); - // Set std::current_exception - void set_exception() noexcept; - // Called at the thread end void finalize() noexcept; // Get atexit function - task_stack& get_atexit() const; + void push_atexit(task_stack); + + // Start waiting + void wait_start(u64 timeout); + + // Proceed waiting + bool wait_wait(u64 timeout); + + // Check exception + void test(); public: - template - thread_ctrl(N&& name) - : m_name(std::forward(name)) - { - } + thread_ctrl(std::string&& name); - // Disable copy/move constructors and operators thread_ctrl(const thread_ctrl&) = delete; ~thread_ctrl(); @@ -126,54 +135,139 @@ public: } // Initialize internal data - void initialize_once() const; + void initialize_once(); // Get thread result (may throw, simultaneous joining allowed) void join(); + // Lock thread mutex + void lock(); + + // Lock conditionally (double-checked) + template + bool lock_if(F&& pred) + { + if (pred()) + { + lock(); + + try + { + if (LIKELY(pred())) + { + return true; + } + else + { + unlock(); + return false; + } + } + catch (...) + { + unlock(); + throw; + } + } + else + { + return false; + } + } + + // Unlock thread mutex (internal data must be initialized) + void unlock(); + // Lock, unlock, notify the thread (required if the condition changed locklessly) - void lock_notify() const; + void lock_notify(); - // Notify the thread, beware the condition change - void notify() const; + // Notify the thread (internal data must be initialized) + void notify(); - // - internal* get_data() const; + // Set exception (internal data must be initialized, thread mutex must be locked) + void set_exception(std::exception_ptr); + + // Current thread sleeps for specified amount of microseconds. + // Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl. + [[deprecated]] static void sleep(u64 useconds); + + // Wait until pred(). Abortable, may throw. Thread must be locked. + // Timeout in microseconds (zero means infinite). + template + static inline auto wait(u64 useconds, F&& pred) + { + g_tls_this_thread->wait_start(useconds); + + while (true) + { + g_tls_this_thread->test(); + + if (auto&& result = pred()) + { + return result; + } + else if (!g_tls_this_thread->wait_wait(useconds) && useconds) + { + return result; + } + } + } + + // Wait until pred(). Abortable, may throw. Thread must be locked. + template + static inline auto wait(F&& pred) + { + while (true) + { + g_tls_this_thread->test(); + + if (auto&& result = pred()) + { + return result; + } + + g_tls_this_thread->wait_wait(0); + } + } + + // Wait once. Thread must be locked. + static inline void wait() + { + g_tls_this_thread->test(); + g_tls_this_thread->wait_wait(0); + g_tls_this_thread->test(); + } + + // Wait unconditionally until aborted. Thread must be locked. + [[noreturn]] static inline void eternalize() + { + while (true) + { + g_tls_this_thread->test(); + g_tls_this_thread->wait_wait(0); + } + } // Get current thread (may be nullptr) - static const thread_ctrl* get_current() + static thread_ctrl* get_current() { return g_tls_this_thread; } // Register function at thread exit (for the current thread) template - static inline void at_exit(F&& func) + static inline void atexit(F&& func) { - return g_tls_this_thread->get_atexit().push(std::forward(func)); + return g_tls_this_thread->push_atexit(std::forward(func)); } // Named thread factory - template - static inline std::shared_ptr spawn(N&& name, F&& func, Args&&... args) + template + static inline std::shared_ptr spawn(N&& name, F&& func) { auto ctrl = std::make_shared(std::forward(name)); - ctrl->m_thread = std::thread([ctrl, task = std::forward(func)](Args&&... args) - { - try - { - ctrl->initialize(); - task(std::forward(args)...); - } - catch (...) - { - ctrl->set_exception(); - } - - ctrl->finalize(); - - }, std::forward(args)...); + thread_ctrl::start(ctrl, std::forward(func)); return ctrl; } @@ -218,22 +312,43 @@ public: m_thread->join(); } - // Get thread_ctrl - const thread_ctrl* operator->() const + // Access thread_ctrl + thread_ctrl* operator->() const { return m_thread.get(); } +}; - // Lock mutex, notify condition variable - void lock_notify() const +// Simple thread mutex locker +class thread_lock final +{ + thread_ctrl* m_thread; + +public: + thread_lock(const thread_lock&) = delete; + + // Lock specified thread + thread_lock(thread_ctrl* thread) + : m_thread(thread) { - m_thread->lock_notify(); + m_thread->lock(); } - // Notify condition variable - void notify() const + // Lock specified named_thread + thread_lock(named_thread& thread) + : thread_lock(thread.operator->()) { - m_thread->notify(); + } + + // Lock current thread + thread_lock() + : thread_lock(thread_ctrl::get_current()) + { + } + + ~thread_lock() + { + m_thread->unlock(); } }; diff --git a/Utilities/VirtualMemory.cpp b/Utilities/VirtualMemory.cpp index e0b2b2ed61..a7e85ff4ff 100644 --- a/Utilities/VirtualMemory.cpp +++ b/Utilities/VirtualMemory.cpp @@ -17,10 +17,10 @@ namespace memory_helper { #ifdef _WIN32 void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); - Ensures(ret != NULL); + ENSURES(ret != NULL); #else void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); - Ensures(ret != 0); + ENSURES(ret != 0); #endif return ret; } @@ -28,18 +28,18 @@ namespace memory_helper void commit_page_memory(void* pointer, size_t page_size) { #ifdef _WIN32 - ASSERT(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); + VERIFY(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); #else - ASSERT(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); + VERIFY(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); #endif } void free_reserved_memory(void* pointer, size_t size) { #ifdef _WIN32 - ASSERT(VirtualFree(pointer, 0, MEM_RELEASE) != 0); + VERIFY(VirtualFree(pointer, 0, MEM_RELEASE) != 0); #else - ASSERT(munmap(pointer, size) == 0); + VERIFY(munmap(pointer, size) == 0); #endif } } diff --git a/Utilities/lockless.h b/Utilities/lockless.h new file mode 100644 index 0000000000..863fe1d647 --- /dev/null +++ b/Utilities/lockless.h @@ -0,0 +1,105 @@ +#pragma once + +#include "types.h" +#include "Atomic.h" +#include "Platform.h" + +//! Simple sizeless array base for concurrent access. Cannot shrink, only growths automatically. +//! There is no way to know the current size. The smaller index is, the faster it's accessed. +//! +//! T is the type of elements. Currently, default constructor of T shall be constexpr. +//! N is initial element count, available without any memory allocation and only stored contiguously. +template +class lf_array +{ + // Data (default-initialized) + T m_data[N]{}; + + // Next array block + atomic_t m_next{}; + +public: + constexpr lf_array() = default; + + ~lf_array() + { + for (auto ptr = m_next.raw(); UNLIKELY(ptr);) + { + delete std::exchange(ptr, std::exchange(ptr->m_next.raw(), nullptr)); + } + } + + T& operator [](std::size_t index) + { + if (LIKELY(index < N)) + { + return m_data[index]; + } + else if (UNLIKELY(!m_next)) + { + // Create new array block. It's not a full-fledged once-synchronization, unlikely needed. + for (auto _new = new lf_array, ptr = this; UNLIKELY(ptr);) + { + // Install the pointer. If failed, go deeper. + ptr = ptr->m_next.compare_and_swap(nullptr, _new); + } + } + + // Access recursively + return (*m_next)[index - N]; + } +}; + +//! Simple lock-free FIFO queue base. Based on lf_array itself. Currently uses 32-bit counters. +//! There is no "push_end" or "pop_begin" provided, the queue element must signal its state on its own. +template +class lf_fifo : public lf_array +{ + struct alignas(8) ctrl_t + { + u32 push; + u32 pop; + }; + + atomic_t m_ctrl{}; + +public: + constexpr lf_fifo() = default; + + // Get current "push" position + u32 size() + { + return reinterpret_cast&>(m_ctrl).load(); // Hack + } + + // Acquire the place for one or more elements. + u32 push_begin(u32 count = 1) + { + return reinterpret_cast&>(m_ctrl).fetch_add(count); // Hack + } + + // Get current "pop" position + u32 peek() + { + return m_ctrl.load().pop; + } + + // Acknowledge processed element, return number of the next one. + // Perform clear if possible, zero is returned in this case. + u32 pop_end(u32 count = 1) + { + return m_ctrl.atomic_op([&](ctrl_t& ctrl) + { + ctrl.pop += count; + + if (ctrl.pop == ctrl.push) + { + // Clean if possible + ctrl.push = 0; + ctrl.pop = 0; + } + + return ctrl.pop; + }); + } +}; diff --git a/Utilities/sync.h b/Utilities/sync.h new file mode 100644 index 0000000000..ba91a76e1f --- /dev/null +++ b/Utilities/sync.h @@ -0,0 +1,192 @@ +#pragma once + +/* For internal use. Don't include. */ + +#include "types.h" +#include "Macro.h" +#include "Atomic.h" + +#ifdef _WIN32 + +#include + +#define DYNAMIC_IMPORT(handle, name) do { name = reinterpret_cast(GetProcAddress(handle, #name)); } while (0) + +static NTSTATUS(*NtSetTimerResolution)(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution); +static NTSTATUS(*NtWaitForKeyedEvent)(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout); +static NTSTATUS(*NtReleaseKeyedEvent)(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout); + +namespace util +{ + static const bool keyed_init = [] + { + const auto handle = LoadLibraryA("ntdll.dll"); + DYNAMIC_IMPORT(handle, NtSetTimerResolution); + DYNAMIC_IMPORT(handle, NtWaitForKeyedEvent); + DYNAMIC_IMPORT(handle, NtReleaseKeyedEvent); + FreeLibrary(handle); + + ULONG res = 100; + NtSetTimerResolution(100, TRUE, &res); + + return NtWaitForKeyedEvent && NtReleaseKeyedEvent; + }(); + + // Wait for specified condition. func() acknowledges success by value modification. + template + inline void keyed_wait(atomic_t& key, F&& func) + { + while (true) + { + NtWaitForKeyedEvent(NULL, &key, FALSE, NULL); + + u32 read = key.load(); + u32 copy = read; + + while (pred(read), read != copy) + { + read = key.compare_and_swap(copy, read); + + if (copy == read) + { + break; + } + + copy = read; + } + } + } + + // Try to wake up a thread. + inline bool keyed_post(atomic_t& key, u32 acknowledged_value) + { + LARGE_INTEGER zero; + zero.QuadPart = 0; + + while (UNLIKELY(NtReleaseKeyedEvent(NULL, &key, FALSE, &zero) == WAIT_TIMEOUT)) + { + if (key.load() != acknowledged_value) + return false; + + //NtReleaseKeyedEvent(NULL, &key, FALSE, NULL); + //return true; + } + + return true; + } + + struct native_rwlock + { + SRWLOCK rwlock = SRWLOCK_INIT; + + constexpr native_rwlock() = default; + + native_rwlock(const native_rwlock&) = delete; + + void lock() + { + AcquireSRWLockExclusive(&rwlock); + } + + bool try_lock() + { + return TryAcquireSRWLockExclusive(&rwlock) != 0; + } + + void unlock() + { + ReleaseSRWLockExclusive(&rwlock); + } + + void lock_shared() + { + AcquireSRWLockShared(&rwlock); + } + + bool try_lock_shared() + { + return TryAcquireSRWLockShared(&rwlock) != 0; + } + + void unlock_shared() + { + ReleaseSRWLockShared(&rwlock); + } + }; + + struct native_cond + { + CONDITION_VARIABLE cond = CONDITION_VARIABLE_INIT; + + constexpr native_cond() = default; + + native_cond(const native_cond&) = delete; + + void notify_one() + { + WakeConditionVariable(&cond); + } + + void notify_all() + { + WakeAllConditionVariable(&cond); + } + + void wait(native_rwlock& rwlock) + { + SleepConditionVariableSRW(&cond, &rwlock.rwlock, INFINITE, 0); + } + + void wait_shared(native_rwlock& rwlock) + { + SleepConditionVariableSRW(&cond, &rwlock.rwlock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED); + } + }; + + class exclusive_lock + { + native_rwlock& m_rwlock; + + public: + exclusive_lock(native_rwlock& rwlock) + : m_rwlock(rwlock) + { + m_rwlock.lock(); + } + + ~exclusive_lock() + { + m_rwlock.unlock(); + } + }; + + class shared_lock + { + native_rwlock& m_rwlock; + + public: + shared_lock(native_rwlock& rwlock) + : m_rwlock(rwlock) + { + m_rwlock.lock_shared(); + } + + ~shared_lock() + { + m_rwlock.unlock_shared(); + } + }; +} + +#else + +namespace util +{ + struct native_rwlock; + struct native_cond; +} + +#endif + +CHECK_SIZE_ALIGN(util::native_rwlock, sizeof(void*), alignof(void*)); +CHECK_SIZE_ALIGN(util::native_cond, sizeof(void*), alignof(void*)); diff --git a/Utilities/types.h b/Utilities/types.h index cff51f5c04..c822aba50a 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -407,12 +407,22 @@ struct ignore } }; +// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set). +template +struct pointer_hash +{ + std::size_t operator()(T* ptr) const + { + return reinterpret_cast(ptr) / Align; + } +}; + // Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied. // For example, `simple_t` may be used to remove endianness. template class TT, std::size_t S, std::size_t A = S> struct alignas(A) any_pod { - enum class byte : char {} data[S]; + std::aligned_storage_t data; any_pod() = default; diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index bd631662f2..d4416d6c75 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -40,7 +40,7 @@ if(NOT MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1") # fix for travis gcc OoM crash. Might be fixed with the move to containers. endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fexceptions") - add_compile_options(-msse -msse2 -mcx16 -mssse3) + add_compile_options(-msse -msse2 -mcx16 -mssse3 -march=native) else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1") endif() diff --git a/rpcs3/Emu/Audio/AudioDumper.cpp b/rpcs3/Emu/Audio/AudioDumper.cpp index 670227b896..a61e62c4be 100644 --- a/rpcs3/Emu/Audio/AudioDumper.cpp +++ b/rpcs3/Emu/Audio/AudioDumper.cpp @@ -24,7 +24,7 @@ void AudioDumper::WriteData(const void* buffer, u32 size) { if (GetCh()) { - ASSERT(m_output.write(buffer, size) == size); + VERIFY(m_output.write(buffer, size) == size); m_header.Size += size; m_header.RIFF.Size += size; } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 27e970e81a..294a1b6e73 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/IdManager.h" - -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/SPUThread.h" -#include "Emu/Cell/RawSPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" #include "CPUThread.h" +#include +#include + thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; +extern std::mutex& get_current_thread_mutex(); +extern std::condition_variable& get_current_thread_cv(); + void cpu_thread::on_task() { state -= cpu_state::exit; @@ -61,7 +61,7 @@ void cpu_thread::on_task() void cpu_thread::on_stop() { state += cpu_state::exit; - lock_notify(); + (*this)->lock_notify(); } cpu_thread::~cpu_thread() @@ -121,35 +121,3 @@ bool cpu_thread::check_status() return false; } - -[[noreturn]] void cpu_thread::xsleep() -{ - throw std::runtime_error("cpu_thread: sleep()/awake() inconsistency"); -} - -std::vector> get_all_cpu_threads() -{ - std::vector> result; - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - for (auto& t : idm::get_all()) - { - result.emplace_back(t); - } - - return result; -} diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index eae4cacb02..89cbb179cf 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -40,7 +40,6 @@ public: const std::string name; const cpu_type type; - const id_value<> id{}; cpu_thread(cpu_type type, const std::string& name); @@ -48,36 +47,34 @@ public: // Public thread state atomic_t> state{ cpu_state::stop }; - // Recursively enter sleep state - void sleep() - { - if (!++m_sleep) xsleep(); - } + // Public recursive sleep state counter + atomic_t sleep_counter{}; - // Leave sleep state - void awake() - { - if (!m_sleep--) xsleep(); - } + // Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.) + atomic_t owner{}; // Process thread state, return true if the checker must return bool check_status(); - virtual std::string dump() const = 0; // Print CPU state + // Increse sleep counter + void sleep() + { + if (!sleep_counter++) return; //handle_interrupt(); + } + + // Decrese sleep counter + void awake() + { + if (!--sleep_counter) owner = nullptr; + } + + // Print CPU state + virtual std::string dump() const = 0; virtual void cpu_init() {} virtual void cpu_task() = 0; virtual bool handle_interrupt() { return false; } - -private: - [[noreturn]] void xsleep(); - - // Sleep/Awake counter - atomic_t m_sleep{}; }; -extern std::mutex& get_current_thread_mutex(); -extern std::condition_variable& get_current_thread_cv(); - inline cpu_thread* get_current_cpu_thread() noexcept { extern thread_local cpu_thread* g_tls_current_cpu_thread; @@ -85,4 +82,26 @@ inline cpu_thread* get_current_cpu_thread() noexcept return g_tls_current_cpu_thread; } -extern std::vector> get_all_cpu_threads(); +// Helper for cpu_thread. +// 1) Calls sleep() and locks the thread in the constructor. +// 2) Calls awake() and unlocks the thread in the destructor. +class cpu_thread_lock final +{ + cpu_thread& m_thread; + +public: + cpu_thread_lock(const cpu_thread_lock&) = delete; + + cpu_thread_lock(cpu_thread& thread) + : m_thread(thread) + { + m_thread.sleep(); + m_thread->lock(); + } + + ~cpu_thread_lock() + { + m_thread.awake(); + m_thread->unlock(); + } +}; diff --git a/rpcs3/Emu/IPC.h b/rpcs3/Emu/IPC.h new file mode 100644 index 0000000000..f8f73d0916 --- /dev/null +++ b/rpcs3/Emu/IPC.h @@ -0,0 +1,88 @@ +#pragma once + +#include +#include + +#include "Utilities/SharedMutex.h" + +// IPC manager for objects of type T and IPC keys of type K. +// External declaration of g_ipc is required. +template +class ipc_manager final +{ + std::unordered_map> m_map; + + shared_mutex m_mutex; + + static ipc_manager g_ipc; + +public: + // Add new object if specified ipc_key is not used + template + static bool add(const K& ipc_key, F&& provider) + { + writer_lock lock(g_ipc.m_mutex); + + // Get object location + std::weak_ptr& wptr = g_ipc.m_map[ipc_key]; + + if (wptr.expired()) + { + // Call a function which must return the object + wptr = provider(); + return true; + } + + return false; + } + + // Unregister specified ipc_key, may return true even if the object doesn't exist anymore + static bool remove(const K& ipc_key) + { + writer_lock lock(g_ipc.m_mutex); + + return g_ipc.m_map.erase(ipc_key) != 0; + } + + // Unregister specified ipc_key, return the object + static std::shared_ptr withdraw(const K& ipc_key) + { + writer_lock lock(g_ipc.m_mutex); + + const auto found = g_ipc.m_map.find(ipc_key); + + if (found != g_ipc.m_map.end()) + { + auto ptr = found->second.lock(); + g_ipc.m_map.erase(found); + return ptr; + } + + return nullptr; + } + + // Get object with specified ipc_key + static std::shared_ptr get(const K& ipc_key) + { + reader_lock lock(g_ipc.m_mutex); + + const auto found = g_ipc.m_map.find(ipc_key); + + if (found != g_ipc.m_map.end()) + { + return found->second.lock(); + } + + return nullptr; + } + + // Check whether the object actually exists + static bool check(const K& ipc_key) + { + reader_lock lock(g_ipc.m_mutex); + + const auto found = g_ipc.m_map.find(ipc_key); + + return found != g_ipc.m_map.end() && !found->second.expired(); + } +}; diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 32ab768c16..e2bef6e4b4 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -1,10 +1,17 @@ #include "stdafx.h" #include "IdManager.h" +DECLARE(idm::g_map); +DECLARE(idm::g_id); +DECLARE(idm::g_mutex); + +DECLARE(fxm::g_map); +DECLARE(fxm::g_mutex); + std::vector& id_manager::typeinfo::access() { static std::vector list; - + return list; } diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 84d4f8bccf..964661661a 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -8,8 +8,6 @@ #include #include #include -#include -#include // Mostly helper namespace namespace id_manager @@ -37,7 +35,7 @@ namespace id_manager template struct on_init { - static void func(T*) + static inline void func(T*) { } }; @@ -45,7 +43,7 @@ namespace id_manager template struct on_init().on_init())> { - static void func(T* ptr) + static inline void func(T* ptr) { ptr->on_init(); } @@ -55,7 +53,7 @@ namespace id_manager template struct on_stop { - static void func(T*) + static inline void func(T*) { } }; @@ -63,7 +61,7 @@ namespace id_manager template struct on_stop().on_stop())> { - static void func(T* ptr) + static inline void func(T* ptr) { ptr->on_stop(); } @@ -155,15 +153,41 @@ class idm // Update optional ID storage template - static auto set_id_value(T* ptr, u32 id) -> decltype(static_cast(std::declval().id)) + static inline auto set_id_value(T* ptr, u32 id) -> decltype(static_cast(std::declval().id)) { ptr->id = id; } - static void set_id_value(...) + static inline void set_id_value(...) { } + // Helper + template + struct function_traits; + + template + struct function_traits + { + using second_type = A2; + using return_type = R; + }; + + // Helper + template + struct bool_if_void + { + friend bool operator ,(bool lhs, const bool_if_void&) + { + return lhs; + } + + operator bool() const + { + return Value; + } + }; + // Prepares new ID, returns nullptr if out of resources static map_type::pointer allocate_id(u32 tag, u32 min, u32 max); @@ -213,7 +237,7 @@ public: // Add a new ID of specified type with specified constructor arguments (returns object or nullptr) template - static std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + static inline std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) { if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { @@ -226,7 +250,7 @@ public: // Add a new ID of specified type with specified constructor arguments (returns id) template - static std::enable_if_t::value, u32> make(Args&&... args) + static inline std::enable_if_t::value, u32> make(Args&&... args) { if (auto pair = create_id(WRAP_EXPR(std::make_shared(std::forward(args)...)))) { @@ -239,7 +263,7 @@ public: // Add a new ID for an existing object provided (returns new id) template - static u32 import_existing(const std::shared_ptr& ptr) + static inline u32 import_existing(const std::shared_ptr& ptr) { if (auto pair = create_id(WRAP_EXPR(ptr))) { @@ -252,7 +276,7 @@ public: // Add a new ID for an object returned by provider() template> - static std::shared_ptr import(F&& provider) + static inline std::shared_ptr import(F&& provider) { if (auto pair = create_id(std::forward(provider))) { @@ -263,18 +287,18 @@ public: return nullptr; } - // Check whether ID exists + // Check whether the ID exists template - static bool check(u32 id) + static inline bool check(u32 id) { reader_lock lock(g_mutex); return find_id(get_type(), id) != nullptr; } - // Get ID + // Get the ID template - static std::shared_ptr get(u32 id) + static inline std::shared_ptr get(u32 id) { reader_lock lock(g_mutex); @@ -288,25 +312,63 @@ public: return{ found->second, static_cast(found->second.get()) }; } - // Get all IDs (unsorted) + // Conditionally get the ID, almost similar to select() but for the single object only. + template::second_type> + static inline auto get(u32 id, F&& pred) + { + using result_type = std::conditional_t::return_type>::value, void, std::shared_ptr>; + + reader_lock lock(g_mutex); + + const auto found = find_id(get_type(), id); + + if (UNLIKELY(found == nullptr)) + { + return static_cast(nullptr); + } + + if (pred(id, *static_cast(found->second.get())), bool_if_void()) + { + return static_cast(std::static_pointer_cast(found->second)); + } + + return static_cast(nullptr); + } + + // Execute for all IDs (unsorted), may return void. If the result evaluates to true, the loop stops and returns the object. + template::second_type> + static inline auto select(F&& pred) + { + using result_type = std::conditional_t::return_type>::value, void, std::shared_ptr>; + + reader_lock lock(g_mutex); + + for (u32 type : { get_type()... }) + { + for (auto& id : g_map[type]) + { + if (pred(id.first, *static_cast(id.second.get())), bool_if_void()) + { + return static_cast(std::static_pointer_cast(id.second)); + } + } + } + + return static_cast(nullptr); + } + + // Get count of objects template - static std::vector> get_all() + static inline u32 get_count() { reader_lock lock(g_mutex); - std::vector> result; - - for (auto& id : g_map[get_type()]) - { - result.emplace_back(id.second, static_cast(id.second.get())); - } - - return result; + return ::size32(g_map[get_type()]); } // Remove the ID template - static bool remove(u32 id) + static inline bool remove(u32 id) { auto&& ptr = delete_id(get_type(), get_tag(), id); @@ -320,7 +382,7 @@ public: // Remove the ID and return it template - static std::shared_ptr withdraw(u32 id) + static inline std::shared_ptr withdraw(u32 id) { auto&& ptr = delete_id(get_type(), get_tag(), id); @@ -332,44 +394,29 @@ public: return{ ptr, static_cast(ptr.get()) }; } - template - static u32 get_count() + // Conditionally remove the ID and return it. + template + static inline std::shared_ptr withdraw(u32 id, F&& pred) { - reader_lock lock(g_mutex); - - return ::size32(g_map[get_type()]); - } - - // Get sorted list of all IDs of specified type - template - static std::set get_set() - { - reader_lock lock(g_mutex); - - std::set result; - - for (auto& id : g_map[get_type()]) + std::shared_ptr ptr; { - result.emplace(id.first); + writer_lock lock(g_mutex); + + const auto found = find_id(get_type(), id); + + if (UNLIKELY(found == nullptr || !pred(id, *static_cast(found->second.get())))) + { + return nullptr; + } + + ptr = deallocate_id(get_tag(), id); + + g_map[get_type()].erase(id); } + + id_manager::on_stop::func(static_cast(ptr.get())); - return result; - } - - // Get sorted map (ID value -> ID data) of all IDs of specified type - template - static std::map> get_map() - { - reader_lock lock(g_mutex); - - std::map> result; - - for (auto& id : g_map[get_type()]) - { - result[id.first] = { id.second, static_cast(id.second.get()) }; - } - - return result; + return{ ptr, static_cast(ptr.get()) }; } }; @@ -518,7 +565,7 @@ public: // Check whether the object exists template - static bool check() + static inline bool check() { reader_lock lock(g_mutex); @@ -527,7 +574,7 @@ public: // Get the object (returns nullptr if it doesn't exist) template - static std::shared_ptr get() + static inline std::shared_ptr get() { reader_lock lock(g_mutex); @@ -538,7 +585,7 @@ public: // Delete the object template - static bool remove() + static inline bool remove() { auto&& ptr = remove(get_type()); @@ -552,7 +599,7 @@ public: // Delete the object and return it template - static std::shared_ptr withdraw() + static inline std::shared_ptr withdraw() { auto&& ptr = remove(get_type()); diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 3f25183067..975beb34e7 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -18,7 +18,7 @@ bool VirtualMemoryBlock::IsInMyRange(const u32 addr, const u32 size) u32 VirtualMemoryBlock::Map(u32 realaddr, u32 size) { - Expects(size); + EXPECTS(size); for (u32 addr = m_range_start; addr <= m_range_start + m_range_size - 1 - GetReservedAmount() - size;) { @@ -48,7 +48,7 @@ u32 VirtualMemoryBlock::Map(u32 realaddr, u32 size) bool VirtualMemoryBlock::Map(u32 realaddr, u32 size, u32 addr) { - Expects(size); + EXPECTS(size); if (!IsInMyRange(addr, size)) { diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index c45a731c10..0f3f70ef5f 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -5,7 +5,7 @@ #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/PSP2/ARMv7Thread.h" #ifdef _WIN32 #include @@ -93,66 +93,15 @@ namespace vm std::vector> g_locations; // memory locations - //using reservation_mutex_t = std::mutex; - - class reservation_mutex_t + access_violation::access_violation(u64 addr, const char* cause) + : std::runtime_error(fmt::exception("Access violation %s address 0x%llx", cause, addr)) { - atomic_t m_lock{ false }; - std::thread::id m_owner{}; + g_tls_fault_count &= ~(1ull << 63); + } - std::condition_variable m_cv; - std::mutex m_mutex; + using reservation_mutex_t = std::mutex; - public: - bool do_notify = false; - - never_inline void lock() - { - std::unique_lock lock(m_mutex, std::defer_lock); - - while (m_lock.exchange(true) == true) - { - if (m_owner == std::this_thread::get_id()) - { - throw EXCEPTION("Deadlock"); - } - - if (!lock) - { - lock.lock(); - continue; - } - - m_cv.wait_for(lock, std::chrono::milliseconds(1)); - } - - m_owner = std::this_thread::get_id(); - do_notify = true; - } - - never_inline void unlock() - { - if (m_owner != std::this_thread::get_id()) - { - throw EXCEPTION("Mutex not owned"); - } - - m_owner = {}; - - if (m_lock.exchange(false) == false) - { - throw EXCEPTION("Lost lock"); - } - - if (do_notify) - { - std::lock_guard lock(m_mutex); - m_cv.notify_one(); - } - } - }; - - const thread_ctrl* volatile g_reservation_owner = nullptr; + thread_ctrl* volatile g_reservation_owner = nullptr; u32 g_reservation_addr = 0; u32 g_reservation_size = 0; @@ -161,14 +110,6 @@ namespace vm reservation_mutex_t g_reservation_mutex; - - - access_violation::access_violation(u64 addr, const char* cause) - : std::runtime_error(fmt::exception("Access violation %s address 0x%llx", cause, addr)) - { - g_tls_fault_count &= ~(1ull << 63); - } - void _reservation_set(u32 addr, bool no_access = false) { #ifdef _WIN32 @@ -320,7 +261,7 @@ namespace vm return true; } - bool reservation_test(const thread_ctrl* current) + bool reservation_test(thread_ctrl* current) { const auto owner = g_reservation_owner; diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index dda271ebcc..26f1af795d 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,6 +1,7 @@ #pragma once #include +#include class thread_ctrl; @@ -32,6 +33,9 @@ namespace vm page_allocated = (1 << 7), }; + // Address type + enum addr_t : u32 {}; + struct access_violation : std::runtime_error { access_violation(u64 addr, const char* cause); @@ -60,7 +64,7 @@ namespace vm bool reservation_query(u32 addr, u32 size, bool is_writing, std::function callback); // Returns true if the current thread owns reservation - bool reservation_test(const thread_ctrl* current); + bool reservation_test(thread_ctrl* current); // Break all reservations created by the current thread void reservation_free(); @@ -133,11 +137,11 @@ namespace vm std::shared_ptr get(memory_location_t location, u32 addr = 0); // Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 0) - inline u32 get_addr(const void* real_ptr) + inline vm::addr_t get_addr(const void* real_ptr) { if (!real_ptr) { - return 0; + return vm::addr_t{}; } const std::ptrdiff_t diff = static_cast(real_ptr) - g_base_addr; @@ -145,7 +149,7 @@ namespace vm if (res == diff) { - return res; + return static_cast(res); } throw fmt::exception("Not a virtual memory pointer (%p)", real_ptr); @@ -166,36 +170,57 @@ namespace vm template<> struct cast_impl { - static u32 cast(const u32& addr, const char* loc) + static vm::addr_t cast(u32 addr, const char* loc) { - return addr; + return static_cast(addr); + } + + static vm::addr_t cast(u32 addr) + { + return static_cast(addr); } }; template<> struct cast_impl { - static u32 cast(const u64& addr, const char* loc) + static vm::addr_t cast(u64 addr, const char* loc) { - return fmt::narrow("Memory address out of range: 0x%llx%s", addr, loc); + return static_cast(fmt::narrow("Memory address out of range: 0x%llx%s", addr, loc)); + } + + static vm::addr_t cast(u64 addr) + { + return static_cast(fmt::narrow("Memory address out of range: 0x%llx", addr)); } }; template struct cast_impl> { - static u32 cast(const se_t& addr, const char* loc) + static vm::addr_t cast(const se_t& addr, const char* loc) { return cast_impl::cast(addr, loc); } + + static vm::addr_t cast(const se_t& addr) + { + return cast_impl::cast(addr); + } }; template - u32 cast(const T& addr, const char* loc) + vm::addr_t cast(const T& addr, const char* loc) { return cast_impl::cast(addr, loc); } + template + vm::addr_t cast(const T& addr) + { + return cast_impl::cast(addr); + } + // Convert specified PS3/PSV virtual memory address to a pointer for common access inline void* base(u32 addr) { diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index e30a8f3b04..f5cff7fc3b 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -25,12 +25,12 @@ namespace vm _ptr_base() = default; - constexpr _ptr_base(addr_type addr, const addr_tag_t&) + _ptr_base(vm::addr_t addr) : m_addr(addr) { } - constexpr addr_type addr() const + addr_type addr() const { return m_addr; } @@ -40,19 +40,21 @@ namespace vm this->m_addr = addr; } - static constexpr _ptr_base make(addr_type addr) + static _ptr_base make(addr_type addr) { - return{ addr, vm::addr }; + _ptr_base result; + result.m_addr = addr; + return result; } // Enable only the conversions which are originally possible between pointer types template::value>> operator _ptr_base() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } - explicit constexpr operator bool() const + explicit operator bool() const { return m_addr != 0; } @@ -61,34 +63,34 @@ namespace vm template> _ptr_base ptr(MT T2::*const mptr) const { - return{ vm::cast(m_addr, HERE) + get_offset(mptr), vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr)); } // Get vm pointer to a struct member with array subscription template, typename = if_comparable_t> _ptr_base ptr(MT T2::*const mptr, u32 index) const { - return{ vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index); } // Get vm reference to a struct member template> _ref_base ref(MT T2::*const mptr) const { - return{ vm::cast(m_addr, HERE) + get_offset(mptr), vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr)); } // Get vm reference to a struct member with array subscription template, typename = if_comparable_t> _ref_base ref(MT T2::*const mptr, u32 index) const { - return{ vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index); } // Get vm reference _ref_base ref() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } T* get_ptr() const @@ -136,22 +138,22 @@ namespace vm _ptr_base operator +() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } _ptr_base operator +(u32 count) const { - return{ vm::cast(m_addr, HERE) + count * SIZE_32(T), vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) + count * SIZE_32(T)); } _ptr_base operator -(u32 count) const { - return{ vm::cast(m_addr, HERE) - count * SIZE_32(T), vm::addr }; + return vm::cast(vm::cast(m_addr, HERE) - count * SIZE_32(T)); } friend _ptr_base operator +(u32 count, const _ptr_base& ptr) { - return{ vm::cast(ptr.m_addr, HERE) + count * SIZE_32(T), vm::addr }; + return vm::cast(vm::cast(ptr.m_addr, HERE) + count * SIZE_32(T)); } // Pointer difference operator @@ -163,9 +165,9 @@ namespace vm _ptr_base operator ++(int) { - const addr_type result = m_addr; + _ptr_base result = *this; m_addr = vm::cast(m_addr, HERE) + SIZE_32(T); - return{ result, vm::addr }; + return result; } _ptr_base& operator ++() @@ -176,9 +178,9 @@ namespace vm _ptr_base operator --(int) { - const addr_type result = m_addr; + _ptr_base result = m_addr; m_addr = vm::cast(m_addr, HERE) - SIZE_32(T); - return{ result, vm::addr }; + return result; } _ptr_base& operator --() @@ -210,12 +212,12 @@ namespace vm _ptr_base() = default; - constexpr _ptr_base(addr_type addr, const addr_tag_t&) + _ptr_base(vm::addr_t addr) : m_addr(addr) { } - constexpr addr_type addr() const + addr_type addr() const { return m_addr; } @@ -225,26 +227,28 @@ namespace vm m_addr = addr; } - static constexpr _ptr_base make(addr_type addr) + static _ptr_base make(addr_type addr) { - return{ addr, vm::addr }; + _ptr_base result; + result.m_addr = addr; + return result; } // Conversion to another function pointer template operator _ptr_base() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } - explicit constexpr operator bool() const + explicit operator bool() const { return m_addr != 0; } _ptr_base operator +() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } // Callback; defined in PPUCallback.h, passing context is mandatory @@ -305,14 +309,14 @@ namespace vm template*>(std::declval()))> inline _ptr_base> static_ptr_cast(const _ptr_base& other) { - return{ vm::cast(other.addr(), HERE), vm::addr }; + return vm::cast(other.addr(), HERE); } // Perform const_cast (for example, vm::cptr to vm::ptr) template*>(std::declval()))> inline _ptr_base> const_ptr_cast(const _ptr_base& other) { - return{ vm::cast(other.addr(), HERE), vm::addr }; + return vm::cast(other.addr(), HERE); } } @@ -343,93 +347,93 @@ namespace vm template*>(std::declval()))> inline _ptr_base> static_ptr_cast(const _ptr_base& other) { - return{ vm::cast(other.addr(), HERE), vm::addr }; + return vm::cast(other.addr(), HERE); } // Perform const_cast (for example, vm::cptr to vm::ptr) template*>(std::declval()))> inline _ptr_base> const_ptr_cast(const _ptr_base& other) { - return{ vm::cast(other.addr(), HERE), vm::addr }; + return vm::cast(other.addr(), HERE); } } struct null_t { template - constexpr operator _ptr_base() const + operator _ptr_base() const { - return _ptr_base{ 0, vm::addr }; + return _ptr_base{}; } template - friend constexpr bool operator ==(const null_t&, const _ptr_base& ptr) + friend bool operator ==(const null_t&, const _ptr_base& ptr) { return !ptr; } template - friend constexpr bool operator ==(const _ptr_base& ptr, const null_t&) + friend bool operator ==(const _ptr_base& ptr, const null_t&) { return !ptr; } template - friend constexpr bool operator !=(const null_t&, const _ptr_base& ptr) + friend bool operator !=(const null_t&, const _ptr_base& ptr) { return ptr.operator bool(); } template - friend constexpr bool operator !=(const _ptr_base& ptr, const null_t&) + friend bool operator !=(const _ptr_base& ptr, const null_t&) { return ptr.operator bool(); } template - friend constexpr bool operator <(const null_t&, const _ptr_base& ptr) + friend bool operator <(const null_t&, const _ptr_base& ptr) { return ptr.operator bool(); } template - friend constexpr bool operator <(const _ptr_base&, const null_t&) + friend bool operator <(const _ptr_base&, const null_t&) { return false; } template - friend constexpr bool operator <=(const null_t&, const _ptr_base&) + friend bool operator <=(const null_t&, const _ptr_base&) { return true; } template - friend constexpr bool operator <=(const _ptr_base& ptr, const null_t&) + friend bool operator <=(const _ptr_base& ptr, const null_t&) { return !ptr.operator bool(); } template - friend constexpr bool operator >(const null_t&, const _ptr_base&) + friend bool operator >(const null_t&, const _ptr_base&) { return false; } template - friend constexpr bool operator >(const _ptr_base& ptr, const null_t&) + friend bool operator >(const _ptr_base& ptr, const null_t&) { return ptr.operator bool(); } template - friend constexpr bool operator >=(const null_t&, const _ptr_base& ptr) + friend bool operator >=(const null_t&, const _ptr_base& ptr) { return !ptr; } template - friend constexpr bool operator >=(const _ptr_base&, const null_t&) + friend bool operator >=(const _ptr_base&, const null_t&) { return true; } diff --git a/rpcs3/Emu/Memory/vm_ref.h b/rpcs3/Emu/Memory/vm_ref.h index 216dff79fc..1d39be5362 100644 --- a/rpcs3/Emu/Memory/vm_ref.h +++ b/rpcs3/Emu/Memory/vm_ref.h @@ -2,9 +2,6 @@ namespace vm { - // Tag which allows to construct vm objects from the address value - static struct addr_tag_t {} constexpr addr{}; - template class _ptr_base; @@ -26,12 +23,12 @@ namespace vm _ref_base(const _ref_base&) = default; - constexpr _ref_base(addr_type addr, const addr_tag_t&) + _ref_base(vm::addr_t addr) : m_addr(addr) { } - constexpr addr_type addr() const + addr_type addr() const { return m_addr; } @@ -44,7 +41,7 @@ namespace vm // convert to vm pointer vm::_ptr_base ptr() const { - return{ vm::cast(m_addr, HERE), vm::addr }; + return vm::cast(m_addr, HERE); } operator simple_t() const diff --git a/rpcs3/Emu/Memory/vm_var.h b/rpcs3/Emu/Memory/vm_var.h index 4420d164b9..9b49aaa87e 100644 --- a/rpcs3/Emu/Memory/vm_var.h +++ b/rpcs3/Emu/Memory/vm_var.h @@ -7,9 +7,9 @@ namespace vm template struct page_allocator { - static inline u32 alloc(u32 size, u32 align) + static inline vm::addr_t alloc(u32 size, u32 align) { - return vm::alloc(size, Location, std::max(align, 4096)); + return vm::cast(vm::alloc(size, Location, std::max(align, 4096))); } static inline void dealloc(u32 addr, u32 size = 0) noexcept @@ -20,9 +20,9 @@ namespace vm struct stack_allocator { - static inline u32 alloc(u32 size, u32 align) + static inline vm::addr_t alloc(u32 size, u32 align) { - return vm::stack_push(size, align); + return vm::cast(vm::stack_push(size, align)); } static inline void dealloc(u32 addr, u32 size) noexcept @@ -39,7 +39,7 @@ namespace vm public: _var_base() - : pointer(A::alloc(SIZE_32(T), ALIGN_32(T)), vm::addr) + : pointer(A::alloc(SIZE_32(T), ALIGN_32(T))) { } @@ -71,7 +71,7 @@ namespace vm public: _var_base(u32 count) - : pointer(A::alloc(SIZE_32(T) * count, ALIGN_32(T)), vm::addr) + : pointer(A::alloc(SIZE_32(T) * count, ALIGN_32(T))) , m_size(SIZE_32(T) * count) { } diff --git a/rpcs3/Emu/Memory/wait_engine.cpp b/rpcs3/Emu/Memory/wait_engine.cpp index ffe441e39e..ed6530a12e 100644 --- a/rpcs3/Emu/Memory/wait_engine.cpp +++ b/rpcs3/Emu/Memory/wait_engine.cpp @@ -6,98 +6,70 @@ #include "Utilities/Thread.h" #include "Utilities/SharedMutex.h" -extern std::condition_variable& get_current_thread_cv(); -extern std::mutex& get_current_thread_mutex(); +#include namespace vm { static shared_mutex s_mutex; - static std::unordered_set s_waiters(256); + static std::unordered_set> s_waiters(256); - bool waiter::try_notify() + void waiter_base::initialize(u32 addr, u32 size) { - { - std::lock_guard lock(*mutex); + EXPECTS(addr && (size & (~size + 1)) == size && (addr & (size - 1)) == 0); - try - { - // Test predicate - if (!pred || !pred()) - { - return false; - } - - // Clear predicate - pred = nullptr; - } - catch (...) - { - // Capture any exception possibly thrown by predicate - pred = [exception = std::current_exception()]() -> bool - { - // New predicate will throw the captured exception from the original thread - std::rethrow_exception(exception); - }; - } - - // Set addr and mask to invalid values to prevent further polling - addr = 0; - mask = ~0; - } - - // Signal thread - cond->notify_one(); - return true; - } - - waiter::~waiter() - { - } - - waiter_lock::waiter_lock(u32 addr, u32 size) - : m_lock(get_current_thread_mutex(), std::defer_lock) - { - Expects(addr && (size & (~size + 1)) == size && (addr & (size - 1)) == 0); - - m_waiter.mutex = m_lock.mutex(); - m_waiter.cond = &get_current_thread_cv(); - m_waiter.addr = addr; - m_waiter.mask = ~(size - 1); + this->addr = addr; + this->mask = ~(size - 1); + this->thread = thread_ctrl::get_current(); { writer_lock lock(s_mutex); - - s_waiters.emplace(&m_waiter); + s_waiters.emplace(this); } - - m_lock.lock(); + + // Wait until thread == nullptr + thread_lock(), thread_ctrl::wait(WRAP_EXPR(!thread || test())); } - void waiter_lock::wait() + bool waiter_base::try_notify() { - // If another thread successfully called pred(), it must be set to null - while (m_waiter.pred) + const auto _t = atomic_storage::load(thread); + + if (UNLIKELY(!_t)) { - // If pred() called by another thread threw an exception, it'll be rethrown - if (m_waiter.pred()) - { - return; - } - - CHECK_EMU_STATUS; - - m_waiter.cond->wait(m_lock); + // Return if thread not found + return false; } + + // Lock the thread + _t->lock(); + + try + { + // Test predicate + if (UNLIKELY(!thread || !test())) + { + _t->unlock(); + return false; + } + } + catch (...) + { + // Capture any exception thrown by the predicate + _t->set_exception(std::current_exception()); + } + + // Signal the thread with nullptr + atomic_storage::store(thread, nullptr); + _t->unlock(); + _t->notify(); + return true; } - waiter_lock::~waiter_lock() + waiter_base::~waiter_base() { - if (m_lock) m_lock.unlock(); - writer_lock lock(s_mutex); - - s_waiters.erase(&m_waiter); + s_waiters.erase(this); } void notify_at(u32 addr, u32 size) @@ -114,44 +86,37 @@ namespace vm } } - static bool notify_all() + // Return amount of threads which are not notified + static std::size_t notify_all() { reader_lock lock(s_mutex); - std::size_t waiters = 0; std::size_t signaled = 0; for (const auto _w : s_waiters) { - if (_w->addr) + if (_w->try_notify()) { - waiters++; - - if (_w->try_notify()) - { - signaled++; - } + signaled++; } } - // return true if waiter list is empty or all available waiters were signaled - return waiters == signaled; + return s_waiters.size() - signaled; } void start() { - // start notification thread - thread_ctrl::spawn("vm::start thread", []() + thread_ctrl::spawn("vm::wait", []() { while (!Emu.IsStopped()) { - // poll waiters periodically (TODO) - while (!notify_all() && !Emu.IsPaused()) + // Poll waiters periodically (TODO) + while (notify_all() && !Emu.IsPaused()) { - std::this_thread::yield(); + thread_ctrl::sleep(50); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + thread_ctrl::sleep(1000); } }); } diff --git a/rpcs3/Emu/Memory/wait_engine.h b/rpcs3/Emu/Memory/wait_engine.h index 433884aee7..e674ca7250 100644 --- a/rpcs3/Emu/Memory/wait_engine.h +++ b/rpcs3/Emu/Memory/wait_engine.h @@ -1,61 +1,50 @@ #pragma once -#include -#include -#include +#include "Utilities/types.h" +#include "Utilities/Macro.h" -class named_thread; +class thread_ctrl; namespace vm { - using mutex_t = std::mutex; - using cond_t = std::condition_variable; - - struct waiter + struct waiter_base { u32 addr; u32 mask; - mutex_t* mutex; - cond_t* cond; - - std::function pred; - - ~waiter(); + thread_ctrl* thread{}; + void initialize(u32 addr, u32 size); bool try_notify(); + + protected: + ~waiter_base(); + + virtual bool test() = 0; }; - class waiter_lock + // Wait until pred() returns true, addr must be aligned to size which must be a power of 2. + // It's possible for pred() to be called from any thread once the waiter is registered. + template + auto wait_op(u32 addr, u32 size, F&& pred) -> decltype(static_cast(pred())) { - waiter m_waiter; - std::unique_lock m_lock; + if (LIKELY(pred())) return; - public: - waiter_lock(u32 addr, u32 size); - - waiter* operator ->() + struct waiter : waiter_base { - return &m_waiter; - } + std::conditional_t, F&&> func; - void wait(); + waiter(F&& func) + : func(std::forward(func)) + { + } - ~waiter_lock(); - }; + bool test() override + { + return func(); + } + }; - // Wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread - template - auto wait_op(u32 addr, u32 size, F&& pred, Args&&... args) -> decltype(static_cast(pred(args...))) - { - // Return immediately if condition passed (optimistic case) - if (pred(args...)) return; - - waiter_lock lock(addr, size); - - // Initialize predicate - lock->pred = WRAP_EXPR(pred(args...)); - - lock.wait(); + waiter(std::forward(pred)).initialize(addr, size); } // Notify waiters on specific addr, addr must be aligned to size which must be a power of 2 diff --git a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp index 743be6817a..14c969b960 100644 --- a/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryFragmentProgram.cpp @@ -4,9 +4,11 @@ #include "CgBinaryProgram.h" #include "Emu/RSX/RSXFragmentProgram.h" +#include + void CgBinaryDisasm::AddCodeAsm(const std::string& code) { - Expects(m_opcode < 70); + EXPECTS(m_opcode < 70); std::string op_name = ""; if (dst.dest_reg == 63) @@ -223,7 +225,7 @@ void CgBinaryDisasm::TaskFP() { m_size = 0; u32* data = (u32*)&m_buffer[m_offset]; - Expects((m_buffer_size - m_offset) % sizeof(u32) == 0); + EXPECTS((m_buffer_size - m_offset) % sizeof(u32) == 0); for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { data[i] = se_storage::swap(data[i]); // WTF, cannot use be_t<> there? @@ -471,7 +473,7 @@ void CgBinaryDisasm::TaskFP() break; } - Ensures(m_step % sizeof(u32) == 0); + ENSURES(m_step % sizeof(u32) == 0); data += m_step / sizeof(u32); } -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/CgBinaryProgram.h b/rpcs3/Emu/RSX/CgBinaryProgram.h index 566468ecea..0b1752347c 100644 --- a/rpcs3/Emu/RSX/CgBinaryProgram.h +++ b/rpcs3/Emu/RSX/CgBinaryProgram.h @@ -373,7 +373,7 @@ public: m_offset = prog.ucode; u32* vdata = (u32*)&m_buffer[m_offset]; - Ensures((m_buffer_size - m_offset) % sizeof(u32) == 0); + ENSURES((m_buffer_size - m_offset) % sizeof(u32) == 0); for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++) { vdata[i] = se_storage::swap(vdata[i]); // WTF, cannot use be_t<> there? diff --git a/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp b/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp index a318201274..a6f03ffffa 100644 --- a/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp +++ b/rpcs3/Emu/RSX/CgBinaryVertexProgram.cpp @@ -6,13 +6,13 @@ void CgBinaryDisasm::AddScaCodeDisasm(const std::string& code) { - Expects(m_sca_opcode < 21); + EXPECTS(m_sca_opcode < 21); m_arb_shader += rsx_vp_sca_op_names[m_sca_opcode] + code + " "; } void CgBinaryDisasm::AddVecCodeDisasm(const std::string& code) { - Expects(m_vec_opcode < 26); + EXPECTS(m_vec_opcode < 26); m_arb_shader += rsx_vp_vec_op_names[m_vec_opcode] + code + " "; } @@ -448,4 +448,4 @@ void CgBinaryDisasm::TaskVP() } m_arb_shader += "END\n"; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/Common/BufferUtils.cpp b/rpcs3/Emu/RSX/Common/BufferUtils.cpp index 05c4a8acdc..9e8f338f48 100644 --- a/rpcs3/Emu/RSX/Common/BufferUtils.cpp +++ b/rpcs3/Emu/RSX/Common/BufferUtils.cpp @@ -48,7 +48,7 @@ namespace void write_vertex_array_data_to_buffer(gsl::span raw_dst_span, const gsl::byte *src_ptr, u32 first, u32 count, rsx::vertex_base_type type, u32 vector_element_count, u32 attribute_src_stride, u8 dst_stride) { - Expects(vector_element_count > 0); + EXPECTS(vector_element_count > 0); switch (type) { @@ -98,7 +98,7 @@ std::tuple upload_untouched(gsl::span> src, gsl::span T min_index = -1; T max_index = 0; - Expects(dst.size_bytes() >= src.size_bytes()); + EXPECTS(dst.size_bytes() >= src.size_bytes()); size_t dst_idx = 0; for (T index : src) @@ -124,7 +124,7 @@ std::tuple expand_indexed_triangle_fan(gsl::span> src, gs T min_index = -1; T max_index = 0; - Expects(dst.size() >= 3 * (src.size() - 2)); + EXPECTS(dst.size() >= 3 * (src.size() - 2)); const T index0 = src[0]; if (!is_primitive_restart_enabled || index0 != -1) // Cut @@ -174,7 +174,7 @@ std::tuple expand_indexed_quads(gsl::span> src, gsl::span T min_index = -1; T max_index = 0; - Expects(4 * dst.size_bytes() >= 6 * src.size_bytes()); + EXPECTS(4 * dst.size_bytes() >= 6 * src.size_bytes()); size_t dst_idx = 0; while (!src.empty()) @@ -353,7 +353,7 @@ std::tuple write_index_array_data_to_buffer_impl(gsl::span(get_index_type_size(type)); - Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); + EXPECTS(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE]; u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX]; @@ -363,7 +363,7 @@ std::tuple write_index_array_data_to_buffer_impl(gsl::span &range = first_count_arguments[i]; const std::tuple &next_range = first_count_arguments[i + 1]; - Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); } u32 first = std::get<0>(first_count_arguments.front()); u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; @@ -415,7 +415,7 @@ std::tuple write_index_array_data_to_buffer_untouched(gsl::span &range = first_count_arguments[i]; const std::tuple &next_range = first_count_arguments[i + 1]; - Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); } u32 first = std::get<0>(first_count_arguments.front()); u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; @@ -438,7 +438,7 @@ std::tuple write_index_array_data_to_buffer_untouched(gsl::span &range = first_count_arguments[i]; const std::tuple &next_range = first_count_arguments[i + 1]; - Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); + EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range)); } u32 first = std::get<0>(first_count_arguments.front()); u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first; diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index b0b9e76057..1c905301e6 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -4,6 +4,8 @@ #include "FragmentProgramDecompiler.h" +#include + FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) : m_prog(prog), m_size(size), @@ -522,21 +524,21 @@ std::string FragmentProgramDecompiler::Decompile() while (true) { - for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); - finded != m_end_offsets.end(); - finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size)) + for (auto found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); + found != m_end_offsets.end(); + found = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size)) { - m_end_offsets.erase(finded); + m_end_offsets.erase(found); m_code_level--; AddCode("}"); m_loop_count--; } - for (auto finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size); - finded != m_else_offsets.end(); - finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size)) + for (auto found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size); + found != m_else_offsets.end(); + found = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size)) { - m_else_offsets.erase(finded); + m_else_offsets.erase(found); m_code_level--; AddCode("}"); AddCode("else"); @@ -644,7 +646,7 @@ std::string FragmentProgramDecompiler::Decompile() if (dst.end) break; - Ensures(m_offset % sizeof(u32) == 0); + ENSURES(m_offset % sizeof(u32) == 0); data += m_offset / sizeof(u32); } diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index 604a4ecf54..e76983b481 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -227,7 +227,7 @@ public: 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1); - Expects(dst_buffer.size_bytes() >= gsl::narrow(I->second.FragmentConstantOffsetCache.size()) * 16); + EXPECTS(dst_buffer.size_bytes() >= gsl::narrow(I->second.FragmentConstantOffsetCache.size()) * 16); size_t offset = 0; for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache) diff --git a/rpcs3/Emu/RSX/Common/ShaderParam.h b/rpcs3/Emu/RSX/Common/ShaderParam.h index 747f45bdcf..d667369565 100644 --- a/rpcs3/Emu/RSX/Common/ShaderParam.h +++ b/rpcs3/Emu/RSX/Common/ShaderParam.h @@ -152,7 +152,7 @@ public: { auto var_blocks = fmt::split(var, { "." }); - Expects(var_blocks.size() != 0); + EXPECTS(var_blocks.size() != 0); name = var_blocks[0]; diff --git a/rpcs3/Emu/RSX/Common/TextureUtils.cpp b/rpcs3/Emu/RSX/Common/TextureUtils.cpp index f39c06601b..960512b5af 100644 --- a/rpcs3/Emu/RSX/Common/TextureUtils.cpp +++ b/rpcs3/Emu/RSX/Common/TextureUtils.cpp @@ -21,7 +21,7 @@ namespace constexpr void copy(gsl::span dst, gsl::span src) { static_assert(std::is_convertible::value, "Cannot convert source and destination span type."); - Expects(dst.size() == src.size()); + EXPECTS(dst.size() == src.size()); std::copy(src.begin(), src.end(), dst.begin()); } diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index 39f72c2674..fed540d080 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -3,6 +3,8 @@ #include "VertexProgramDecompiler.h" +#include + std::string VertexProgramDecompiler::GetMask(bool is_sca) { std::string ret; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp index c987400078..fdaf42161f 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12GSRender.h" #include "d3dx12.h" @@ -78,7 +78,7 @@ std::vector D3D12GSRender::upload_vertex_attrib u32 vertex_count = get_vertex_count(vertex_ranges); size_t offset_in_vertex_buffers_buffer = 0; u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; - Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); + EXPECTS(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0); for (int index = 0; index < rsx::limits::vertex_count; ++index) { @@ -350,7 +350,7 @@ std::tuple> D3D12GSRe return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list)); } - Expects(draw_command == rsx::draw_command::indexed); + EXPECTS(draw_command == rsx::draw_command::indexed); // Index count size_t index_count = get_index_count(draw_mode, gsl::narrow(get_vertex_count(first_count_commands))); diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp index d5721cb1ed..29a7ddfc79 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12CommonDecompiler.h" std::string getFloatTypeNameImp(size_t elementCount) diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp index 03478f5640..fe42ff7be9 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Formats.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12Formats.h" #include "D3D12Utils.h" #include "Emu/RSX/GCM.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp index 1eba50945c..1d6d2f26fc 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12FragmentProgramDecompiler.h" #include "D3D12CommonDecompiler.h" #include "Emu/Memory/Memory.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index c4f2e66e17..8f71e92e44 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "Utilities/Config.h" #include "D3D12GSRender.h" #include @@ -43,13 +43,13 @@ HMODULE D3DCompiler; void loadD3D12FunctionPointers() { - ASSERT(D3D12Module = LoadLibrary(L"d3d12.dll")); + VERIFY(D3D12Module = LoadLibrary(L"d3d12.dll")); wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice"); wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface"); wrapD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)GetProcAddress(D3D12Module, "D3D12SerializeRootSignature"); - ASSERT(D3D11Module = LoadLibrary(L"d3d11.dll")); + VERIFY(D3D11Module = LoadLibrary(L"d3d11.dll")); wrapD3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)GetProcAddress(D3D11Module, "D3D11On12CreateDevice"); - ASSERT(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll")); + VERIFY(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll")); wrapD3DCompile = (pD3DCompile)GetProcAddress(D3DCompiler, "D3DCompile"); } @@ -486,7 +486,7 @@ void D3D12GSRender::flip(int buffer) if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) { resource_storage &storage = get_current_resource_storage(); - ASSERT(storage.ram_framebuffer == nullptr); + VERIFY(storage.ram_framebuffer == nullptr); size_t w = 0, h = 0, row_pitch = 0; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.cpp b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.cpp index c97e8e47f8..38de09d3c6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12MemoryHelpers.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h index 2de6ee913b..d9d58adc38 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12MemoryHelpers.h @@ -3,6 +3,7 @@ #include "d3dx12.h" #include "../Common/ring_buffer_helper.h" #include +#include struct d3d12_data_heap : public data_heap { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Overlay.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Overlay.cpp index d82978e04d..1df51b57e6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Overlay.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Overlay.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12GSRender.h" #include #include diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp index 2ba3d0e5ec..2957cf514f 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "Utilities/Config.h" #include "D3D12PipelineState.h" #include "D3D12GSRender.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index 1370d91f30..0644e2dff6 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "Utilities/Config.h" #include "D3D12RenderTargetSets.h" #include "Emu/Memory/Memory.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index 26ca992e45..17013b3c97 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12GSRender.h" #include "d3dx12.h" #include "../Common/TextureUtils.h" diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp index e6cd73157a..9e7645df06 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12GSRender.h" #include "d3dx12.h" #define STRINGIFY(x) #x diff --git a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp index 2688e08930..f49a409e40 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp @@ -1,6 +1,6 @@ +#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" -#ifdef _MSC_VER #include "D3D12VertexProgramDecompiler.h" #include "D3D12CommonDecompiler.h" #include "Emu/System.h" diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index 36d7b638b9..ccf1c35880 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -4,6 +4,8 @@ #include "GLVertexProgram.h" #include "GLCommonDecompiler.h" +#include + std::string GLVertexDecompilerThread::getFloatTypeName(size_t elementCount) { return getFloatTypeNameImpl(elementCount); diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 370befbbc2..886179031e 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -12,6 +12,8 @@ #include "Utilities/GSL.h" #include "Utilities/StrUtil.h" +#include + #define CMD_DEBUG 0 cfg::bool_entry g_cfg_rsx_write_color_buffers(cfg::root.video, "Write Color Buffers"); @@ -40,7 +42,7 @@ namespace rsx void shaders_cache::load(const std::string &path, shader_language lang) { - const std::string lang_name = bijective_find(lang, ""); + const std::string lang_name(::unveil::get(lang)); auto extract_hash = [](const std::string &string) { @@ -174,7 +176,7 @@ namespace rsx } throw EXCEPTION("Wrong vector size"); case vertex_base_type::cmp: return sizeof(u16) * 4; - case vertex_base_type::ub256: Expects(size == 4); return sizeof(u8) * 4; + case vertex_base_type::ub256: EXPECTS(size == 4); return sizeof(u8) * 4; } throw EXCEPTION("RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type); } @@ -561,7 +563,7 @@ namespace rsx } else { - Expects(0); + EXPECTS(0); //std::lock_guard lock{ m_mtx_task }; //internal_task_entry &front = m_internal_tasks.front(); diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 4f84b5a716..9b2afa5bb9 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "GCM.h" #include "RSXTexture.h" #include "RSXVertexProgram.h" @@ -52,13 +53,18 @@ namespace rsx } template<> -struct bijective +struct unveil { - static constexpr bijective_pair map[] + static inline const char* get(rsx::shader_language in) { - { rsx::shader_language::glsl, "glsl" }, - { rsx::shader_language::hlsl, "hlsl" }, - }; + switch (in) + { + case rsx::shader_language::glsl: return "glsl"; + case rsx::shader_language::hlsl: return "hlsl"; + } + + return ""; + } }; namespace rsx diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 0ea6ddb38f..73919ceb96 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -99,7 +99,7 @@ namespace vk size_t color_format_idx = 0; size_t depth_format_idx = 0; - Expects(color_count < 5); + EXPECTS(color_count < 5); switch (color_format) { diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 968589bc75..96e8c224a0 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -7,6 +7,8 @@ #include "rsx_utils.h" #include "Emu/Cell/PPUCallback.h" +#include + cfg::map_entry g_cfg_rsx_frame_limit(cfg::root.video, "Frame limit", { { "Off", 0. }, @@ -43,7 +45,7 @@ namespace rsx if (Emu.IsStopped()) break; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(1ms); } } @@ -253,7 +255,7 @@ namespace rsx return; } - vm::ps3::ptr result = { get_address(offset, location), vm::addr }; + vm::ps3::ptr result = vm::cast(get_address(offset, location)); result->timer = rsx->timestamp(); diff --git a/rpcs3/Emu/RSX/rsx_utils.h b/rpcs3/Emu/RSX/rsx_utils.h index 989c4470a5..d02b63218c 100644 --- a/rpcs3/Emu/RSX/rsx_utils.h +++ b/rpcs3/Emu/RSX/rsx_utils.h @@ -5,8 +5,6 @@ extern "C" #include } -#include - namespace rsx { template @@ -26,6 +24,12 @@ namespace rsx } } + // + static inline u32 ceil_log2(u32 value) + { + return value <= 1 ? 0 : ::cntlz32((value - 1) << 1) ^ 31; + } + /* Note: What the ps3 calls swizzling in this case is actually z-ordering / morton ordering of pixels * - Input can be swizzled or linear, bool flag handles conversion to and from * - It will handle any width and height that are a power of 2, square or non square @@ -34,8 +38,8 @@ namespace rsx template void convert_linear_swizzle(void* input_pixels, void* output_pixels, u16 width, u16 height, bool input_is_swizzled) { - u16 log2width = ::narrow(ceil(std::log2(width))); - u16 log2height = ::narrow(ceil(std::log2(height))); + u32 log2width = ceil_log2(width); + u32 log2height = ceil_log2(height); // Max mask possible for square texture u32 x_mask = 0x55555555; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index e49240a652..253824b2de 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -9,7 +9,9 @@ #include "Emu/Cell/PPUCallback.h" #include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/SPUThread.h" +#include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/lv2/sys_sync.h" +#include "Emu/PSP2/ARMv7Thread.h" #include "Emu/IdManager.h" #include "Emu/RSX/GSRender.h" @@ -21,6 +23,8 @@ #include "../Crypto/unself.h" +#include + cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot"); cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes"); @@ -31,6 +35,8 @@ extern cfg::string_entry g_cfg_vfs_app_home; extern atomic_t g_thread_count; +extern atomic_t g_ppu_core[2]; + extern u64 get_system_time(); fs::file g_tty; @@ -60,6 +66,9 @@ void Emulator::Init() idm::init(); fxm::init(); + g_ppu_core[0] = 0; + g_ppu_core[1] = 0; + // Reset defaults, cache them cfg::root.from_default(); g_cfg_defaults = cfg::root.to_string(); @@ -252,10 +261,10 @@ void Emulator::Load() { LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path); - LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", bijective_find(ppu_exec, "???")); - LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", bijective_find(ppu_prx, "???")); - LOG_WARNING(LOADER, "** spu_exec_loader -> %s", bijective_find(spu_exec, "???")); - LOG_WARNING(LOADER, "** arm_exec_loader -> %s", bijective_find(arm_exec, "???")); + LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error()); + LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error()); + LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error()); + LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error()); return; } @@ -294,11 +303,11 @@ void Emulator::Run() m_pause_amend_time = 0; m_status = Running; - for (auto& thread : get_all_cpu_threads()) + idm::select([](u32, cpu_thread& cpu) { - thread->state -= cpu_state::stop; - thread->lock_notify(); - } + cpu.state -= cpu_state::stop; + cpu->lock_notify(); + }); SendDbgCommand(DID_STARTED_EMU); } @@ -323,10 +332,10 @@ bool Emulator::Pause() SendDbgCommand(DID_PAUSE_EMU); - for (auto& thread : get_all_cpu_threads()) + idm::select([](u32, cpu_thread& cpu) { - thread->state += cpu_state::dbg_global_pause; - } + cpu.state += cpu_state::dbg_global_pause; + }); SendDbgCommand(DID_PAUSED_EMU); @@ -357,11 +366,11 @@ void Emulator::Resume() SendDbgCommand(DID_RESUME_EMU); - for (auto& thread : get_all_cpu_threads()) + idm::select([](u32, cpu_thread& cpu) { - thread->state -= cpu_state::dbg_global_pause; - thread->lock_notify(); - } + cpu.state -= cpu_state::dbg_global_pause; + cpu->lock_notify(); + }); rpcs3::on_resume()(); @@ -383,11 +392,11 @@ void Emulator::Stop() { LV2_LOCK; - for (auto& thread : get_all_cpu_threads()) + idm::select([](u32, cpu_thread& cpu) { - thread->state += cpu_state::dbg_global_stop; - thread->lock_notify(); - } + cpu.state += cpu_state::dbg_global_stop; + cpu->lock_notify(); + }); } LOG_NOTICE(GENERAL, "All threads signaled..."); @@ -424,16 +433,3 @@ void Emulator::Stop() } Emulator Emu; - -DECLARE(idm::g_map); -DECLARE(idm::g_id); -DECLARE(idm::g_mutex); - -DECLARE(fxm::g_map); -DECLARE(fxm::g_mutex); - -#ifndef _MSC_VER -constexpr DECLARE(bijective::map); -constexpr DECLARE(bijective<_log::level, const char*>::map); -constexpr DECLARE(bijective::map); -#endif diff --git a/rpcs3/Gui/ConLogFrame.cpp b/rpcs3/Gui/ConLogFrame.cpp index c8296bf0b1..f363c0e2e9 100644 --- a/rpcs3/Gui/ConLogFrame.cpp +++ b/rpcs3/Gui/ConLogFrame.cpp @@ -2,6 +2,8 @@ #include "stdafx_gui.h" #include "Gui/ConLogFrame.h" +#include + enum { id_log_copy, // Copy log to ClipBoard @@ -210,19 +212,19 @@ void LogFrame::OnTimer(wxTimerEvent& event) if (text[pos + 2] == ' ') { - _log::level level; + logs::level level; wxColour color; switch (text[pos + 1].GetValue()) { - case 'A': level = _log::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan - case 'F': level = _log::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia - case 'E': level = _log::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red - case 'U': level = _log::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange - case 'S': level = _log::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green - case 'W': level = _log::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow - case '!': level = _log::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White - case 'T': level = _log::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray + case 'A': level = logs::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan + case 'F': level = logs::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia + case 'E': level = logs::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red + case 'U': level = logs::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange + case 'S': level = logs::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green + case 'W': level = logs::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow + case '!': level = logs::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White + case 'T': level = logs::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray default: continue; } diff --git a/rpcs3/Gui/ConLogFrame.h b/rpcs3/Gui/ConLogFrame.h index 316cd37a39..10ae45834a 100644 --- a/rpcs3/Gui/ConLogFrame.h +++ b/rpcs3/Gui/ConLogFrame.h @@ -5,7 +5,7 @@ class LogFrame : public wxPanel fs::file m_log_file; fs::file m_tty_file; - _log::level m_level{ _log::level::always }; // current log level + logs::level m_level{ logs::level::always }; // current log level wxColour m_color{ 0, 255, 255 }; // current log color wxAuiNotebook m_tabs; @@ -20,7 +20,7 @@ class LogFrame : public wxPanel YAML::Node m_cfg_level; YAML::Node m_cfg_tty; - _log::level get_cfg_level() const { return static_cast<_log::level>(m_cfg_level.as(4)); } + logs::level get_cfg_level() const { return static_cast(m_cfg_level.as(4)); } bool get_cfg_tty() const { return m_cfg_tty.as(true); } public: diff --git a/rpcs3/Gui/GameViewer.cpp b/rpcs3/Gui/GameViewer.cpp index 283725b2f7..46d2e6a2fa 100644 --- a/rpcs3/Gui/GameViewer.cpp +++ b/rpcs3/Gui/GameViewer.cpp @@ -6,6 +6,8 @@ #include "Loader/PSF.h" #include "SettingsDialog.h" +#include + static const std::string m_class_name = "GameViewer"; // Auxiliary classes diff --git a/rpcs3/Gui/InterpreterDisAsm.cpp b/rpcs3/Gui/InterpreterDisAsm.cpp index e28e1c60d9..c593d9e376 100644 --- a/rpcs3/Gui/InterpreterDisAsm.cpp +++ b/rpcs3/Gui/InterpreterDisAsm.cpp @@ -2,15 +2,17 @@ #include "stdafx_gui.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include "Emu/IdManager.h" #include "rpcs3.h" #include "InterpreterDisAsm.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/SPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/Cell/RawSPUThread.h" +#include "Emu/PSP2/ARMv7Thread.h" #include "Emu/Cell/PPUDisAsm.h" #include "Emu/Cell/SPUDisAsm.h" -#include "Emu/ARMv7/ARMv7DisAsm.h" +#include "Emu/PSP2/ARMv7DisAsm.h" #include "InstructionEditor.h" #include "RegisterEditor.h" @@ -23,7 +25,7 @@ u32 InterpreterDisAsmFrame::GetPc() const { switch (cpu->type) { - case cpu_type::ppu: return static_cast(cpu)->PC; + case cpu_type::ppu: return static_cast(cpu)->pc; case cpu_type::spu: return static_cast(cpu)->pc; case cpu_type::arm: return static_cast(cpu)->PC; } @@ -121,10 +123,10 @@ void InterpreterDisAsmFrame::UpdateUnitList() m_choice_units->Freeze(); m_choice_units->Clear(); - for (auto& t : get_all_cpu_threads()) + idm::select([&](u32, cpu_thread& cpu) { - m_choice_units->Append(t->get_name(), t.get()); - } + m_choice_units->Append(cpu.get_name(), &cpu); + }); m_choice_units->Thaw(); } @@ -437,7 +439,7 @@ void InterpreterDisAsmFrame::DoRun(wxCommandEvent& WXUNUSED(event)) if (cpu && cpu->state.test(cpu_state_pause)) { cpu->state -= cpu_state::dbg_pause; - cpu->lock_notify(); + (*cpu)->lock_notify(); } } @@ -459,7 +461,7 @@ void InterpreterDisAsmFrame::DoStep(wxCommandEvent& WXUNUSED(event)) return state.test_and_reset(cpu_state::dbg_pause); })) { - cpu->lock_notify(); + (*cpu)->lock_notify(); } } } diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index 7e139cb9b2..df743ed1f4 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -80,221 +80,166 @@ void KernelExplorer::Update() // TODO: FileSystem // Semaphores - const auto sema_map = idm::get_map(); - - if (sema_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Semaphores (%zu)", sema_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Semaphores (%zu)", count)); - for (const auto& data : sema_map) + idm::select([&](u32 id, lv2_sema_t& sema) { - const auto& sema = *data.second; - - m_tree->AppendItem(node, fmt::format("Semaphore: ID = 0x%08x '%s', Count = %d, Max Count = %d, Waiters = %#zu", data.first, + m_tree->AppendItem(node, fmt::format("Semaphore: ID = 0x%08x '%s', Count = %d, Max Count = %d, Waiters = %#zu", id, &name64(sema.name), sema.value.load(), sema.max, sema.sq.size())); - } + }); } // Mutexes - const auto mutex_map = idm::get_map(); - - if (mutex_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Mutexes (%zu)", mutex_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Mutexes (%zu)", count)); - for (const auto& data : mutex_map) + idm::select([&](u32 id, lv2_mutex_t& mutex) { - const auto& mutex = *data.second; - - m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x '%s'", data.first, + m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x '%s'", id, &name64(mutex.name))); - } + }); } // Lightweight Mutexes - const auto lwm_map = idm::get_map(); - - if (lwm_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Mutexes (%zu)", lwm_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Mutexes (%zu)", count)); - for (const auto& data : lwm_map) + idm::select([&](u32 id, lv2_lwmutex_t& lwm) { - const auto& lwm = *data.second; - - m_tree->AppendItem(node, fmt::format("LWMutex: ID = 0x%08x '%s'", data.first, + m_tree->AppendItem(node, fmt::format("LWMutex: ID = 0x%08x '%s'", id, &name64(lwm.name))); - } + }); } // Condition Variables - const auto cond_map = idm::get_map(); - - if (cond_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Condition Variables (%zu)", cond_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Condition Variables (%zu)", count)); - for (const auto& data : cond_map) + idm::select([&](u32 id, lv2_cond_t& cond) { - const auto& cond = *data.second; - - m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x '%s'", data.first, + m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x '%s'", id, &name64(cond.name))); - } + }); } // Lightweight Condition Variables - const auto lwc_map = idm::get_map(); - - if (lwc_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Condition Variables (%zu)", lwc_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Lightweight Condition Variables (%zu)", count)); - for (const auto& data : lwc_map) + idm::select([&](u32 id, lv2_lwcond_t& lwc) { - const auto& lwc = *data.second; - - m_tree->AppendItem(node, fmt::format("LWCond: ID = 0x%08x '%s'", data.first, + m_tree->AppendItem(node, fmt::format("LWCond: ID = 0x%08x '%s'", id, &name64(lwc.name))); - } + }); } // Event Queues - const auto eq_map = idm::get_map(); - - if (eq_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Event Queues (%zu)", eq_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Event Queues (%zu)", count)); - for (const auto& data : eq_map) + idm::select([&](u32 id, lv2_event_queue_t& eq) { - const auto& eq = *data.second; - - m_tree->AppendItem(node, fmt::format("Event Queue: ID = 0x%08x '%s', %s, Key = %#llx, Events = %zu/%d, Waiters = %zu", data.first, + m_tree->AppendItem(node, fmt::format("Event Queue: ID = 0x%08x '%s', %s, Key = %#llx, Events = %zu/%d, Waiters = %zu", id, &name64(eq.name), eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.ipc_key, eq.events(), eq.size, eq.waiters())); - } + }); } // Event Ports - const auto ep_map = idm::get_map(); - - if (ep_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Event Ports (%zu)", ep_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Event Ports (%zu)", count)); - for (const auto& data : ep_map) + idm::select([&](u32 id, lv2_event_port_t& ep) { - const auto& ep = *data.second; - - m_tree->AppendItem(node, fmt::format("Event Port: ID = 0x%08x, Name = %#llx", data.first, + m_tree->AppendItem(node, fmt::format("Event Port: ID = 0x%08x, Name = %#llx", id, ep.name)); - } + }); } // Event Flags - const auto ef_map = idm::get_map(); - - if (ef_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Event Flags (%zu)", ef_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Event Flags (%zu)", count)); - for (const auto& data : ef_map) + idm::select([&](u32 id, lv2_event_flag_t& ef) { - const auto& ef = *data.second; - - m_tree->AppendItem(node, fmt::format("Event Flag: ID = 0x%08x '%s', Type = 0x%x, Pattern = 0x%llx", data.first, &name64(ef.name), ef.type, ef.pattern.load())); - } + m_tree->AppendItem(node, fmt::format("Event Flag: ID = 0x%08x '%s', Type = 0x%x, Pattern = 0x%llx", id, + &name64(ef.name), ef.type, ef.pattern.load())); + }); } // Reader/writer Locks - const auto rwlock_map = idm::get_map(); - - if (rwlock_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Reader/writer Locks (%zu)", rwlock_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Reader/writer Locks (%zu)", count)); - for (const auto& data : rwlock_map) + idm::select([&](u32 id, lv2_rwlock_t&) { - const auto& rwlock = *data.second; - - m_tree->AppendItem(node, fmt::format("RWLock: ID = 0x%08x", data.first)); - } + m_tree->AppendItem(node, fmt::format("RWLock: ID = 0x%08x", id)); + }); } // PRX Libraries - const auto prx_map = idm::get_map(); - - if (prx_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("PRX Libraries (%zu)", prx_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("PRX Libraries (%zu)", count)); - for (const auto& data : prx_map) + idm::select([&](u32 id, lv2_prx_t&) { - const auto& prx = *data.second; - - m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x", data.first)); - } + m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x", id)); + }); } // Memory Containers - const auto ct_map = idm::get_map(); - - if (ct_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Memory Containers (%zu)", ct_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Memory Containers (%zu)", count)); - for (const auto& data : ct_map) + idm::select([&](u32 id, lv2_memory_container_t&) { - const auto& ct = *data.second; - - m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", data.first)); - } + m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", id)); + }); } // Memory Objects - const auto mem_map = idm::get_map(); - - if (mem_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("Memory Objects (%zu)", mem_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("Memory Objects (%zu)", count)); - for (const auto& data : mem_map) + idm::select([&](u32 id, lv2_memory_t&) { - const auto& mem = *data.second; - - m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", data.first)); - } + m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", id)); + }); } // PPU Threads - const auto ppu_map = idm::get_map(); - - if (ppu_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("PPU Threads (%zu)", ppu_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("PPU Threads (%zu)", count)); - for (const auto& data : ppu_map) + idm::select([&](u32 id, PPUThread& ppu) { - const auto& ppu = *data.second; - - m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", data.first, ppu.get_name())); - } + m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", id, ppu.get_name())); + }); } // SPU Thread Groups - const auto spu_map = idm::get_map(); - - if (spu_map.size()) + if (const u32 count = idm::get_count()) { - const auto& node = m_tree->AppendItem(root, fmt::format("SPU Thread Groups (%d)", spu_map.size())); + const auto& node = m_tree->AppendItem(root, fmt::format("SPU Thread Groups (%d)", count)); - for (const auto& data : spu_map) + idm::select([&](u32 id, lv2_spu_group_t& tg) { - const auto& tg = *data.second; - - m_tree->AppendItem(node, fmt::format("SPU Thread Group: ID = 0x%08x '%s'", data.first, + m_tree->AppendItem(node, fmt::format("SPU Thread Group: ID = 0x%08x '%s'", id, tg.name.c_str())); - } + }); } // RawSPU Threads (TODO) diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index d9cdf5709e..8233aaf435 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -21,6 +21,8 @@ #include "Utilities/Thread.h" +#include + #ifndef _WIN32 #include "frame_icon.xpm" #endif diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index 6c3139874e..95226fcf50 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -15,6 +15,7 @@ #include "SettingsDialog.h" #include +#include // Node location using cfg_location = std::vector; diff --git a/rpcs3/Loader/ELF.h b/rpcs3/Loader/ELF.h index 71e2cfde76..f66084ad19 100644 --- a/rpcs3/Loader/ELF.h +++ b/rpcs3/Loader/ELF.h @@ -1,5 +1,6 @@ #pragma once +#include "../../Utilities/types.h" #include "../../Utilities/File.h" enum class elf_os : u8 @@ -155,26 +156,31 @@ enum class elf_error // ELF loader error information template<> -struct bijective +struct unveil { - static constexpr bijective_pair map[] + static inline const char* get(elf_error error) { - { elf_error::ok, "" }, + switch (error) + { + case elf_error::ok: return "OK"; - { elf_error::stream, "Invalid stream" }, - { elf_error::stream_header, "Failed to read ELF header" }, - { elf_error::stream_phdrs, "Failed to read ELF program headers" }, - { elf_error::stream_shdrs, "Failed to read ELF section headers" }, - { elf_error::stream_data, "Failed to read ELF program data" }, + case elf_error::stream: return "Invalid stream"; + case elf_error::stream_header: return "Failed to read ELF header"; + case elf_error::stream_phdrs: return "Failed to read ELF program headers"; + case elf_error::stream_shdrs: return "Failed to read ELF section headers"; + case elf_error::stream_data: return "Failed to read ELF program data"; - { elf_error::header_magic, "Not an ELF" }, - { elf_error::header_version, "Invalid or unsupported ELF format" }, - { elf_error::header_class, "Invalid ELF class" }, - { elf_error::header_machine, "Invalid ELF machine" }, - { elf_error::header_endianness, "Invalid ELF data (endianness)" }, - { elf_error::header_type, "Invalid ELF type" }, - { elf_error::header_os, "Invalid ELF OS ABI" }, - }; + case elf_error::header_magic: return "Not an ELF"; + case elf_error::header_version: return "Invalid or unsupported ELF format"; + case elf_error::header_class: return "Invalid ELF class"; + case elf_error::header_machine: return "Invalid ELF machine"; + case elf_error::header_endianness: return "Invalid ELF data (endianness)"; + case elf_error::header_type: return "Invalid ELF type"; + case elf_error::header_os: return "Invalid ELF OS ABI"; + + default: throw error; + } + } }; // ELF loader with specified parameters. @@ -185,7 +191,7 @@ class elf_loader { elf_error m_error{}; - elf_error error(elf_error e) + elf_error set_error(elf_error e) { return m_error = e; } @@ -213,57 +219,57 @@ public: { // Check stream if (!stream) - return error(elf_error::stream); + return set_error(elf_error::stream); // Read ELF header stream.seek(offset); if (!stream.read(header)) - return error(elf_error::stream_header); + return set_error(elf_error::stream_header); // Check magic if (header.e_magic != "\177ELF"_u32) - return error(elf_error::header_magic); + return set_error(elf_error::header_magic); // Check class if (header.e_class != (std::is_same::value ? 1 : 2)) - return error(elf_error::header_class); + return set_error(elf_error::header_class); // Check endianness if (header.e_data != (std::is_same, le_t>::value ? 1 : 2)) - return error(elf_error::header_endianness); + return set_error(elf_error::header_endianness); // Check machine if (header.e_machine != Machine) - return error(elf_error::header_machine); + return set_error(elf_error::header_machine); // Check OS only if specified (hack) if (OS != elf_os::none && header.e_os_abi != OS) - return error(elf_error::header_os); + return set_error(elf_error::header_os); // Check type only if specified (hack) if (Type != elf_type::none && header.e_type != Type) - return error(elf_error::header_type); + return set_error(elf_error::header_type); // Check version and other params if (header.e_curver != 1 || header.e_version != 1 || header.e_ehsize != sizeof(ehdr_t)) - return error(elf_error::header_version); + return set_error(elf_error::header_version); if (header.e_phnum && header.e_phentsize != sizeof(phdr_t)) - return error(elf_error::header_version); + return set_error(elf_error::header_version); if (header.e_shnum && header.e_shentsize != sizeof(shdr_t)) - return error(elf_error::header_version); + return set_error(elf_error::header_version); // Load program headers std::vector _phdrs(header.e_phnum); stream.seek(offset + header.e_phoff); if (!stream.read(_phdrs)) - return error(elf_error::stream_phdrs); + return set_error(elf_error::stream_phdrs); shdrs.resize(header.e_shnum); stream.seek(offset + header.e_shoff); if (!stream.read(shdrs)) - return error(elf_error::stream_shdrs); + return set_error(elf_error::stream_shdrs); progs.clear(); progs.reserve(_phdrs.size()); @@ -275,7 +281,7 @@ public: progs.back().bin.resize(hdr.p_filesz); stream.seek(offset + hdr.p_offset); if (!stream.read(progs.back().bin)) - return error(elf_error::stream_data); + return set_error(elf_error::stream_data); } shdrs.shrink_to_fit(); @@ -336,6 +342,11 @@ public: return m_error; } + elf_error get_error() const + { + return m_error; + } + // Format-specific loader function (must be specialized) typename elf_load_result::type load() const; }; diff --git a/rpcs3/Loader/PSF.cpp b/rpcs3/Loader/PSF.cpp index 8f23aef7f7..f5caf5182f 100644 --- a/rpcs3/Loader/PSF.cpp +++ b/rpcs3/Loader/PSF.cpp @@ -3,7 +3,7 @@ namespace psf { - _log::channel log("PSF", _log::level::notice); + logs::channel log("PSF", logs::level::notice); struct header_t { @@ -23,28 +23,49 @@ namespace psf le_t data_off; }; + + entry::entry(format type, u32 max_size, const std::string& value) + : m_type(type) + , m_max_size(max_size) + , m_value_string(value) + { + EXPECTS(type == format::string || type == format::array); + EXPECTS(max_size); + } + + entry::entry(u32 value) + : m_type(format::integer) + , m_max_size(sizeof(u32)) + , m_value_integer(value) + { + } + + entry::~entry() + { + } + const std::string& entry::as_string() const { - Expects(m_type == format::string || m_type == format::array); + EXPECTS(m_type == format::string || m_type == format::array); return m_value_string; } u32 entry::as_integer() const { - Expects(m_type == format::integer); + EXPECTS(m_type == format::integer); return m_value_integer; } entry& entry::operator =(const std::string& value) { - Expects(m_type == format::string || m_type == format::array); + EXPECTS(m_type == format::string || m_type == format::array); m_value_string = value; return *this; } entry& entry::operator =(u32 value) { - Expects(m_type == format::integer); + EXPECTS(m_type == format::integer); m_value_integer = value; return *this; } @@ -64,73 +85,75 @@ namespace psf throw fmt::exception("Invalid format (0x%x)" HERE, m_type); } - registry load_object(const std::vector& data) + registry load_object(const fs::file& stream) { registry result; // Hack for empty input (TODO) - if (data.empty()) + if (!stream) { return result; } // Check size - Expects(data.size() >= sizeof(header_t)); - Expects((std::uintptr_t)data.data() % 8 == 0); + EXPECTS(stream.size() >= sizeof(header_t)); // Get header - const header_t& header = reinterpret_cast(data[0]); + header_t header; + EXPECTS(stream.read(header)); // Check magic and version - Expects(header.magic == "\0PSF"_u32); - Expects(header.version == 0x101); - Expects(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); - Expects(header.off_key_table <= header.off_data_table); - Expects(header.off_data_table <= data.size()); + EXPECTS(header.magic == "\0PSF"_u32); + EXPECTS(header.version == 0x101); + EXPECTS(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); + EXPECTS(header.off_key_table <= header.off_data_table); + EXPECTS(header.off_data_table <= stream.size()); - // Get indices (alignment should be fine) - const def_table_t* indices = reinterpret_cast(data.data() + sizeof(header_t)); + // Get indices + std::vector indices; + EXPECTS(stream.read(indices, header.entries_num)); + + // Get keys + std::string keys; + EXPECTS(stream.seek(header.off_key_table) == header.off_key_table); + EXPECTS(stream.read(keys, header.off_data_table - header.off_key_table)); // Load entries for (u32 i = 0; i < header.entries_num; ++i) { - Expects(indices[i].key_off < header.off_data_table - header.off_key_table); + EXPECTS(indices[i].key_off < header.off_data_table - header.off_key_table); - // Get key name range - const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off; - const auto name_end = std::find(name_ptr , data.begin() + header.off_data_table, '\0'); + // Get key name (null-terminated string) + std::string key(keys.data() + indices[i].key_off); - // Get name (must be unique) - std::string key(name_ptr, name_end); + EXPECTS(result.count(key) == 0); + EXPECTS(indices[i].param_len <= indices[i].param_max); + EXPECTS(indices[i].data_off < stream.size() - header.off_data_table); + EXPECTS(indices[i].param_max < stream.size() - indices[i].data_off); - Expects(result.count(key) == 0); - Expects(indices[i].param_len <= indices[i].param_max); - Expects(indices[i].data_off < data.size() - header.off_data_table); - Expects(indices[i].param_max < data.size() - indices[i].data_off); - - // Get data pointer - const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off; + // Seek data pointer + stream.seek(header.off_data_table + indices[i].data_off); if (indices[i].param_fmt == format::integer && indices[i].param_max == sizeof(u32) && indices[i].param_len == sizeof(u32)) { // Integer data + le_t value; + EXPECTS(stream.read(value)); + result.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(key)), - std::forward_as_tuple(reinterpret_cast&>(*value_ptr))); + std::forward_as_tuple(value)); } else if (indices[i].param_fmt == format::string || indices[i].param_fmt == format::array) { // String/array data std::string value; + EXPECTS(stream.read(value, indices[i].param_len)); if (indices[i].param_fmt == format::string) { // Find null terminator - value.assign(value_ptr, std::find(value_ptr, value_ptr + indices[i].param_len, '\0')); - } - else - { - value.assign(value_ptr, value_ptr + indices[i].param_len); + value.resize(std::strlen(value.c_str())); } result.emplace(std::piecewise_construct, @@ -147,7 +170,7 @@ namespace psf return result; } - std::vector save_object(const registry& psf) + void save_object(const fs::file& stream, const psf::registry& psf) { std::vector indices; indices.reserve(psf.size()); @@ -182,20 +205,18 @@ namespace psf header.entries_num = ::narrow(psf.size()); // Save header and indices - std::vector result; result.reserve(header.off_data_table + data_offset); - - result.insert(result.end(), (char*)&header, (char*)&header + sizeof(header_t)); - result.insert(result.end(), (char*)indices.data(), (char*)indices.data() + sizeof(def_table_t) * psf.size()); + stream.write(header); + stream.write(indices); // Save key table for (const auto& entry : psf) { - result.insert(result.end(), entry.first.begin(), entry.first.end()); - result.push_back('\0'); + stream.write(entry.first); + stream.write('\0'); } - // Insert zero padding - result.insert(result.end(), header.off_data_table - result.size(), '\0'); + // Skip padding + stream.seek(header.off_data_table); // Save data for (const auto& entry : psf) @@ -206,7 +227,7 @@ namespace psf if (fmt == format::integer && max == sizeof(u32)) { const le_t value = entry.second.as_integer(); - result.insert(result.end(), (char*)&value, (char*)&value + sizeof(u32)); + stream.write(value); } else if (fmt == format::string || fmt == format::array) { @@ -219,16 +240,14 @@ namespace psf log.error("Entry value shrinkage (key='%s', value='%s', size=0x%zx, max=0x%x)", entry.first, value, size, max); } - result.insert(result.end(), value.begin(), value.begin() + size); - result.insert(result.end(), max - size, '\0'); // Write zeros up to max_size + stream.write(value); + stream.seek(max - size, fs::seek_cur); // Skip up to max_size } else { throw EXCEPTION("Invalid entry format (key='%s', fmt=0x%x)", entry.first, fmt); } } - - return result; } std::string get_string(const registry& psf, const std::string& key, const std::string& def) diff --git a/rpcs3/Loader/PSF.h b/rpcs3/Loader/PSF.h index ed360ed2b8..08fa4c5ec2 100644 --- a/rpcs3/Loader/PSF.h +++ b/rpcs3/Loader/PSF.h @@ -20,22 +20,12 @@ namespace psf public: // Construct string entry, assign the value - entry(format type, u32 max_size, const std::string& value = {}) - : m_type(type) - , m_max_size(max_size) - , m_value_string(value) - { - Expects(type == format::string || type == format::array); - Expects(max_size); - } + entry(format type, u32 max_size, const std::string& value = {}); // Construct integer entry, assign the value - entry(u32 value) - : m_type(format::integer) - , m_max_size(sizeof(u32)) - , m_value_integer(value) - { - } + entry(u32 value); + + ~entry(); const std::string& as_string() const; u32 as_integer() const; @@ -51,24 +41,11 @@ namespace psf // Define PSF registry as a sorted map of entries: using registry = std::map; - // Load PSF registry from SFO binary data - registry load_object(const std::vector&); - - // Load PSF registry from SFO file, if opened - inline registry load_object(const fs::file& f) - { - if (f) - { - return load_object(f.to_vector()); - } - else - { - return registry{}; - } - } + // Load PSF registry from SFO binary format + registry load_object(const fs::file&); // Convert PSF registry to SFO binary format - std::vector save_object(const registry&); + void save_object(const fs::file&, const registry&); // Get string value or default value std::string get_string(const registry& psf, const std::string& key, const std::string& def = {}); diff --git a/rpcs3/Loader/TROPUSR.cpp b/rpcs3/Loader/TROPUSR.cpp index bd3e859a41..b58b71e122 100644 --- a/rpcs3/Loader/TROPUSR.cpp +++ b/rpcs3/Loader/TROPUSR.cpp @@ -138,7 +138,7 @@ bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& con const std::string& path = vfs::get(configpath); // TODO: rXmlDocument can open only real file - ASSERT(!fs::get_virtual_device(path)); + VERIFY(!fs::get_virtual_device(path)); rXmlDocument doc; doc.Load(path); diff --git a/rpcs3/Loader/TRP.cpp b/rpcs3/Loader/TRP.cpp index 2f59b9b2b1..be78fb7c63 100644 --- a/rpcs3/Loader/TRP.cpp +++ b/rpcs3/Loader/TRP.cpp @@ -16,7 +16,7 @@ bool TRPLoader::Install(const std::string& dest, bool show) const std::string& local_path = vfs::get(dest); - if (!fs::create_dir(local_path) && fs::error != EEXIST) + if (!fs::create_dir(local_path) && fs::g_tls_error != fs::error::exist) { return false; } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index f63cba175f..f2ee70cae5 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -85,7 +85,7 @@ - + @@ -265,70 +265,70 @@ NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -364,6 +364,8 @@ + + @@ -372,7 +374,6 @@ - @@ -389,78 +390,79 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index d7baae4115..ca8e48a36b 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -54,12 +54,6 @@ {2a8841dc-bce0-41bb-9fcb-5bf1f8dda213} - - {93b1cff1-0158-4327-a437-e9abcac8d724} - - - {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} - {13d20086-2188-425a-9856-0440fe6f79f2} @@ -69,6 +63,12 @@ {4317ac27-38e4-4f8d-9bac-496f9b00f615} + + {93b1cff1-0158-4327-a437-e9abcac8d724} + + + {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} + @@ -113,9 +113,6 @@ Emu\CPU - - Emu\ARMv7 - Emu\Audio @@ -161,192 +158,9 @@ Crypto - - Emu\ARMv7 - - - Emu\ARMv7 - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - Utilities - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - Emu\GPU\RSX @@ -419,9 +233,6 @@ Emu\Cell - - Emu\ARMv7 - Emu\Cell\lv2 @@ -833,12 +644,6 @@ Emu\Cell\Modules - - Emu\ARMv7 - - - Emu\ARMv7\Modules - Utilities @@ -854,6 +659,201 @@ Emu + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + @@ -937,18 +937,6 @@ Emu\CPU - - Emu\ARMv7 - - - Emu\ARMv7 - - - Emu\ARMv7 - - - Emu\ARMv7 - Emu\Audio @@ -1057,33 +1045,6 @@ Emu\Audio - - Emu\ARMv7 - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - Utilities @@ -1099,159 +1060,9 @@ Emu\GPU\RSX\Common - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - - - Emu\ARMv7\Modules - Utilities - - Utilities - Emu\Cell @@ -1306,9 +1117,6 @@ Loader - - Emu\ARMv7 - Emu\Cell\lv2 @@ -1579,15 +1387,6 @@ Emu\Cell - - Emu\ARMv7 - - - Emu\ARMv7 - - - Emu\ARMv7\Modules - Header Files @@ -1606,9 +1405,6 @@ Emu\Memory - - Emu\Cell\lv2 - Utilities @@ -1618,5 +1414,215 @@ Utilities + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2 + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu\PSP2\Modules + + + Emu + + + Utilities + + + Utilities + \ No newline at end of file diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index 7148a0c127..d29af71143 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -23,20 +23,20 @@ #include #include #include +#include #include -#include -#include #include #include #include #include -#include -#include #include -#include -using namespace std::string_literals; -using namespace std::chrono_literals; +// MSVC bug workaround +#ifdef _MSC_VER +namespace std { inline namespace literals { inline namespace chrono_literals {}}} +#endif + +using namespace std::literals; // Obsolete, throw fmt::exception directly. Use 'HERE' macro, if necessary. #define EXCEPTION(format_str, ...) fmt::exception("%s(): " format_str HERE, __FUNCTION__, ##__VA_ARGS__)