1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00
This commit is contained in:
Nekotekina 2016-05-13 17:01:48 +03:00
parent e2d82394f6
commit 266db1336d
81 changed files with 2247 additions and 1731 deletions

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "Platform.h"
// Helper class, provides access to compiler-specific atomic intrinsics // Helper class, provides access to compiler-specific atomic intrinsics
template<typename T, std::size_t Size> template<typename T, std::size_t Size>
@ -744,9 +745,9 @@ public:
while (true) while (true)
{ {
func(_new = old, args...); func((_new = old), args...);
if (atomic_storage<type>::compare_exchange(m_data, old, _new)) return old; if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new))) return old;
} }
} }
@ -765,9 +766,9 @@ public:
while (true) while (true)
{ {
func(_new = old, args...); func((_new = old), args...);
if (atomic_storage<type>::compare_exchange(m_data, old, _new)) return _new; if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new))) return _new;
} }
} }
@ -786,9 +787,9 @@ public:
while (true) while (true)
{ {
RT&& result = func(_new = old, args...); RT&& result = func((_new = old), args...);
if (atomic_storage<type>::compare_exchange(m_data, old, _new)) return std::move(result); if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new))) return std::move(result);
} }
} }
@ -800,9 +801,9 @@ public:
while (true) while (true)
{ {
func(_new = old, args...); func((_new = old), args...);
if (atomic_storage<type>::compare_exchange(m_data, old, _new)) return; if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new))) return;
} }
} }

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <unordered_set>
// Regarded as a Debugger Enchantment // Regarded as a Debugger Enchantment
namespace debug namespace debug
{ {

View File

@ -5,7 +5,7 @@
namespace cfg namespace cfg
{ {
_log::channel cfg("CFG", _log::level::notice); logs::channel cfg("CFG", logs::level::notice);
entry_base::entry_base(type _type) entry_base::entry_base(type _type)
: m_type(_type) : m_type(_type)

View File

@ -179,7 +179,7 @@ namespace cfg
for (const auto& v : init) for (const auto& v : init)
{ {
// Ensure elements are unique // Ensure elements are unique
ASSERT(map.emplace(v.first, v.second).second); VERIFY(map.emplace(v.first, v.second).second);
} }
return map; return map;
@ -529,4 +529,4 @@ namespace cfg
} }
// Registered log channel // 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<logs::level, true> name(cfg::root.log, #name, ::name.enabled); }

View File

@ -69,6 +69,19 @@ static time_t to_time(const FILETIME& ft)
return to_time(v); 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 #else
#include <sys/mman.h> #include <sys/mman.h>
@ -87,11 +100,22 @@ static time_t to_time(const FILETIME& ft)
#include <sys/sendfile.h> #include <sys/sendfile.h>
#endif #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 #endif
namespace fs namespace fs
{ {
thread_local uint error = 0; thread_local error g_tls_error = error::ok;
class device_manager final class device_manager final
{ {
@ -146,7 +170,7 @@ std::shared_ptr<fs::device_base> fs::get_virtual_device(const std::string& path)
std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, const std::shared_ptr<device_base>& device) std::shared_ptr<fs::device_base> fs::set_virtual_device(const std::string& name, const std::shared_ptr<device_base>& 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); 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 static const auto test_get_parent_dir = []() -> bool
{ {
// Success: // Success:
ASSERT(fs::get_parent_dir("/x/y///") == "/x"); VERIFY(fs::get_parent_dir("/x/y///") == "/x");
ASSERT(fs::get_parent_dir("/x/y/") == "/x"); VERIFY(fs::get_parent_dir("/x/y/") == "/x");
ASSERT(fs::get_parent_dir("/x/y") == "/x"); VERIFY(fs::get_parent_dir("/x/y") == "/x");
ASSERT(fs::get_parent_dir("x:/y") == "x:"); VERIFY(fs::get_parent_dir("x:/y") == "x:");
ASSERT(fs::get_parent_dir("//x/y") == "//x"); VERIFY(fs::get_parent_dir("//x/y") == "//x");
// Failure: // Failure:
ASSERT(fs::get_parent_dir("").empty()); VERIFY(fs::get_parent_dir("").empty());
ASSERT(fs::get_parent_dir("x/").empty()); VERIFY(fs::get_parent_dir("x/").empty());
ASSERT(fs::get_parent_dir("x").empty()); VERIFY(fs::get_parent_dir("x").empty());
ASSERT(fs::get_parent_dir("x///").empty()); VERIFY(fs::get_parent_dir("x///").empty());
ASSERT(fs::get_parent_dir("/x/").empty()); VERIFY(fs::get_parent_dir("/x/").empty());
ASSERT(fs::get_parent_dir("/x").empty()); VERIFY(fs::get_parent_dir("/x").empty());
ASSERT(fs::get_parent_dir("/").empty()); VERIFY(fs::get_parent_dir("/").empty());
ASSERT(fs::get_parent_dir("//").empty()); VERIFY(fs::get_parent_dir("//").empty());
ASSERT(fs::get_parent_dir("//x").empty()); VERIFY(fs::get_parent_dir("//x").empty());
ASSERT(fs::get_parent_dir("//x/").empty()); VERIFY(fs::get_parent_dir("//x/").empty());
ASSERT(fs::get_parent_dir("///").empty()); VERIFY(fs::get_parent_dir("///").empty());
ASSERT(fs::get_parent_dir("///x").empty()); VERIFY(fs::get_parent_dir("///x").empty());
ASSERT(fs::get_parent_dir("///x/").empty()); VERIFY(fs::get_parent_dir("///x/").empty());
return false; return false;
}(); }();
@ -213,14 +237,7 @@ bool fs::stat(const std::string& path, stat_t& info)
WIN32_FILE_ATTRIBUTE_DATA attrs; WIN32_FILE_ATTRIBUTE_DATA attrs;
if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs)) if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -234,7 +251,7 @@ bool fs::stat(const std::string& path, stat_t& info)
struct ::stat file_info; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -260,14 +277,7 @@ bool fs::exists(const std::string& path)
#ifdef _WIN32 #ifdef _WIN32
if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES) if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -276,7 +286,7 @@ bool fs::exists(const std::string& path)
struct ::stat file_info; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -296,7 +306,7 @@ bool fs::is_file(const std::string& path)
if (info.is_directory) if (info.is_directory)
{ {
fs::error = EEXIST; g_tls_error = error::exist;
return false; return false;
} }
@ -307,21 +317,14 @@ bool fs::is_file(const std::string& path)
const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
if (attrs == INVALID_FILE_ATTRIBUTES) if (attrs == INVALID_FILE_ATTRIBUTES)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
#else #else
struct ::stat file_info; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
#endif #endif
@ -333,7 +336,7 @@ bool fs::is_file(const std::string& path)
if (S_ISDIR(file_info.st_mode)) if (S_ISDIR(file_info.st_mode))
#endif #endif
{ {
fs::error = EEXIST; g_tls_error = error::exist;
return false; return false;
} }
@ -352,7 +355,7 @@ bool fs::is_dir(const std::string& path)
if (info.is_directory == false) if (info.is_directory == false)
{ {
fs::error = EEXIST; g_tls_error = error::exist;
return false; return false;
} }
@ -363,21 +366,14 @@ bool fs::is_dir(const std::string& path)
const DWORD attrs = GetFileAttributesW(to_wchar(path).get()); const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
if (attrs == INVALID_FILE_ATTRIBUTES) if (attrs == INVALID_FILE_ATTRIBUTES)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
#else #else
struct ::stat file_info; struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0) if (::stat(path.c_str(), &file_info) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
#endif #endif
@ -388,7 +384,7 @@ bool fs::is_dir(const std::string& path)
if (!S_ISDIR(file_info.st_mode)) if (!S_ISDIR(file_info.st_mode))
#endif #endif
{ {
fs::error = EEXIST; g_tls_error = error::exist;
return false; return false;
} }
@ -405,14 +401,7 @@ bool fs::create_dir(const std::string& path)
#ifdef _WIN32 #ifdef _WIN32
if (!CreateDirectoryW(to_wchar(path).get(), NULL)) if (!CreateDirectoryW(to_wchar(path).get(), NULL))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -420,7 +409,7 @@ bool fs::create_dir(const std::string& path)
#else #else
if (::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) 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; return false;
} }
@ -450,13 +439,7 @@ bool fs::remove_dir(const std::string& path)
#ifdef _WIN32 #ifdef _WIN32
if (!RemoveDirectoryW(to_wchar(path).get())) if (!RemoveDirectoryW(to_wchar(path).get()))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -464,7 +447,7 @@ bool fs::remove_dir(const std::string& path)
#else #else
if (::rmdir(path.c_str()) != 0) if (::rmdir(path.c_str()) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -489,13 +472,7 @@ bool fs::rename(const std::string& from, const std::string& to)
#ifdef _WIN32 #ifdef _WIN32
if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get())) if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get()))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -503,7 +480,7 @@ bool fs::rename(const std::string& from, const std::string& to)
#else #else
if (::rename(from.c_str(), to.c_str()) != 0) if (::rename(from.c_str(), to.c_str()) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -523,13 +500,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
#ifdef _WIN32 #ifdef _WIN32
if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite)) if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; 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); const int input = ::open(from.c_str(), O_RDONLY);
if (input == -1) if (input == -1)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -550,7 +521,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int err = errno; const int err = errno;
::close(input); ::close(input);
fs::error = err; g_tls_error = to_error(err);
return false; return false;
} }
@ -569,7 +540,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
::close(input); ::close(input);
::close(output); ::close(output);
fs::error = err; g_tls_error = to_error(err);
return false; return false;
} }
@ -589,14 +560,7 @@ bool fs::remove_file(const std::string& path)
#ifdef _WIN32 #ifdef _WIN32
if (!DeleteFileW(to_wchar(path).get())) if (!DeleteFileW(to_wchar(path).get()))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -604,7 +568,7 @@ bool fs::remove_file(const std::string& path)
#else #else
if (::unlink(path.c_str()) != 0) if (::unlink(path.c_str()) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; 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); 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) if (handle == INVALID_HANDLE_VALUE)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -641,13 +598,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
// Seek and truncate // Seek and truncate
if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN) || !SetEndOfFile(handle)) if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN) || !SetEndOfFile(handle))
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
CloseHandle(handle); CloseHandle(handle);
return false; return false;
} }
@ -657,7 +608,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
#else #else
if (::truncate(path.c_str(), length) != 0) if (::truncate(path.c_str(), length) != 0)
{ {
fs::error = errno; g_tls_error = to_error(errno);
return false; return false;
} }
@ -672,7 +623,7 @@ void fs::file::xnull() const
void fs::file::xfail() 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<open_mode> mode) bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
@ -704,7 +655,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{ {
if (mode & fs::excl) if (mode & fs::excl)
{ {
fs::error = EINVAL; g_tls_error = error::inval;
return false; return false;
} }
@ -715,15 +666,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -747,12 +690,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
FILE_BASIC_INFO basic_info; FILE_BASIC_INFO basic_info;
if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO))) if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO)))
{ {
// TODO: convert Win32 error code to errno throw fmt::exception("Win32 error: %u." HERE, GetLastError());
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
} }
stat_t info; stat_t info;
@ -773,47 +711,22 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
pos.QuadPart = 0; pos.QuadPart = 0;
if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
return false; return false;
} }
pos.QuadPart = length; pos.QuadPart = length;
if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
switch (DWORD error = GetLastError())
{
case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
return false; return false;
} }
const BOOL result = SetEndOfFile(m_handle); // change file size 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 throw fmt::exception("Win32 error: %u." HERE, GetLastError());
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);
}
} }
return result != FALSE; return result != FALSE;
@ -823,16 +736,12 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{ {
// TODO (call ReadFile multiple times if count is too big) // TODO (call ReadFile multiple times if count is too big)
const int size = ::narrow<int>(count, "Too big count" HERE); const int size = ::narrow<int>(count, "Too big count" HERE);
Expects(size >= 0); EXPECTS(size >= 0);
DWORD nread; DWORD nread;
if (!ReadFile(m_handle, buffer, size, &nread, NULL)) if (!ReadFile(m_handle, buffer, size, &nread, NULL))
{ {
switch (DWORD error = GetLastError()) throw fmt::exception("Win32 error: %u." HERE, GetLastError());
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
} }
return nread; return nread;
@ -842,16 +751,12 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{ {
// TODO (call WriteFile multiple times if count is too big) // TODO (call WriteFile multiple times if count is too big)
const int size = ::narrow<int>(count, "Too big count" HERE); const int size = ::narrow<int>(count, "Too big count" HERE);
Expects(size >= 0); EXPECTS(size >= 0);
DWORD nwritten; DWORD nwritten;
if (!WriteFile(m_handle, buffer, size, &nwritten, NULL)) if (!WriteFile(m_handle, buffer, size, &nwritten, NULL))
{ {
switch (DWORD error = GetLastError()) throw fmt::exception("Win32 error: %u." HERE, GetLastError());
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
} }
return nwritten; return nwritten;
@ -870,11 +775,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (!SetFilePointerEx(m_handle, pos, &pos, mode)) if (!SetFilePointerEx(m_handle, pos, &pos, mode))
{ {
switch (DWORD error = GetLastError()) throw fmt::exception("Win32 error: %u." HERE, GetLastError());
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
} }
return pos.QuadPart; return pos.QuadPart;
@ -885,11 +786,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
LARGE_INTEGER size; LARGE_INTEGER size;
if (!GetFileSizeEx(m_handle, &size)) if (!GetFileSizeEx(m_handle, &size))
{ {
switch (DWORD error = GetLastError()) throw fmt::exception("Win32 error: %u." HERE, GetLastError());
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
} }
return size.QuadPart; return size.QuadPart;
@ -913,8 +810,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (fd == -1) if (fd == -1)
{ {
// TODO: errno g_tls_error = to_error(errno);
fs::error = errno;
return false; return false;
} }
@ -938,11 +834,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
struct ::stat file_info; struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0) if (::fstat(m_fd, &file_info) != 0)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
stat_t info; stat_t info;
@ -960,12 +852,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{ {
if (::ftruncate(m_fd, length) != 0) if (::ftruncate(m_fd, length) != 0)
{ {
switch (int error = errno) g_tls_error = to_error(errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
return false; return false;
} }
@ -977,11 +864,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::read(m_fd, buffer, count); const auto result = ::read(m_fd, buffer, count);
if (result == -1) if (result == -1)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
return result; return result;
@ -992,11 +875,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::write(m_fd, buffer, count); const auto result = ::write(m_fd, buffer, count);
if (result == -1) if (result == -1)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
return result; return result;
@ -1013,11 +892,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::lseek(m_fd, offset, mode); const auto result = ::lseek(m_fd, offset, mode);
if (result == -1) if (result == -1)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
return result; return result;
@ -1028,11 +903,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
struct ::stat file_info; struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0) if (::fstat(m_fd, &file_info) != 0)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
return file_info.st_size; 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 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 char* const m_ptr;
const u64 m_size; const u64 m_size;
@ -1063,26 +934,26 @@ fs::file::file(const void* ptr, std::size_t size)
fs::stat_t stat() override 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 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 u64 read(void* buffer, u64 count) override
{ {
const u64 start = m_pos; const u64 start = m_pos;
const u64 end = seek(count, fs::seek_cur); 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); std::memcpy(buffer, m_ptr + start, read_size);
return read_size; return read_size;
} }
u64 write(const void* buffer, u64 count) override 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 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<u64>(offset, m_size) : whence == fs::seek_set ? m_pos = std::min<u64>(offset, m_size) :
whence == fs::seek_cur ? m_pos = std::min<u64>(offset + m_pos, m_size) : whence == fs::seek_cur ? m_pos = std::min<u64>(offset + m_pos, m_size) :
whence == fs::seek_end ? m_pos = std::min<u64>(offset + m_size, m_size) : whence == fs::seek_end ? m_pos = std::min<u64>(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 u64 size() override
@ -1127,14 +998,7 @@ bool fs::dir::open(const std::string& path)
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
{ {
// TODO: convert Win32 error code to errno g_tls_error = to_error(GetLastError());
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);
}
return false; return false;
} }
@ -1179,11 +1043,12 @@ bool fs::dir::open(const std::string& path)
WIN32_FIND_DATAW found; WIN32_FIND_DATAW found;
if (!FindNextFileW(m_handle, &found)) if (!FindNextFileW(m_handle, &found))
{ {
switch (DWORD error = GetLastError()) if (ERROR_NO_MORE_FILES == GetLastError())
{ {
case ERROR_NO_MORE_FILES: return false; return false;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
} }
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
} }
add_entry(found); add_entry(found);
@ -1205,8 +1070,7 @@ bool fs::dir::open(const std::string& path)
if (!ptr) if (!ptr)
{ {
// TODO: errno g_tls_error = to_error(errno);
fs::error = errno;
return false; return false;
} }
@ -1236,11 +1100,7 @@ bool fs::dir::open(const std::string& path)
struct ::stat file_info; struct ::stat file_info;
if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0) if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0)
{ {
switch (int error = errno) throw fmt::exception("System error: %d." HERE, errno);
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
} }
info.name = found->d_name; info.name = found->d_name;

View File

@ -10,9 +10,6 @@
namespace fs namespace fs
{ {
// Error code returned
extern thread_local uint error;
// File open mode flags // File open mode flags
enum struct open_mode : u32 enum struct open_mode : u32
{ {
@ -265,6 +262,13 @@ namespace fs
return read(&str[0], str.size()) == str.size(); 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 // Read POD, sizeof(T) is used
template<typename T> template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
@ -279,6 +283,14 @@ namespace fs
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size(); return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
} }
// Read POD std::vector
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(std::vector<T>& vec, std::size_t size) const
{
vec.resize(size);
return read(vec.data(), sizeof(T) * size) == sizeof(T) * size;
}
// Read POD (experimental) // Read POD (experimental)
template<typename T> template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
@ -432,4 +444,16 @@ namespace fs
// Get size of all files recursively // Get size of all files recursively
u64 get_dir_size(const std::string& path); 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;
} }

View File

@ -3,12 +3,8 @@
#define GSL_THROW_ON_CONTRACT_VIOLATION #define GSL_THROW_ON_CONTRACT_VIOLATION
#pragma push_macro("new") #pragma push_macro("new")
#pragma push_macro("Expects")
#pragma push_macro("Ensures")
#undef new #undef new
#include <gsl.h>
#pragma pop_macro("new")
#undef Expects #undef Expects
#undef Ensures #undef Ensures
#include <gsl.h>
#pragma pop_macro("Ensures")
#pragma pop_macro("Expects")
#pragma pop_macro("new")

View File

@ -8,7 +8,11 @@
// Thread-specific log prefix provider // Thread-specific log prefix provider
thread_local std::string(*g_tls_log_prefix)() = nullptr; thread_local std::string(*g_tls_log_prefix)() = nullptr;
namespace _log #ifndef _MSC_VER
constexpr DECLARE(bijective<logs::level, const char*>::map);
#endif
namespace logs
{ {
struct listener struct listener
{ {
@ -65,7 +69,7 @@ namespace _log
channel ARMv7("ARMv7"); 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_list args;
va_start(args, fmt); 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(); [[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 try
{ {
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) 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 (...) 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); m_file.write(text);
} }
std::size_t _log::file_writer::size() const std::size_t logs::file_writer::size() const
{ {
return m_file.pos(); 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); std::string msg; msg.reserve(text.size() + 200);

View File

@ -3,7 +3,7 @@
#include "types.h" #include "types.h"
#include "Atomic.h" #include "Atomic.h"
namespace _log namespace logs
{ {
enum class level : uint enum class level : uint
{ {
@ -79,27 +79,27 @@ namespace _log
} }
template<> template<>
struct bijective<_log::level, const char*> struct bijective<logs::level, const char*>
{ {
static constexpr bijective_pair<_log::level, const char*> map[] static constexpr bijective_pair<logs::level, const char*> map[]
{ {
{ _log::level::always, "Nothing" }, { logs::level::always, "Nothing" },
{ _log::level::fatal, "Fatal" }, { logs::level::fatal, "Fatal" },
{ _log::level::error, "Error" }, { logs::level::error, "Error" },
{ _log::level::todo, "TODO" }, { logs::level::todo, "TODO" },
{ _log::level::success, "Success" }, { logs::level::success, "Success" },
{ _log::level::warning, "Warning" }, { logs::level::warning, "Warning" },
{ _log::level::notice, "Notice" }, { logs::level::notice, "Notice" },
{ _log::level::trace, "Trace" }, { logs::level::trace, "Trace" },
}; };
}; };
// Legacy: // Legacy:
#define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__) #define LOG_SUCCESS(ch, fmt, ...) logs::ch.success(fmt, ##__VA_ARGS__)
#define LOG_NOTICE(ch, fmt, ...) _log::ch.notice (fmt, ##__VA_ARGS__) #define LOG_NOTICE(ch, fmt, ...) logs::ch.notice (fmt, ##__VA_ARGS__)
#define LOG_WARNING(ch, fmt, ...) _log::ch.warning(fmt, ##__VA_ARGS__) #define LOG_WARNING(ch, fmt, ...) logs::ch.warning(fmt, ##__VA_ARGS__)
#define LOG_ERROR(ch, fmt, ...) _log::ch.error (fmt, ##__VA_ARGS__) #define LOG_ERROR(ch, fmt, ...) logs::ch.error (fmt, ##__VA_ARGS__)
#define LOG_TODO(ch, fmt, ...) _log::ch.todo (fmt, ##__VA_ARGS__) #define LOG_TODO(ch, fmt, ...) logs::ch.todo (fmt, ##__VA_ARGS__)
#define LOG_TRACE(ch, fmt, ...) _log::ch.trace (fmt, ##__VA_ARGS__) #define LOG_TRACE(ch, fmt, ...) logs::ch.trace (fmt, ##__VA_ARGS__)
#define LOG_FATAL(ch, fmt, ...) _log::ch.fatal (fmt, ##__VA_ARGS__) #define LOG_FATAL(ch, fmt, ...) logs::ch.fatal (fmt, ##__VA_ARGS__)

View File

@ -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_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_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_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 // Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t
#define SIZE_32(type) static_cast<std::uint32_t>(sizeof(type)) #define SIZE_32(type) static_cast<std::uint32_t>(sizeof(type))
@ -60,20 +61,22 @@ constexpr std::uint32_t size32(const T(&)[Size])
#define STRINGIZE_DETAIL(x) #x #define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(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 WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; }
#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; } #define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; }
#define PURE_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__) ")" #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). // 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. // EXPECTS() and ENSURES() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification. // Expressions are not guaranteed to evaluate.
#define Expects ASSERT #define EXPECTS(expr) do { if (!(expr)) throw std::runtime_error("Precondition failed: " #expr HERE); } while (0)
#define Ensures ASSERT #define ENSURES(expr) do { if (!(expr)) throw std::runtime_error("Postcondition failed: " #expr HERE); } while (0)
#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__ #define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__

View File

@ -35,7 +35,7 @@ public:
bool try_wait() bool try_wait()
{ {
return LIKELY(m_value.compare_and_swap_test(1, 0)); return m_value.compare_and_swap_test(1, 0);
} }
void post() void post()

View File

@ -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<std::mutex> 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() void shared_mutex::initialize_once()
{ {
if (UNLIKELY(!m_data)) if (UNLIKELY(!m_data))

View File

@ -32,6 +32,9 @@ class shared_mutex final
void lock_hard(); void lock_hard();
void unlock_notify(); void unlock_notify();
void lock_upgrade_hard();
void lock_degrade_hard();
public: public:
constexpr shared_mutex() = default; constexpr shared_mutex() = default;
@ -42,15 +45,9 @@ public:
bool try_lock_shared() bool try_lock_shared()
{ {
auto ctrl = m_ctrl.load(); const u32 ctrl = m_ctrl.load();
if (UNLIKELY(ctrl >= SM_READER_MAX)) return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1);
{
ctrl = 0;
}
// Weak attempt
return LIKELY(m_ctrl.compare_and_swap_test(ctrl, ctrl + 1));
} }
void lock_shared() void lock_shared()
@ -72,12 +69,12 @@ public:
bool try_lock() 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() void lock()
{ {
if (UNLIKELY(!try_lock())) if (UNLIKELY(!m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)))
{ {
lock_hard(); lock_hard();
} }
@ -85,11 +82,39 @@ public:
void unlock() 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(); 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. //! Simplified shared (reader) lock implementation.
@ -133,3 +158,23 @@ public:
m_mutex.unlock(); 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();
}
};

View File

@ -59,17 +59,27 @@ public:
// Remove thread from the sleep queue // Remove thread from the sleep queue
void leave() void leave()
{ {
auto it = std::find(m_queue.begin(), m_queue.end(), &m_thread); for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
if (it != m_queue.end())
{ {
m_queue.erase(it); if (*it == &m_thread)
{
m_queue.erase(it);
return;
}
} }
} }
// Check whether the thread exists in the sleep queue // Check whether the thread exists in the sleep queue
explicit operator bool() const 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;
} }
}; };

View File

@ -5,6 +5,7 @@
#include <cassert> #include <cassert>
#include <array> #include <array>
#include <memory> #include <memory>
#include <algorithm>
std::string v128::to_hex() const std::string v128::to_hex() const
{ {

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <cstdarg> #include <cstdarg>
#include <string>
#include <exception> #include <exception>
#include <string>
#include "Platform.h" #include "Platform.h"
#include "types.h" #include "types.h"
@ -14,7 +14,7 @@ namespace fmt
// Formatting function // Formatting function
template<typename... Args> template<typename... Args>
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<Args>::get(args)...); return unsafe_format(fmt, ::unveil<Args>::get(args)...);
} }
@ -34,7 +34,6 @@ namespace fmt
class exception : public exception_base class exception : public exception_base
{ {
public: public:
// Formatting constructor
template<typename... Args> template<typename... Args>
exception(const char* fmt, const Args&... args) exception(const char* fmt, const Args&... args)
: exception_base(fmt, ::unveil<Args>::get(args)...) : exception_base(fmt, ::unveil<Args>::get(args)...)

View File

@ -1263,9 +1263,11 @@ const bool s_self_test = []() -> bool
return true; return true;
}(); }();
#include <thread>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
#include <exception> #include <exception>
#include <chrono>
thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr; thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr;
@ -1278,17 +1280,20 @@ struct thread_ctrl::internal
task_stack atexit; task_stack atexit;
std::exception_ptr exception; // Caught exception std::exception_ptr exception; // Caught exception
std::chrono::high_resolution_clock::time_point time_limit;
}; };
// Temporarily until better interface is implemented thread_local thread_ctrl::internal* g_tls_internal = nullptr;
extern std::condition_variable& get_current_thread_cv()
{
return thread_ctrl::get_current()->get_data()->cond;
}
extern std::mutex& get_current_thread_mutex() 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 // TODO
@ -1296,10 +1301,64 @@ extern atomic_t<u32> g_thread_count(0);
extern thread_local std::string(*g_tls_log_prefix)(); extern thread_local std::string(*g_tls_log_prefix)();
void thread_ctrl::start(const std::shared_ptr<thread_ctrl>& ctrl, task_stack task)
{
reinterpret_cast<std::thread&>(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<std::mutex> 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() void thread_ctrl::initialize()
{ {
initialize_once(); // TODO (temporarily)
// Initialize TLS variable // Initialize TLS variable
g_tls_this_thread = this; g_tls_this_thread = this;
g_tls_internal = this->m_data;
g_tls_log_prefix = [] g_tls_log_prefix = []
{ {
@ -1339,12 +1398,6 @@ void thread_ctrl::initialize()
#endif #endif
} }
void thread_ctrl::set_exception() noexcept
{
initialize_once();
m_data->exception = std::current_exception();
}
void thread_ctrl::finalize() noexcept void thread_ctrl::finalize() noexcept
{ {
// TODO // TODO
@ -1355,30 +1408,43 @@ void thread_ctrl::finalize() noexcept
--g_thread_count; --g_thread_count;
#ifdef _MSC_VER #ifdef _WIN32
ULONG64 time; ULONG64 time;
QueryThreadCycleTime(m_thread.native_handle(), &time); QueryThreadCycleTime(GetCurrentThread(), &time);
LOG_NOTICE(GENERAL, "Thread time: %f Gc", time / 1000000000.); LOG_NOTICE(GENERAL, "Thread time: %f Gc", time / 1000000000.);
#endif #endif
} }
task_stack& thread_ctrl::get_atexit() const void thread_ctrl::push_atexit(task_stack task)
{ {
initialize_once(); 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() thread_ctrl::~thread_ctrl()
{ {
if (m_thread.joinable()) if (reinterpret_cast<std::thread&>(m_thread).joinable())
{ {
m_thread.detach(); reinterpret_cast<std::thread&>(m_thread).detach();
} }
delete m_data; delete m_data;
reinterpret_cast<std::thread&>(m_thread).~thread();
} }
void thread_ctrl::initialize_once() const void thread_ctrl::initialize_once()
{ {
if (UNLIKELY(!m_data)) if (UNLIKELY(!m_data))
{ {
@ -1393,33 +1459,37 @@ void thread_ctrl::initialize_once() const
void thread_ctrl::join() void thread_ctrl::join()
{ {
if (LIKELY(m_thread.joinable())) // Increase contention counter
const u32 _j = m_joining++;
if (LIKELY(_j >= 0x80000000))
{ {
// Increase contention counter // Already joined (signal condition)
if (UNLIKELY(m_joining++)) m_joining = 0x80000000;
}
else if (LIKELY(_j == 0))
{
// Winner joins the thread
reinterpret_cast<std::thread&>(m_thread).join();
// Notify others if necessary
if (UNLIKELY(m_joining.exchange(0x80000000) != 1))
{ {
// Hard way
initialize_once(); initialize_once();
std::unique_lock<std::mutex> lock(m_data->mutex); // Serialize for reliable notification
m_data->join.wait(lock, WRAP_EXPR(!m_thread.joinable())); m_data->mutex.lock();
m_data->mutex.unlock();
m_data->join.notify_all();
} }
else }
{ else
// Winner joins the thread {
m_thread.join(); // Hard way
initialize_once();
// Notify others if necessary std::unique_lock<std::mutex> lock(m_data->mutex);
if (UNLIKELY(m_joining > 1)) m_data->join.wait(lock, WRAP_EXPR(m_joining >= 0x80000000));
{
initialize_once();
// Serialize for reliable notification
m_data->mutex.lock();
m_data->mutex.unlock();
m_data->join.notify_all();
}
}
} }
if (UNLIKELY(m_data && m_data->exception)) 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)) if (UNLIKELY(g_tls_this_thread == this))
{ {
@ -1443,16 +1524,19 @@ void thread_ctrl::lock_notify() const
m_data->cond.notify_one(); m_data->cond.notify_one();
} }
void thread_ctrl::notify() const void thread_ctrl::notify()
{ {
initialize_once();
m_data->cond.notify_one(); m_data->cond.notify_one();
} }
thread_ctrl::internal* thread_ctrl::get_data() const void thread_ctrl::set_exception(std::exception_ptr e)
{ {
initialize_once(); m_data->exception = e;
return m_data; }
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() named_thread::~named_thread()
{ {
LOG_TRACE(GENERAL, "%s", __func__);
} }
std::string named_thread::get_name() const std::string named_thread::get_name() const

View File

@ -1,8 +1,8 @@
#pragma once #pragma once
#include <exception>
#include <string> #include <string>
#include <memory> #include <memory>
#include <thread>
#include "Platform.h" #include "Platform.h"
#include "Atomic.h" #include "Atomic.h"
@ -28,38 +28,41 @@ class task_stack
} }
}; };
template<typename F>
struct task_type : task_base
{
std::remove_reference_t<F> func;
task_type(F&& func)
: func(std::forward<F>(func))
{
}
void exec() override
{
func();
task_base::exec();
}
};
std::unique_ptr<task_base> m_stack; std::unique_ptr<task_base> m_stack;
public: public:
task_stack() = default;
template<typename F> template<typename F>
void push(F&& func) task_stack(F&& func)
: m_stack(new task_type<F>(std::forward<F>(func)))
{ {
struct task_t : task_base }
{
std::remove_reference_t<F> func;
task_t(F&& func) void push(task_stack stack)
: func(std::forward<F>(func)) {
{ auto _top = stack.m_stack.release();
}
void exec() override
{
func();
task_base::exec();
}
};
auto _top = new task_t(std::forward<F>(func));
auto _next = m_stack.release(); auto _next = m_stack.release();
m_stack.reset(_top); m_stack.reset(_top);
#ifndef _MSC_VER while (UNLIKELY(_top->next)) _top = _top->next.get();
_top->next.reset(_next); _top->next.reset(_next);
#else
auto& next = _top->next;
next.release();
next.reset(_next);
#endif
} }
void reset() void reset()
@ -79,42 +82,48 @@ public:
// Thread control class // Thread control class
class thread_ctrl final class thread_ctrl final
{ {
public: // TODO
struct internal; struct internal;
private:
static thread_local thread_ctrl* g_tls_this_thread; static thread_local thread_ctrl* g_tls_this_thread;
// Thread handle // Thread handle storage
std::thread m_thread; std::aligned_storage_t<16> m_thread;
// Thread join contention counter // Thread join contention counter
atomic_t<uint> m_joining{}; atomic_t<u32> m_joining{};
// Thread internals
atomic_t<internal*> m_data{};
// Fixed name // Fixed name
std::string m_name; std::string m_name;
// Thread internals // Start thread
mutable atomic_t<internal*> m_data{}; static void start(const std::shared_ptr<thread_ctrl>&, task_stack);
// Called at the thread start // Called at the thread start
void initialize(); void initialize();
// Set std::current_exception
void set_exception() noexcept;
// Called at the thread end // Called at the thread end
void finalize() noexcept; void finalize() noexcept;
// Get atexit function // 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: public:
template<typename N> thread_ctrl(std::string&& name);
thread_ctrl(N&& name)
: m_name(std::forward<N>(name))
{
}
// Disable copy/move constructors and operators
thread_ctrl(const thread_ctrl&) = delete; thread_ctrl(const thread_ctrl&) = delete;
~thread_ctrl(); ~thread_ctrl();
@ -126,54 +135,139 @@ public:
} }
// Initialize internal data // Initialize internal data
void initialize_once() const; void initialize_once();
// Get thread result (may throw, simultaneous joining allowed) // Get thread result (may throw, simultaneous joining allowed)
void join(); void join();
// Lock thread mutex
void lock();
// Lock conditionally (double-checked)
template<typename F>
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) // 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 // Notify the thread (internal data must be initialized)
void notify() const; void notify();
// // Set exception (internal data must be initialized, thread mutex must be locked)
internal* get_data() const; 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<typename F>
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<typename F>
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) // Get current thread (may be nullptr)
static const thread_ctrl* get_current() static thread_ctrl* get_current()
{ {
return g_tls_this_thread; return g_tls_this_thread;
} }
// Register function at thread exit (for the current thread) // Register function at thread exit (for the current thread)
template<typename F> template<typename F>
static inline void at_exit(F&& func) static inline void atexit(F&& func)
{ {
return g_tls_this_thread->get_atexit().push(std::forward<F>(func)); return g_tls_this_thread->push_atexit(std::forward<F>(func));
} }
// Named thread factory // Named thread factory
template<typename N, typename F, typename... Args> template<typename N, typename F>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func, Args&&... args) static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
{ {
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name)); auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](Args&&... args) thread_ctrl::start(ctrl, std::forward<F>(func));
{
try
{
ctrl->initialize();
task(std::forward<Args>(args)...);
}
catch (...)
{
ctrl->set_exception();
}
ctrl->finalize();
}, std::forward<Args>(args)...);
return ctrl; return ctrl;
} }
@ -218,22 +312,43 @@ public:
m_thread->join(); m_thread->join();
} }
// Get thread_ctrl // Access thread_ctrl
const thread_ctrl* operator->() const thread_ctrl* operator->() const
{ {
return m_thread.get(); return m_thread.get();
} }
};
// Lock mutex, notify condition variable // Simple thread mutex locker
void lock_notify() const 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 // Lock specified named_thread
void notify() const 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();
} }
}; };

View File

@ -17,10 +17,10 @@ namespace memory_helper
{ {
#ifdef _WIN32 #ifdef _WIN32
void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
Ensures(ret != NULL); ENSURES(ret != NULL);
#else #else
void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
Ensures(ret != 0); ENSURES(ret != 0);
#endif #endif
return ret; return ret;
} }
@ -28,18 +28,18 @@ namespace memory_helper
void commit_page_memory(void* pointer, size_t page_size) void commit_page_memory(void* pointer, size_t page_size)
{ {
#ifdef _WIN32 #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 #else
ASSERT(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); VERIFY(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1);
#endif #endif
} }
void free_reserved_memory(void* pointer, size_t size) void free_reserved_memory(void* pointer, size_t size)
{ {
#ifdef _WIN32 #ifdef _WIN32
ASSERT(VirtualFree(pointer, 0, MEM_RELEASE) != 0); VERIFY(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
#else #else
ASSERT(munmap(pointer, size) == 0); VERIFY(munmap(pointer, size) == 0);
#endif #endif
} }
} }

105
Utilities/lockless.h Normal file
View File

@ -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<typename T, std::size_t N>
class lf_array
{
// Data (default-initialized)
T m_data[N]{};
// Next array block
atomic_t<lf_array*> 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<T, N> 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<typename T, std::size_t N>
class lf_fifo : public lf_array<T, N>
{
struct alignas(8) ctrl_t
{
u32 push;
u32 pop;
};
atomic_t<ctrl_t> m_ctrl{};
public:
constexpr lf_fifo() = default;
// Get current "push" position
u32 size()
{
return reinterpret_cast<atomic_t<u32>&>(m_ctrl).load(); // Hack
}
// Acquire the place for one or more elements.
u32 push_begin(u32 count = 1)
{
return reinterpret_cast<atomic_t<u32>&>(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;
});
}
};

192
Utilities/sync.h Normal file
View File

@ -0,0 +1,192 @@
#pragma once
/* For internal use. Don't include. */
#include "types.h"
#include "Macro.h"
#include "Atomic.h"
#ifdef _WIN32
#include <Windows.h>
#define DYNAMIC_IMPORT(handle, name) do { name = reinterpret_cast<decltype(name)>(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<typename F>
inline void keyed_wait(atomic_t<u32>& 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<u32>& 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*));

View File

@ -407,12 +407,22 @@ struct ignore
} }
}; };
// Simplified hash algorithm for pointers. May be used in std::unordered_(map|set).
template<typename T, std::size_t Align = alignof(T)>
struct pointer_hash
{
std::size_t operator()(T* ptr) const
{
return reinterpret_cast<std::uintptr_t>(ptr) / Align;
}
};
// Contains value of any POD type with fixed size and alignment. TT<> is the type converter applied. // 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. // For example, `simple_t` may be used to remove endianness.
template<template<typename> class TT, std::size_t S, std::size_t A = S> template<template<typename> class TT, std::size_t S, std::size_t A = S>
struct alignas(A) any_pod struct alignas(A) any_pod
{ {
enum class byte : char {} data[S]; std::aligned_storage_t<S, A> data;
any_pod() = default; any_pod() = default;

View File

@ -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. 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() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fexceptions") 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() 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") 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() endif()

View File

@ -24,7 +24,7 @@ void AudioDumper::WriteData(const void* buffer, u32 size)
{ {
if (GetCh()) if (GetCh())
{ {
ASSERT(m_output.write(buffer, size) == size); VERIFY(m_output.write(buffer, size) == size);
m_header.Size += size; m_header.Size += size;
m_header.RIFF.Size += size; m_header.RIFF.Size += size;
} }

View File

@ -1,15 +1,15 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.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 "CPUThread.h"
#include <mutex>
#include <condition_variable>
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr; 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() void cpu_thread::on_task()
{ {
state -= cpu_state::exit; state -= cpu_state::exit;
@ -61,7 +61,7 @@ void cpu_thread::on_task()
void cpu_thread::on_stop() void cpu_thread::on_stop()
{ {
state += cpu_state::exit; state += cpu_state::exit;
lock_notify(); (*this)->lock_notify();
} }
cpu_thread::~cpu_thread() cpu_thread::~cpu_thread()
@ -121,35 +121,3 @@ bool cpu_thread::check_status()
return false; return false;
} }
[[noreturn]] void cpu_thread::xsleep()
{
throw std::runtime_error("cpu_thread: sleep()/awake() inconsistency");
}
std::vector<std::shared_ptr<cpu_thread>> get_all_cpu_threads()
{
std::vector<std::shared_ptr<cpu_thread>> result;
for (auto& t : idm::get_all<PPUThread>())
{
result.emplace_back(t);
}
for (auto& t : idm::get_all<SPUThread>())
{
result.emplace_back(t);
}
for (auto& t : idm::get_all<RawSPUThread>())
{
result.emplace_back(t);
}
for (auto& t : idm::get_all<ARMv7Thread>())
{
result.emplace_back(t);
}
return result;
}

View File

@ -40,7 +40,6 @@ public:
const std::string name; const std::string name;
const cpu_type type; const cpu_type type;
const id_value<> id{}; const id_value<> id{};
cpu_thread(cpu_type type, const std::string& name); cpu_thread(cpu_type type, const std::string& name);
@ -48,36 +47,34 @@ public:
// Public thread state // Public thread state
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop }; atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
// Recursively enter sleep state // Public recursive sleep state counter
void sleep() atomic_t<u32> sleep_counter{};
{
if (!++m_sleep) xsleep();
}
// Leave sleep state // Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.)
void awake() atomic_t<void*> owner{};
{
if (!m_sleep--) xsleep();
}
// Process thread state, return true if the checker must return // Process thread state, return true if the checker must return
bool check_status(); 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_init() {}
virtual void cpu_task() = 0; virtual void cpu_task() = 0;
virtual bool handle_interrupt() { return false; } virtual bool handle_interrupt() { return false; }
private:
[[noreturn]] void xsleep();
// Sleep/Awake counter
atomic_t<u32> 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 inline cpu_thread* get_current_cpu_thread() noexcept
{ {
extern thread_local cpu_thread* g_tls_current_cpu_thread; 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; return g_tls_current_cpu_thread;
} }
extern std::vector<std::shared_ptr<cpu_thread>> 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();
}
};

88
rpcs3/Emu/IPC.h Normal file
View File

@ -0,0 +1,88 @@
#pragma once
#include <memory>
#include <unordered_map>
#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<typename T, typename K>
class ipc_manager final
{
std::unordered_map<K, std::weak_ptr<T>> m_map;
shared_mutex m_mutex;
static ipc_manager g_ipc;
public:
// Add new object if specified ipc_key is not used
template<typename F>
static bool add(const K& ipc_key, F&& provider)
{
writer_lock lock(g_ipc.m_mutex);
// Get object location
std::weak_ptr<T>& 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<T> 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<T> 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();
}
};

View File

@ -1,10 +1,17 @@
#include "stdafx.h" #include "stdafx.h"
#include "IdManager.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>& id_manager::typeinfo::access() std::vector<id_manager::typeinfo>& id_manager::typeinfo::access()
{ {
static std::vector<typeinfo> list; static std::vector<typeinfo> list;
return list; return list;
} }

View File

@ -8,8 +8,6 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <set>
#include <map>
// Mostly helper namespace // Mostly helper namespace
namespace id_manager namespace id_manager
@ -37,7 +35,7 @@ namespace id_manager
template<typename T, typename = void> template<typename T, typename = void>
struct on_init struct on_init
{ {
static void func(T*) static inline void func(T*)
{ {
} }
}; };
@ -45,7 +43,7 @@ namespace id_manager
template<typename T> template<typename T>
struct on_init<T, decltype(std::declval<T>().on_init())> struct on_init<T, decltype(std::declval<T>().on_init())>
{ {
static void func(T* ptr) static inline void func(T* ptr)
{ {
ptr->on_init(); ptr->on_init();
} }
@ -55,7 +53,7 @@ namespace id_manager
template<typename T, typename = void> template<typename T, typename = void>
struct on_stop struct on_stop
{ {
static void func(T*) static inline void func(T*)
{ {
} }
}; };
@ -63,7 +61,7 @@ namespace id_manager
template<typename T> template<typename T>
struct on_stop<T, decltype(std::declval<T>().on_stop())> struct on_stop<T, decltype(std::declval<T>().on_stop())>
{ {
static void func(T* ptr) static inline void func(T* ptr)
{ {
ptr->on_stop(); ptr->on_stop();
} }
@ -155,15 +153,41 @@ class idm
// Update optional ID storage // Update optional ID storage
template<typename T> template<typename T>
static auto set_id_value(T* ptr, u32 id) -> decltype(static_cast<void>(std::declval<T&>().id)) static inline auto set_id_value(T* ptr, u32 id) -> decltype(static_cast<void>(std::declval<T&>().id))
{ {
ptr->id = id; ptr->id = id;
} }
static void set_id_value(...) static inline void set_id_value(...)
{ {
} }
// Helper
template<typename F>
struct function_traits;
template<typename F, typename R, typename A1, typename A2>
struct function_traits<R(F::*)(A1, A2&) const>
{
using second_type = A2;
using return_type = R;
};
// Helper
template<bool Value>
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 // Prepares new ID, returns nullptr if out of resources
static map_type::pointer allocate_id(u32 tag, u32 min, u32 max); 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) // Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
template<typename T, typename Make = T, typename... Args> template<typename T, typename Make = T, typename... Args>
static std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> make_ptr(Args&&... args) static inline std::enable_if_t<std::is_constructible<Make, Args...>::value, std::shared_ptr<T>> make_ptr(Args&&... args)
{ {
if (auto pair = create_id<T>(WRAP_EXPR(std::make_shared<Make>(std::forward<Args>(args)...)))) if (auto pair = create_id<T>(WRAP_EXPR(std::make_shared<Make>(std::forward<Args>(args)...))))
{ {
@ -226,7 +250,7 @@ public:
// Add a new ID of specified type with specified constructor arguments (returns id) // Add a new ID of specified type with specified constructor arguments (returns id)
template<typename T, typename Make = T, typename... Args> template<typename T, typename Make = T, typename... Args>
static std::enable_if_t<std::is_constructible<Make, Args...>::value, u32> make(Args&&... args) static inline std::enable_if_t<std::is_constructible<Make, Args...>::value, u32> make(Args&&... args)
{ {
if (auto pair = create_id<T>(WRAP_EXPR(std::make_shared<Make>(std::forward<Args>(args)...)))) if (auto pair = create_id<T>(WRAP_EXPR(std::make_shared<Make>(std::forward<Args>(args)...))))
{ {
@ -239,7 +263,7 @@ public:
// Add a new ID for an existing object provided (returns new id) // Add a new ID for an existing object provided (returns new id)
template<typename T> template<typename T>
static u32 import_existing(const std::shared_ptr<T>& ptr) static inline u32 import_existing(const std::shared_ptr<T>& ptr)
{ {
if (auto pair = create_id<T>(WRAP_EXPR(ptr))) if (auto pair = create_id<T>(WRAP_EXPR(ptr)))
{ {
@ -252,7 +276,7 @@ public:
// Add a new ID for an object returned by provider() // Add a new ID for an object returned by provider()
template<typename T, typename F, typename = std::result_of_t<F()>> template<typename T, typename F, typename = std::result_of_t<F()>>
static std::shared_ptr<T> import(F&& provider) static inline std::shared_ptr<T> import(F&& provider)
{ {
if (auto pair = create_id<T>(std::forward<F>(provider))) if (auto pair = create_id<T>(std::forward<F>(provider)))
{ {
@ -263,18 +287,18 @@ public:
return nullptr; return nullptr;
} }
// Check whether ID exists // Check whether the ID exists
template<typename T> template<typename T>
static bool check(u32 id) static inline bool check(u32 id)
{ {
reader_lock lock(g_mutex); reader_lock lock(g_mutex);
return find_id(get_type<T>(), id) != nullptr; return find_id(get_type<T>(), id) != nullptr;
} }
// Get ID // Get the ID
template<typename T> template<typename T>
static std::shared_ptr<T> get(u32 id) static inline std::shared_ptr<T> get(u32 id)
{ {
reader_lock lock(g_mutex); reader_lock lock(g_mutex);
@ -288,25 +312,63 @@ public:
return{ found->second, static_cast<T*>(found->second.get()) }; return{ found->second, static_cast<T*>(found->second.get()) };
} }
// Get all IDs (unsorted) // Conditionally get the ID, almost similar to select() but for the single object only.
template<typename T, typename F, typename FT = decltype(&F::operator()), typename A2 = typename function_traits<FT>::second_type>
static inline auto get(u32 id, F&& pred)
{
using result_type = std::conditional_t<std::is_void<typename function_traits<FT>::return_type>::value, void, std::shared_ptr<A2>>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), id);
if (UNLIKELY(found == nullptr))
{
return static_cast<result_type>(nullptr);
}
if (pred(id, *static_cast<A2*>(found->second.get())), bool_if_void<false>())
{
return static_cast<result_type>(std::static_pointer_cast<A2>(found->second));
}
return static_cast<result_type>(nullptr);
}
// Execute for all IDs (unsorted), may return void. If the result evaluates to true, the loop stops and returns the object.
template<typename... Types, typename F, typename FT = decltype(&F::operator()), typename A2 = typename function_traits<FT>::second_type>
static inline auto select(F&& pred)
{
using result_type = std::conditional_t<std::is_void<typename function_traits<FT>::return_type>::value, void, std::shared_ptr<A2>>;
reader_lock lock(g_mutex);
for (u32 type : { get_type<Types>()... })
{
for (auto& id : g_map[type])
{
if (pred(id.first, *static_cast<A2*>(id.second.get())), bool_if_void<false>())
{
return static_cast<result_type>(std::static_pointer_cast<A2>(id.second));
}
}
}
return static_cast<result_type>(nullptr);
}
// Get count of objects
template<typename T> template<typename T>
static std::vector<std::shared_ptr<T>> get_all() static inline u32 get_count()
{ {
reader_lock lock(g_mutex); reader_lock lock(g_mutex);
std::vector<std::shared_ptr<T>> result; return ::size32(g_map[get_type<T>()]);
for (auto& id : g_map[get_type<T>()])
{
result.emplace_back(id.second, static_cast<T*>(id.second.get()));
}
return result;
} }
// Remove the ID // Remove the ID
template<typename T> template<typename T>
static bool remove(u32 id) static inline bool remove(u32 id)
{ {
auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id); auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id);
@ -320,7 +382,7 @@ public:
// Remove the ID and return it // Remove the ID and return it
template<typename T> template<typename T>
static std::shared_ptr<T> withdraw(u32 id) static inline std::shared_ptr<T> withdraw(u32 id)
{ {
auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id); auto&& ptr = delete_id(get_type<T>(), get_tag<T>(), id);
@ -332,44 +394,29 @@ public:
return{ ptr, static_cast<T*>(ptr.get()) }; return{ ptr, static_cast<T*>(ptr.get()) };
} }
template<typename T> // Conditionally remove the ID and return it.
static u32 get_count() template<typename T, typename F>
static inline std::shared_ptr<T> withdraw(u32 id, F&& pred)
{ {
reader_lock lock(g_mutex); std::shared_ptr<void> ptr;
return ::size32(g_map[get_type<T>()]);
}
// Get sorted list of all IDs of specified type
template<typename T>
static std::set<u32> get_set()
{
reader_lock lock(g_mutex);
std::set<u32> result;
for (auto& id : g_map[get_type<T>()])
{ {
result.emplace(id.first); writer_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), id);
if (UNLIKELY(found == nullptr || !pred(id, *static_cast<T*>(found->second.get()))))
{
return nullptr;
}
ptr = deallocate_id(get_tag<T>(), id);
g_map[get_type<T>()].erase(id);
} }
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
return result; return{ ptr, static_cast<T*>(ptr.get()) };
}
// Get sorted map (ID value -> ID data) of all IDs of specified type
template<typename T>
static std::map<u32, std::shared_ptr<T>> get_map()
{
reader_lock lock(g_mutex);
std::map<u32, std::shared_ptr<T>> result;
for (auto& id : g_map[get_type<T>()])
{
result[id.first] = { id.second, static_cast<T*>(id.second.get()) };
}
return result;
} }
}; };
@ -518,7 +565,7 @@ public:
// Check whether the object exists // Check whether the object exists
template<typename T> template<typename T>
static bool check() static inline bool check()
{ {
reader_lock lock(g_mutex); reader_lock lock(g_mutex);
@ -527,7 +574,7 @@ public:
// Get the object (returns nullptr if it doesn't exist) // Get the object (returns nullptr if it doesn't exist)
template<typename T> template<typename T>
static std::shared_ptr<T> get() static inline std::shared_ptr<T> get()
{ {
reader_lock lock(g_mutex); reader_lock lock(g_mutex);
@ -538,7 +585,7 @@ public:
// Delete the object // Delete the object
template<typename T> template<typename T>
static bool remove() static inline bool remove()
{ {
auto&& ptr = remove(get_type<T>()); auto&& ptr = remove(get_type<T>());
@ -552,7 +599,7 @@ public:
// Delete the object and return it // Delete the object and return it
template<typename T> template<typename T>
static std::shared_ptr<T> withdraw() static inline std::shared_ptr<T> withdraw()
{ {
auto&& ptr = remove(get_type<T>()); auto&& ptr = remove(get_type<T>());

View File

@ -18,7 +18,7 @@ bool VirtualMemoryBlock::IsInMyRange(const u32 addr, const u32 size)
u32 VirtualMemoryBlock::Map(u32 realaddr, 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;) 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) bool VirtualMemoryBlock::Map(u32 realaddr, u32 size, u32 addr)
{ {
Expects(size); EXPECTS(size);
if (!IsInMyRange(addr, size)) if (!IsInMyRange(addr, size))
{ {

View File

@ -5,7 +5,7 @@
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h" #include "Emu/PSP2/ARMv7Thread.h"
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <Windows.h>
@ -93,66 +93,15 @@ namespace vm
std::vector<std::shared_ptr<block_t>> g_locations; // memory locations std::vector<std::shared_ptr<block_t>> g_locations; // memory locations
//using reservation_mutex_t = std::mutex; access_violation::access_violation(u64 addr, const char* cause)
: std::runtime_error(fmt::exception("Access violation %s address 0x%llx", cause, addr))
class reservation_mutex_t
{ {
atomic_t<bool> m_lock{ false }; g_tls_fault_count &= ~(1ull << 63);
std::thread::id m_owner{}; }
std::condition_variable m_cv; using reservation_mutex_t = std::mutex;
std::mutex m_mutex;
public: thread_ctrl* volatile g_reservation_owner = nullptr;
bool do_notify = false;
never_inline void lock()
{
std::unique_lock<std::mutex> 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<std::mutex> lock(m_mutex);
m_cv.notify_one();
}
}
};
const thread_ctrl* volatile g_reservation_owner = nullptr;
u32 g_reservation_addr = 0; u32 g_reservation_addr = 0;
u32 g_reservation_size = 0; u32 g_reservation_size = 0;
@ -161,14 +110,6 @@ namespace vm
reservation_mutex_t g_reservation_mutex; 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) void _reservation_set(u32 addr, bool no_access = false)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -320,7 +261,7 @@ namespace vm
return true; return true;
} }
bool reservation_test(const thread_ctrl* current) bool reservation_test(thread_ctrl* current)
{ {
const auto owner = g_reservation_owner; const auto owner = g_reservation_owner;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <mutex>
class thread_ctrl; class thread_ctrl;
@ -32,6 +33,9 @@ namespace vm
page_allocated = (1 << 7), page_allocated = (1 << 7),
}; };
// Address type
enum addr_t : u32 {};
struct access_violation : std::runtime_error struct access_violation : std::runtime_error
{ {
access_violation(u64 addr, const char* cause); 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<bool()> callback); bool reservation_query(u32 addr, u32 size, bool is_writing, std::function<bool()> callback);
// Returns true if the current thread owns reservation // 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 // Break all reservations created by the current thread
void reservation_free(); void reservation_free();
@ -133,11 +137,11 @@ namespace vm
std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0); std::shared_ptr<block_t> get(memory_location_t location, u32 addr = 0);
// Get PS3/PSV virtual memory address from the provided pointer (nullptr always converted to 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) if (!real_ptr)
{ {
return 0; return vm::addr_t{};
} }
const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr; const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr;
@ -145,7 +149,7 @@ namespace vm
if (res == diff) if (res == diff)
{ {
return res; return static_cast<vm::addr_t>(res);
} }
throw fmt::exception("Not a virtual memory pointer (%p)", real_ptr); throw fmt::exception("Not a virtual memory pointer (%p)", real_ptr);
@ -166,36 +170,57 @@ namespace vm
template<> template<>
struct cast_impl<u32> struct cast_impl<u32>
{ {
static u32 cast(const u32& addr, const char* loc) static vm::addr_t cast(u32 addr, const char* loc)
{ {
return addr; return static_cast<vm::addr_t>(addr);
}
static vm::addr_t cast(u32 addr)
{
return static_cast<vm::addr_t>(addr);
} }
}; };
template<> template<>
struct cast_impl<u64> struct cast_impl<u64>
{ {
static u32 cast(const u64& addr, const char* loc) static vm::addr_t cast(u64 addr, const char* loc)
{ {
return fmt::narrow<u32>("Memory address out of range: 0x%llx%s", addr, loc); return static_cast<vm::addr_t>(fmt::narrow<u32>("Memory address out of range: 0x%llx%s", addr, loc));
}
static vm::addr_t cast(u64 addr)
{
return static_cast<vm::addr_t>(fmt::narrow<u32>("Memory address out of range: 0x%llx", addr));
} }
}; };
template<typename T, bool Se> template<typename T, bool Se>
struct cast_impl<se_t<T, Se>> struct cast_impl<se_t<T, Se>>
{ {
static u32 cast(const se_t<T, Se>& addr, const char* loc) static vm::addr_t cast(const se_t<T, Se>& addr, const char* loc)
{ {
return cast_impl<T>::cast(addr, loc); return cast_impl<T>::cast(addr, loc);
} }
static vm::addr_t cast(const se_t<T, Se>& addr)
{
return cast_impl<T>::cast(addr);
}
}; };
template<typename T> template<typename T>
u32 cast(const T& addr, const char* loc) vm::addr_t cast(const T& addr, const char* loc)
{ {
return cast_impl<T>::cast(addr, loc); return cast_impl<T>::cast(addr, loc);
} }
template<typename T>
vm::addr_t cast(const T& addr)
{
return cast_impl<T>::cast(addr);
}
// Convert specified PS3/PSV virtual memory address to a pointer for common access // Convert specified PS3/PSV virtual memory address to a pointer for common access
inline void* base(u32 addr) inline void* base(u32 addr)
{ {

View File

@ -25,12 +25,12 @@ namespace vm
_ptr_base() = default; _ptr_base() = default;
constexpr _ptr_base(addr_type addr, const addr_tag_t&) _ptr_base(vm::addr_t addr)
: m_addr(addr) : m_addr(addr)
{ {
} }
constexpr addr_type addr() const addr_type addr() const
{ {
return m_addr; return m_addr;
} }
@ -40,19 +40,21 @@ namespace vm
this->m_addr = addr; 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 // Enable only the conversions which are originally possible between pointer types
template<typename T2, typename AT2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>> template<typename T2, typename AT2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>>
operator _ptr_base<T2, AT2>() const operator _ptr_base<T2, AT2>() 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; return m_addr != 0;
} }
@ -61,34 +63,34 @@ namespace vm
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> template<typename MT, typename T2, typename = if_comparable_t<T, T2>>
_ptr_base<MT> ptr(MT T2::*const mptr) const _ptr_base<MT> 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 // Get vm pointer to a struct member with array subscription
template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>> template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>>
_ptr_base<ET> ptr(MT T2::*const mptr, u32 index) const _ptr_base<ET> 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 // Get vm reference to a struct member
template<typename MT, typename T2, typename = if_comparable_t<T, T2>> template<typename MT, typename T2, typename = if_comparable_t<T, T2>>
_ref_base<MT> ref(MT T2::*const mptr) const _ref_base<MT> 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 // Get vm reference to a struct member with array subscription
template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>> template<typename MT, typename T2, typename ET = std::remove_extent_t<MT>, typename = if_comparable_t<T, T2>>
_ref_base<ET> ref(MT T2::*const mptr, u32 index) const _ref_base<ET> 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 // Get vm reference
_ref_base<T, u32> ref() const _ref_base<T, u32> ref() const
{ {
return{ vm::cast(m_addr, HERE), vm::addr }; return vm::cast(m_addr, HERE);
} }
T* get_ptr() const T* get_ptr() const
@ -136,22 +138,22 @@ namespace vm
_ptr_base<T, u32> operator +() const _ptr_base<T, u32> operator +() const
{ {
return{ vm::cast(m_addr, HERE), vm::addr }; return vm::cast(m_addr, HERE);
} }
_ptr_base<T, u32> operator +(u32 count) const _ptr_base<T, u32> 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<T, u32> operator -(u32 count) const _ptr_base<T, u32> 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<T, u32> operator +(u32 count, const _ptr_base& ptr) friend _ptr_base<T, u32> 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 // Pointer difference operator
@ -163,9 +165,9 @@ namespace vm
_ptr_base operator ++(int) _ptr_base operator ++(int)
{ {
const addr_type result = m_addr; _ptr_base result = *this;
m_addr = vm::cast(m_addr, HERE) + SIZE_32(T); m_addr = vm::cast(m_addr, HERE) + SIZE_32(T);
return{ result, vm::addr }; return result;
} }
_ptr_base& operator ++() _ptr_base& operator ++()
@ -176,9 +178,9 @@ namespace vm
_ptr_base operator --(int) _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); m_addr = vm::cast(m_addr, HERE) - SIZE_32(T);
return{ result, vm::addr }; return result;
} }
_ptr_base& operator --() _ptr_base& operator --()
@ -210,12 +212,12 @@ namespace vm
_ptr_base() = default; _ptr_base() = default;
constexpr _ptr_base(addr_type addr, const addr_tag_t&) _ptr_base(vm::addr_t addr)
: m_addr(addr) : m_addr(addr)
{ {
} }
constexpr addr_type addr() const addr_type addr() const
{ {
return m_addr; return m_addr;
} }
@ -225,26 +227,28 @@ namespace vm
m_addr = addr; 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 // Conversion to another function pointer
template<typename AT2> template<typename AT2>
operator _ptr_base<RT(T...), AT2>() const operator _ptr_base<RT(T...), AT2>() 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; return m_addr != 0;
} }
_ptr_base<RT(T...), u32> operator +() const _ptr_base<RT(T...), u32> 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 // Callback; defined in PPUCallback.h, passing context is mandatory
@ -305,14 +309,14 @@ namespace vm
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_be_t<CT>*>(std::declval<T*>()))> template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_be_t<CT>*>(std::declval<T*>()))>
inline _ptr_base<to_be_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other) inline _ptr_base<to_be_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return{ vm::cast(other.addr(), HERE), vm::addr }; return vm::cast(other.addr(), HERE);
} }
// Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>) // Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_be_t<CT>*>(std::declval<T*>()))> template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_be_t<CT>*>(std::declval<T*>()))>
inline _ptr_base<to_be_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other) inline _ptr_base<to_be_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return{ vm::cast(other.addr(), HERE), vm::addr }; return vm::cast(other.addr(), HERE);
} }
} }
@ -343,93 +347,93 @@ namespace vm
template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_le_t<CT>*>(std::declval<T*>()))> template<typename CT, typename T, typename AT, typename = decltype(static_cast<to_le_t<CT>*>(std::declval<T*>()))>
inline _ptr_base<to_le_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other) inline _ptr_base<to_le_t<CT>> static_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return{ vm::cast(other.addr(), HERE), vm::addr }; return vm::cast(other.addr(), HERE);
} }
// Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>) // Perform const_cast (for example, vm::cptr<char> to vm::ptr<char>)
template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_le_t<CT>*>(std::declval<T*>()))> template<typename CT, typename T, typename AT, typename = decltype(const_cast<to_le_t<CT>*>(std::declval<T*>()))>
inline _ptr_base<to_le_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other) inline _ptr_base<to_le_t<CT>> const_ptr_cast(const _ptr_base<T, AT>& other)
{ {
return{ vm::cast(other.addr(), HERE), vm::addr }; return vm::cast(other.addr(), HERE);
} }
} }
struct null_t struct null_t
{ {
template<typename T, typename AT> template<typename T, typename AT>
constexpr operator _ptr_base<T, AT>() const operator _ptr_base<T, AT>() const
{ {
return _ptr_base<T, AT>{ 0, vm::addr }; return _ptr_base<T, AT>{};
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator ==(const null_t&, const _ptr_base<T, AT>& ptr) friend bool operator ==(const null_t&, const _ptr_base<T, AT>& ptr)
{ {
return !ptr; return !ptr;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator ==(const _ptr_base<T, AT>& ptr, const null_t&) friend bool operator ==(const _ptr_base<T, AT>& ptr, const null_t&)
{ {
return !ptr; return !ptr;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator !=(const null_t&, const _ptr_base<T, AT>& ptr) friend bool operator !=(const null_t&, const _ptr_base<T, AT>& ptr)
{ {
return ptr.operator bool(); return ptr.operator bool();
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator !=(const _ptr_base<T, AT>& ptr, const null_t&) friend bool operator !=(const _ptr_base<T, AT>& ptr, const null_t&)
{ {
return ptr.operator bool(); return ptr.operator bool();
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator <(const null_t&, const _ptr_base<T, AT>& ptr) friend bool operator <(const null_t&, const _ptr_base<T, AT>& ptr)
{ {
return ptr.operator bool(); return ptr.operator bool();
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator <(const _ptr_base<T, AT>&, const null_t&) friend bool operator <(const _ptr_base<T, AT>&, const null_t&)
{ {
return false; return false;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator <=(const null_t&, const _ptr_base<T, AT>&) friend bool operator <=(const null_t&, const _ptr_base<T, AT>&)
{ {
return true; return true;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator <=(const _ptr_base<T, AT>& ptr, const null_t&) friend bool operator <=(const _ptr_base<T, AT>& ptr, const null_t&)
{ {
return !ptr.operator bool(); return !ptr.operator bool();
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator >(const null_t&, const _ptr_base<T, AT>&) friend bool operator >(const null_t&, const _ptr_base<T, AT>&)
{ {
return false; return false;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator >(const _ptr_base<T, AT>& ptr, const null_t&) friend bool operator >(const _ptr_base<T, AT>& ptr, const null_t&)
{ {
return ptr.operator bool(); return ptr.operator bool();
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator >=(const null_t&, const _ptr_base<T, AT>& ptr) friend bool operator >=(const null_t&, const _ptr_base<T, AT>& ptr)
{ {
return !ptr; return !ptr;
} }
template<typename T, typename AT> template<typename T, typename AT>
friend constexpr bool operator >=(const _ptr_base<T, AT>&, const null_t&) friend bool operator >=(const _ptr_base<T, AT>&, const null_t&)
{ {
return true; return true;
} }

View File

@ -2,9 +2,6 @@
namespace vm namespace vm
{ {
// Tag which allows to construct vm objects from the address value
static struct addr_tag_t {} constexpr addr{};
template<typename T, typename AT> template<typename T, typename AT>
class _ptr_base; class _ptr_base;
@ -26,12 +23,12 @@ namespace vm
_ref_base(const _ref_base&) = default; _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) : m_addr(addr)
{ {
} }
constexpr addr_type addr() const addr_type addr() const
{ {
return m_addr; return m_addr;
} }
@ -44,7 +41,7 @@ namespace vm
// convert to vm pointer // convert to vm pointer
vm::_ptr_base<T, u32> ptr() const vm::_ptr_base<T, u32> ptr() const
{ {
return{ vm::cast(m_addr, HERE), vm::addr }; return vm::cast(m_addr, HERE);
} }
operator simple_t<T>() const operator simple_t<T>() const

View File

@ -7,9 +7,9 @@ namespace vm
template<memory_location_t Location = vm::main> template<memory_location_t Location = vm::main>
struct page_allocator 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<u32>(align, 4096)); return vm::cast(vm::alloc(size, Location, std::max<u32>(align, 4096)));
} }
static inline void dealloc(u32 addr, u32 size = 0) noexcept static inline void dealloc(u32 addr, u32 size = 0) noexcept
@ -20,9 +20,9 @@ namespace vm
struct stack_allocator 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 static inline void dealloc(u32 addr, u32 size) noexcept
@ -39,7 +39,7 @@ namespace vm
public: public:
_var_base() _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: public:
_var_base(u32 count) _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) , m_size(SIZE_32(T) * count)
{ {
} }

View File

@ -6,98 +6,70 @@
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include "Utilities/SharedMutex.h" #include "Utilities/SharedMutex.h"
extern std::condition_variable& get_current_thread_cv(); #include <unordered_set>
extern std::mutex& get_current_thread_mutex();
namespace vm namespace vm
{ {
static shared_mutex s_mutex; static shared_mutex s_mutex;
static std::unordered_set<waiter*> s_waiters(256); static std::unordered_set<waiter_base*, pointer_hash<waiter_base>> s_waiters(256);
bool waiter::try_notify() void waiter_base::initialize(u32 addr, u32 size)
{ {
{ EXPECTS(addr && (size & (~size + 1)) == size && (addr & (size - 1)) == 0);
std::lock_guard<mutex_t> lock(*mutex);
try this->addr = addr;
{ this->mask = ~(size - 1);
// Test predicate this->thread = thread_ctrl::get_current();
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);
{ {
writer_lock lock(s_mutex); writer_lock lock(s_mutex);
s_waiters.emplace(this);
s_waiters.emplace(&m_waiter);
} }
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 const auto _t = atomic_storage<thread_ctrl*>::load(thread);
while (m_waiter.pred)
if (UNLIKELY(!_t))
{ {
// If pred() called by another thread threw an exception, it'll be rethrown // Return if thread not found
if (m_waiter.pred()) return false;
{
return;
}
CHECK_EMU_STATUS;
m_waiter.cond->wait(m_lock);
} }
// 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<thread_ctrl*>::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); writer_lock lock(s_mutex);
s_waiters.erase(this);
s_waiters.erase(&m_waiter);
} }
void notify_at(u32 addr, u32 size) 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); reader_lock lock(s_mutex);
std::size_t waiters = 0;
std::size_t signaled = 0; std::size_t signaled = 0;
for (const auto _w : s_waiters) for (const auto _w : s_waiters)
{ {
if (_w->addr) if (_w->try_notify())
{ {
waiters++; signaled++;
if (_w->try_notify())
{
signaled++;
}
} }
} }
// return true if waiter list is empty or all available waiters were signaled return s_waiters.size() - signaled;
return waiters == signaled;
} }
void start() void start()
{ {
// start notification thread thread_ctrl::spawn("vm::wait", []()
thread_ctrl::spawn("vm::start thread", []()
{ {
while (!Emu.IsStopped()) while (!Emu.IsStopped())
{ {
// poll waiters periodically (TODO) // Poll waiters periodically (TODO)
while (!notify_all() && !Emu.IsPaused()) 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);
} }
}); });
} }

View File

@ -1,61 +1,50 @@
#pragma once #pragma once
#include <mutex> #include "Utilities/types.h"
#include <condition_variable> #include "Utilities/Macro.h"
#include <functional>
class named_thread; class thread_ctrl;
namespace vm namespace vm
{ {
using mutex_t = std::mutex; struct waiter_base
using cond_t = std::condition_variable;
struct waiter
{ {
u32 addr; u32 addr;
u32 mask; u32 mask;
mutex_t* mutex; thread_ctrl* thread{};
cond_t* cond;
std::function<bool()> pred;
~waiter();
void initialize(u32 addr, u32 size);
bool try_notify(); 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<typename F>
auto wait_op(u32 addr, u32 size, F&& pred) -> decltype(static_cast<void>(pred()))
{ {
waiter m_waiter; if (LIKELY(pred())) return;
std::unique_lock<mutex_t> m_lock;
public: struct waiter : waiter_base
waiter_lock(u32 addr, u32 size);
waiter* operator ->()
{ {
return &m_waiter; std::conditional_t<sizeof(F) <= sizeof(void*), std::remove_reference_t<F>, F&&> func;
}
void wait(); waiter(F&& func)
: func(std::forward<F>(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 waiter(std::forward<F>(pred)).initialize(addr, size);
template<typename F, typename... Args>
auto wait_op(u32 addr, u32 size, F&& pred, Args&&... args) -> decltype(static_cast<void>(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();
} }
// Notify waiters on specific addr, addr must be aligned to size which must be a power of 2 // Notify waiters on specific addr, addr must be aligned to size which must be a power of 2

View File

@ -4,9 +4,11 @@
#include "CgBinaryProgram.h" #include "CgBinaryProgram.h"
#include "Emu/RSX/RSXFragmentProgram.h" #include "Emu/RSX/RSXFragmentProgram.h"
#include <algorithm>
void CgBinaryDisasm::AddCodeAsm(const std::string& code) void CgBinaryDisasm::AddCodeAsm(const std::string& code)
{ {
Expects(m_opcode < 70); EXPECTS(m_opcode < 70);
std::string op_name = ""; std::string op_name = "";
if (dst.dest_reg == 63) if (dst.dest_reg == 63)
@ -223,7 +225,7 @@ void CgBinaryDisasm::TaskFP()
{ {
m_size = 0; m_size = 0;
u32* data = (u32*)&m_buffer[m_offset]; 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++) for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++)
{ {
data[i] = se_storage<u32>::swap(data[i]); // WTF, cannot use be_t<> there? data[i] = se_storage<u32>::swap(data[i]); // WTF, cannot use be_t<> there?
@ -471,7 +473,7 @@ void CgBinaryDisasm::TaskFP()
break; break;
} }
Ensures(m_step % sizeof(u32) == 0); ENSURES(m_step % sizeof(u32) == 0);
data += m_step / sizeof(u32); data += m_step / sizeof(u32);
} }
} }

View File

@ -373,7 +373,7 @@ public:
m_offset = prog.ucode; m_offset = prog.ucode;
u32* vdata = (u32*)&m_buffer[m_offset]; 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++) for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++)
{ {
vdata[i] = se_storage<u32>::swap(vdata[i]); // WTF, cannot use be_t<> there? vdata[i] = se_storage<u32>::swap(vdata[i]); // WTF, cannot use be_t<> there?

View File

@ -6,13 +6,13 @@
void CgBinaryDisasm::AddScaCodeDisasm(const std::string& code) 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 + " "; m_arb_shader += rsx_vp_sca_op_names[m_sca_opcode] + code + " ";
} }
void CgBinaryDisasm::AddVecCodeDisasm(const std::string& 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 + " "; m_arb_shader += rsx_vp_vec_op_names[m_vec_opcode] + code + " ";
} }
@ -448,4 +448,4 @@ void CgBinaryDisasm::TaskVP()
} }
m_arb_shader += "END\n"; m_arb_shader += "END\n";
} }

View File

@ -48,7 +48,7 @@ namespace
void write_vertex_array_data_to_buffer(gsl::span<gsl::byte> 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) void write_vertex_array_data_to_buffer(gsl::span<gsl::byte> 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) switch (type)
{ {
@ -98,7 +98,7 @@ std::tuple<T, T> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::span<T>
T min_index = -1; T min_index = -1;
T max_index = 0; T max_index = 0;
Expects(dst.size_bytes() >= src.size_bytes()); EXPECTS(dst.size_bytes() >= src.size_bytes());
size_t dst_idx = 0; size_t dst_idx = 0;
for (T index : src) for (T index : src)
@ -124,7 +124,7 @@ std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gs
T min_index = -1; T min_index = -1;
T max_index = 0; T max_index = 0;
Expects(dst.size() >= 3 * (src.size() - 2)); EXPECTS(dst.size() >= 3 * (src.size() - 2));
const T index0 = src[0]; const T index0 = src[0];
if (!is_primitive_restart_enabled || index0 != -1) // Cut if (!is_primitive_restart_enabled || index0 != -1) // Cut
@ -174,7 +174,7 @@ std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span
T min_index = -1; T min_index = -1;
T max_index = 0; 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; size_t dst_idx = 0;
while (!src.empty()) while (!src.empty())
@ -353,7 +353,7 @@ std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic
u32 type_size = gsl::narrow<u32>(get_index_type_size(type)); u32 type_size = gsl::narrow<u32>(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]; bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX]; u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX];
@ -363,7 +363,7 @@ std::tuple<T, T> write_index_array_data_to_buffer_impl(gsl::span<T, gsl::dynamic
{ {
const std::tuple<u32, u32> &range = first_count_arguments[i]; const std::tuple<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1]; const std::tuple<u32, u32> &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 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; u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
@ -415,7 +415,7 @@ std::tuple<u32, u32> write_index_array_data_to_buffer_untouched(gsl::span<u32, g
{ {
const std::tuple<u32, u32> &range = first_count_arguments[i]; const std::tuple<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1]; const std::tuple<u32, u32> &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 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; u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
@ -438,7 +438,7 @@ std::tuple<u16, u16> write_index_array_data_to_buffer_untouched(gsl::span<u16, g
{ {
const std::tuple<u32, u32> &range = first_count_arguments[i]; const std::tuple<u32, u32> &range = first_count_arguments[i];
const std::tuple<u32, u32> &next_range = first_count_arguments[i + 1]; const std::tuple<u32, u32> &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 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; u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;

View File

@ -4,6 +4,8 @@
#include "FragmentProgramDecompiler.h" #include "FragmentProgramDecompiler.h"
#include <algorithm>
FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) : FragmentProgramDecompiler::FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size) :
m_prog(prog), m_prog(prog),
m_size(size), m_size(size),
@ -522,21 +524,21 @@ std::string FragmentProgramDecompiler::Decompile()
while (true) while (true)
{ {
for (auto 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);
finded != m_end_offsets.end(); found != m_end_offsets.end();
finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size)) 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--; m_code_level--;
AddCode("}"); AddCode("}");
m_loop_count--; m_loop_count--;
} }
for (auto 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);
finded != m_else_offsets.end(); found != m_else_offsets.end();
finded = std::find(m_else_offsets.begin(), m_else_offsets.end(), m_size)) 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--; m_code_level--;
AddCode("}"); AddCode("}");
AddCode("else"); AddCode("else");
@ -644,7 +646,7 @@ std::string FragmentProgramDecompiler::Decompile()
if (dst.end) break; if (dst.end) break;
Ensures(m_offset % sizeof(u32) == 0); ENSURES(m_offset % sizeof(u32) == 0);
data += m_offset / sizeof(u32); data += m_offset / sizeof(u32);
} }

View File

@ -227,7 +227,7 @@ public:
0x6, 0x7, 0x4, 0x5, 0x6, 0x7, 0x4, 0x5,
0x2, 0x3, 0x0, 0x1); 0x2, 0x3, 0x0, 0x1);
Expects(dst_buffer.size_bytes() >= gsl::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16); EXPECTS(dst_buffer.size_bytes() >= gsl::narrow<int>(I->second.FragmentConstantOffsetCache.size()) * 16);
size_t offset = 0; size_t offset = 0;
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache) for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)

View File

@ -152,7 +152,7 @@ public:
{ {
auto var_blocks = fmt::split(var, { "." }); auto var_blocks = fmt::split(var, { "." });
Expects(var_blocks.size() != 0); EXPECTS(var_blocks.size() != 0);
name = var_blocks[0]; name = var_blocks[0];

View File

@ -21,7 +21,7 @@ namespace
constexpr void copy(gsl::span<T1> dst, gsl::span<T2> src) constexpr void copy(gsl::span<T1> dst, gsl::span<T2> src)
{ {
static_assert(std::is_convertible<T1, T2>::value, "Cannot convert source and destination span type."); static_assert(std::is_convertible<T1, T2>::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()); std::copy(src.begin(), src.end(), dst.begin());
} }

View File

@ -3,6 +3,8 @@
#include "VertexProgramDecompiler.h" #include "VertexProgramDecompiler.h"
#include <algorithm>
std::string VertexProgramDecompiler::GetMask(bool is_sca) std::string VertexProgramDecompiler::GetMask(bool is_sca)
{ {
std::string ret; std::string ret;

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
#include "d3dx12.h" #include "d3dx12.h"
@ -78,7 +78,7 @@ std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attrib
u32 vertex_count = get_vertex_count(vertex_ranges); u32 vertex_count = get_vertex_count(vertex_ranges);
size_t offset_in_vertex_buffers_buffer = 0; size_t offset_in_vertex_buffers_buffer = 0;
u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; 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) for (int index = 0; index < rsx::limits::vertex_count; ++index)
{ {
@ -350,7 +350,7 @@ std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRe
return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list)); 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 // Index count
size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands))); size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands)));

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12CommonDecompiler.h" #include "D3D12CommonDecompiler.h"
std::string getFloatTypeNameImp(size_t elementCount) std::string getFloatTypeNameImp(size_t elementCount)

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12Formats.h" #include "D3D12Formats.h"
#include "D3D12Utils.h" #include "D3D12Utils.h"
#include "Emu/RSX/GCM.h" #include "Emu/RSX/GCM.h"

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12FragmentProgramDecompiler.h" #include "D3D12FragmentProgramDecompiler.h"
#include "D3D12CommonDecompiler.h" #include "D3D12CommonDecompiler.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
#include <wrl/client.h> #include <wrl/client.h>
@ -43,13 +43,13 @@ HMODULE D3DCompiler;
void loadD3D12FunctionPointers() void loadD3D12FunctionPointers()
{ {
ASSERT(D3D12Module = LoadLibrary(L"d3d12.dll")); VERIFY(D3D12Module = LoadLibrary(L"d3d12.dll"));
wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice"); wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice");
wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface"); wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface");
wrapD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)GetProcAddress(D3D12Module, "D3D12SerializeRootSignature"); 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"); 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"); 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]))) 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(); 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; size_t w = 0, h = 0, row_pitch = 0;

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12MemoryHelpers.h" #include "D3D12MemoryHelpers.h"

View File

@ -3,6 +3,7 @@
#include "d3dx12.h" #include "d3dx12.h"
#include "../Common/ring_buffer_helper.h" #include "../Common/ring_buffer_helper.h"
#include <list> #include <list>
#include <mutex>
struct d3d12_data_heap : public data_heap struct d3d12_data_heap : public data_heap
{ {

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
#include <d2d1_3.h> #include <d2d1_3.h>
#include <dwrite_3.h> #include <dwrite_3.h>

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "D3D12PipelineState.h" #include "D3D12PipelineState.h"
#include "D3D12GSRender.h" #include "D3D12GSRender.h"

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "D3D12RenderTargetSets.h" #include "D3D12RenderTargetSets.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
#include "d3dx12.h" #include "d3dx12.h"
#include "../Common/TextureUtils.h" #include "../Common/TextureUtils.h"

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12GSRender.h" #include "D3D12GSRender.h"
#include "d3dx12.h" #include "d3dx12.h"
#define STRINGIFY(x) #x #define STRINGIFY(x) #x

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h" #include "stdafx.h"
#include "stdafx_d3d12.h" #include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "D3D12VertexProgramDecompiler.h" #include "D3D12VertexProgramDecompiler.h"
#include "D3D12CommonDecompiler.h" #include "D3D12CommonDecompiler.h"
#include "Emu/System.h" #include "Emu/System.h"

View File

@ -4,6 +4,8 @@
#include "GLVertexProgram.h" #include "GLVertexProgram.h"
#include "GLCommonDecompiler.h" #include "GLCommonDecompiler.h"
#include <algorithm>
std::string GLVertexDecompilerThread::getFloatTypeName(size_t elementCount) std::string GLVertexDecompilerThread::getFloatTypeName(size_t elementCount)
{ {
return getFloatTypeNameImpl(elementCount); return getFloatTypeNameImpl(elementCount);

View File

@ -12,6 +12,8 @@
#include "Utilities/GSL.h" #include "Utilities/GSL.h"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#include <thread>
#define CMD_DEBUG 0 #define CMD_DEBUG 0
cfg::bool_entry g_cfg_rsx_write_color_buffers(cfg::root.video, "Write Color Buffers"); 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) void shaders_cache::load(const std::string &path, shader_language lang)
{ {
const std::string lang_name = bijective_find<shader_language>(lang, ""); const std::string lang_name(::unveil<shader_language>::get(lang));
auto extract_hash = [](const std::string &string) auto extract_hash = [](const std::string &string)
{ {
@ -174,7 +176,7 @@ namespace rsx
} }
throw EXCEPTION("Wrong vector size"); throw EXCEPTION("Wrong vector size");
case vertex_base_type::cmp: return sizeof(u16) * 4; 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); throw EXCEPTION("RSXVertexData::GetTypeSize: Bad vertex data type (%d)!", type);
} }
@ -561,7 +563,7 @@ namespace rsx
} }
else else
{ {
Expects(0); EXPECTS(0);
//std::lock_guard<std::mutex> lock{ m_mtx_task }; //std::lock_guard<std::mutex> lock{ m_mtx_task };
//internal_task_entry &front = m_internal_tasks.front(); //internal_task_entry &front = m_internal_tasks.front();

View File

@ -3,6 +3,7 @@
#include <stack> #include <stack>
#include <deque> #include <deque>
#include <set> #include <set>
#include <mutex>
#include "GCM.h" #include "GCM.h"
#include "RSXTexture.h" #include "RSXTexture.h"
#include "RSXVertexProgram.h" #include "RSXVertexProgram.h"
@ -52,13 +53,18 @@ namespace rsx
} }
template<> template<>
struct bijective<rsx::shader_language, const char*> struct unveil<rsx::shader_language>
{ {
static constexpr bijective_pair<rsx::shader_language, const char*> map[] static inline const char* get(rsx::shader_language in)
{ {
{ rsx::shader_language::glsl, "glsl" }, switch (in)
{ rsx::shader_language::hlsl, "hlsl" }, {
}; case rsx::shader_language::glsl: return "glsl";
case rsx::shader_language::hlsl: return "hlsl";
}
return "";
}
}; };
namespace rsx namespace rsx

View File

@ -99,7 +99,7 @@ namespace vk
size_t color_format_idx = 0; size_t color_format_idx = 0;
size_t depth_format_idx = 0; size_t depth_format_idx = 0;
Expects(color_count < 5); EXPECTS(color_count < 5);
switch (color_format) switch (color_format)
{ {

View File

@ -7,6 +7,8 @@
#include "rsx_utils.h" #include "rsx_utils.h"
#include "Emu/Cell/PPUCallback.h" #include "Emu/Cell/PPUCallback.h"
#include <thread>
cfg::map_entry<double> g_cfg_rsx_frame_limit(cfg::root.video, "Frame limit", cfg::map_entry<double> g_cfg_rsx_frame_limit(cfg::root.video, "Frame limit",
{ {
{ "Off", 0. }, { "Off", 0. },
@ -43,7 +45,7 @@ namespace rsx
if (Emu.IsStopped()) if (Emu.IsStopped())
break; break;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(1ms);
} }
} }
@ -253,7 +255,7 @@ namespace rsx
return; return;
} }
vm::ps3::ptr<CellGcmReportData> result = { get_address(offset, location), vm::addr }; vm::ps3::ptr<CellGcmReportData> result = vm::cast(get_address(offset, location));
result->timer = rsx->timestamp(); result->timer = rsx->timestamp();

View File

@ -5,8 +5,6 @@ extern "C"
#include <libavutil/pixfmt.h> #include <libavutil/pixfmt.h>
} }
#include <cmath>
namespace rsx namespace rsx
{ {
template<typename T> template<typename T>
@ -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 /* 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 * - 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 * - It will handle any width and height that are a power of 2, square or non square
@ -34,8 +38,8 @@ namespace rsx
template<typename T> template<typename T>
void convert_linear_swizzle(void* input_pixels, void* output_pixels, u16 width, u16 height, bool input_is_swizzled) void convert_linear_swizzle(void* input_pixels, void* output_pixels, u16 width, u16 height, bool input_is_swizzled)
{ {
u16 log2width = ::narrow<u16>(ceil(std::log2(width))); u32 log2width = ceil_log2(width);
u16 log2height = ::narrow<u16>(ceil(std::log2(height))); u32 log2height = ceil_log2(height);
// Max mask possible for square texture // Max mask possible for square texture
u32 x_mask = 0x55555555; u32 x_mask = 0x55555555;

View File

@ -9,7 +9,9 @@
#include "Emu/Cell/PPUCallback.h" #include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/Cell/lv2/sys_sync.h" #include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/PSP2/ARMv7Thread.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/RSX/GSRender.h" #include "Emu/RSX/GSRender.h"
@ -21,6 +23,8 @@
#include "../Crypto/unself.h" #include "../Crypto/unself.h"
#include <thread>
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot"); 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"); 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<u32> g_thread_count; extern atomic_t<u32> g_thread_count;
extern atomic_t<u32> g_ppu_core[2];
extern u64 get_system_time(); extern u64 get_system_time();
fs::file g_tty; fs::file g_tty;
@ -60,6 +66,9 @@ void Emulator::Init()
idm::init(); idm::init();
fxm::init(); fxm::init();
g_ppu_core[0] = 0;
g_ppu_core[1] = 0;
// Reset defaults, cache them // Reset defaults, cache them
cfg::root.from_default(); cfg::root.from_default();
g_cfg_defaults = cfg::root.to_string(); 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_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);
LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", bijective_find<elf_error>(ppu_exec, "???")); LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error());
LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", bijective_find<elf_error>(ppu_prx, "???")); LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec_loader -> %s", bijective_find<elf_error>(spu_exec, "???")); LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec_loader -> %s", bijective_find<elf_error>(arm_exec, "???")); LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error());
return; return;
} }
@ -294,11 +303,11 @@ void Emulator::Run()
m_pause_amend_time = 0; m_pause_amend_time = 0;
m_status = Running; m_status = Running;
for (auto& thread : get_all_cpu_threads()) idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{ {
thread->state -= cpu_state::stop; cpu.state -= cpu_state::stop;
thread->lock_notify(); cpu->lock_notify();
} });
SendDbgCommand(DID_STARTED_EMU); SendDbgCommand(DID_STARTED_EMU);
} }
@ -323,10 +332,10 @@ bool Emulator::Pause()
SendDbgCommand(DID_PAUSE_EMU); SendDbgCommand(DID_PAUSE_EMU);
for (auto& thread : get_all_cpu_threads()) idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{ {
thread->state += cpu_state::dbg_global_pause; cpu.state += cpu_state::dbg_global_pause;
} });
SendDbgCommand(DID_PAUSED_EMU); SendDbgCommand(DID_PAUSED_EMU);
@ -357,11 +366,11 @@ void Emulator::Resume()
SendDbgCommand(DID_RESUME_EMU); SendDbgCommand(DID_RESUME_EMU);
for (auto& thread : get_all_cpu_threads()) idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{ {
thread->state -= cpu_state::dbg_global_pause; cpu.state -= cpu_state::dbg_global_pause;
thread->lock_notify(); cpu->lock_notify();
} });
rpcs3::on_resume()(); rpcs3::on_resume()();
@ -383,11 +392,11 @@ void Emulator::Stop()
{ {
LV2_LOCK; LV2_LOCK;
for (auto& thread : get_all_cpu_threads()) idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{ {
thread->state += cpu_state::dbg_global_stop; cpu.state += cpu_state::dbg_global_stop;
thread->lock_notify(); cpu->lock_notify();
} });
} }
LOG_NOTICE(GENERAL, "All threads signaled..."); LOG_NOTICE(GENERAL, "All threads signaled...");
@ -424,16 +433,3 @@ void Emulator::Stop()
} }
Emulator Emu; 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<elf_error, const char*>::map);
constexpr DECLARE(bijective<_log::level, const char*>::map);
constexpr DECLARE(bijective<rsx::shader_language, const char*>::map);
#endif

View File

@ -2,6 +2,8 @@
#include "stdafx_gui.h" #include "stdafx_gui.h"
#include "Gui/ConLogFrame.h" #include "Gui/ConLogFrame.h"
#include <chrono>
enum enum
{ {
id_log_copy, // Copy log to ClipBoard id_log_copy, // Copy log to ClipBoard
@ -210,19 +212,19 @@ void LogFrame::OnTimer(wxTimerEvent& event)
if (text[pos + 2] == ' ') if (text[pos + 2] == ' ')
{ {
_log::level level; logs::level level;
wxColour color; wxColour color;
switch (text[pos + 1].GetValue()) switch (text[pos + 1].GetValue())
{ {
case 'A': level = _log::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan case 'A': level = logs::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan
case 'F': level = _log::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia case 'F': level = logs::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia
case 'E': level = _log::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red case 'E': level = logs::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red
case 'U': level = _log::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange case 'U': level = logs::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange
case 'S': level = _log::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green case 'S': level = logs::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green
case 'W': level = _log::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow case 'W': level = logs::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow
case '!': level = _log::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White case '!': level = logs::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White
case 'T': level = _log::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray case 'T': level = logs::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray
default: continue; default: continue;
} }

View File

@ -5,7 +5,7 @@ class LogFrame : public wxPanel
fs::file m_log_file; fs::file m_log_file;
fs::file m_tty_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 wxColour m_color{ 0, 255, 255 }; // current log color
wxAuiNotebook m_tabs; wxAuiNotebook m_tabs;
@ -20,7 +20,7 @@ class LogFrame : public wxPanel
YAML::Node m_cfg_level; YAML::Node m_cfg_level;
YAML::Node m_cfg_tty; YAML::Node m_cfg_tty;
_log::level get_cfg_level() const { return static_cast<_log::level>(m_cfg_level.as<uint>(4)); } logs::level get_cfg_level() const { return static_cast<logs::level>(m_cfg_level.as<uint>(4)); }
bool get_cfg_tty() const { return m_cfg_tty.as<bool>(true); } bool get_cfg_tty() const { return m_cfg_tty.as<bool>(true); }
public: public:

View File

@ -6,6 +6,8 @@
#include "Loader/PSF.h" #include "Loader/PSF.h"
#include "SettingsDialog.h" #include "SettingsDialog.h"
#include <algorithm>
static const std::string m_class_name = "GameViewer"; static const std::string m_class_name = "GameViewer";
// Auxiliary classes // Auxiliary classes

View File

@ -2,15 +2,17 @@
#include "stdafx_gui.h" #include "stdafx_gui.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h"
#include "rpcs3.h" #include "rpcs3.h"
#include "InterpreterDisAsm.h" #include "InterpreterDisAsm.h"
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.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/PPUDisAsm.h"
#include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUDisAsm.h"
#include "Emu/ARMv7/ARMv7DisAsm.h" #include "Emu/PSP2/ARMv7DisAsm.h"
#include "InstructionEditor.h" #include "InstructionEditor.h"
#include "RegisterEditor.h" #include "RegisterEditor.h"
@ -23,7 +25,7 @@ u32 InterpreterDisAsmFrame::GetPc() const
{ {
switch (cpu->type) switch (cpu->type)
{ {
case cpu_type::ppu: return static_cast<PPUThread*>(cpu)->PC; case cpu_type::ppu: return static_cast<PPUThread*>(cpu)->pc;
case cpu_type::spu: return static_cast<SPUThread*>(cpu)->pc; case cpu_type::spu: return static_cast<SPUThread*>(cpu)->pc;
case cpu_type::arm: return static_cast<ARMv7Thread*>(cpu)->PC; case cpu_type::arm: return static_cast<ARMv7Thread*>(cpu)->PC;
} }
@ -121,10 +123,10 @@ void InterpreterDisAsmFrame::UpdateUnitList()
m_choice_units->Freeze(); m_choice_units->Freeze();
m_choice_units->Clear(); m_choice_units->Clear();
for (auto& t : get_all_cpu_threads()) idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([&](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(); m_choice_units->Thaw();
} }
@ -437,7 +439,7 @@ void InterpreterDisAsmFrame::DoRun(wxCommandEvent& WXUNUSED(event))
if (cpu && cpu->state.test(cpu_state_pause)) if (cpu && cpu->state.test(cpu_state_pause))
{ {
cpu->state -= cpu_state::dbg_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); return state.test_and_reset(cpu_state::dbg_pause);
})) }))
{ {
cpu->lock_notify(); (*cpu)->lock_notify();
} }
} }
} }

View File

@ -80,221 +80,166 @@ void KernelExplorer::Update()
// TODO: FileSystem // TODO: FileSystem
// Semaphores // Semaphores
const auto sema_map = idm::get_map<lv2_sema_t>(); if (const u32 count = idm::get_count<lv2_sema_t>())
if (sema_map.size())
{ {
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<lv2_sema_t>([&](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", id,
m_tree->AppendItem(node, fmt::format("Semaphore: ID = 0x%08x '%s', Count = %d, Max Count = %d, Waiters = %#zu", data.first,
&name64(sema.name), sema.value.load(), sema.max, sema.sq.size())); &name64(sema.name), sema.value.load(), sema.max, sema.sq.size()));
} });
} }
// Mutexes // Mutexes
const auto mutex_map = idm::get_map<lv2_mutex_t>(); if (const u32 count = idm::get_count<lv2_mutex_t>())
if (mutex_map.size())
{ {
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<lv2_mutex_t>([&](u32 id, lv2_mutex_t& mutex)
{ {
const auto& mutex = *data.second; m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x '%s'", id,
m_tree->AppendItem(node, fmt::format("Mutex: ID = 0x%08x '%s'", data.first,
&name64(mutex.name))); &name64(mutex.name)));
} });
} }
// Lightweight Mutexes // Lightweight Mutexes
const auto lwm_map = idm::get_map<lv2_lwmutex_t>(); if (const u32 count = idm::get_count<lv2_lwmutex_t>())
if (lwm_map.size())
{ {
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<lv2_lwmutex_t>([&](u32 id, lv2_lwmutex_t& lwm)
{ {
const auto& lwm = *data.second; m_tree->AppendItem(node, fmt::format("LWMutex: ID = 0x%08x '%s'", id,
m_tree->AppendItem(node, fmt::format("LWMutex: ID = 0x%08x '%s'", data.first,
&name64(lwm.name))); &name64(lwm.name)));
} });
} }
// Condition Variables // Condition Variables
const auto cond_map = idm::get_map<lv2_cond_t>(); if (const u32 count = idm::get_count<lv2_cond_t>())
if (cond_map.size())
{ {
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<lv2_cond_t>([&](u32 id, lv2_cond_t& cond)
{ {
const auto& cond = *data.second; m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x '%s'", id,
m_tree->AppendItem(node, fmt::format("Cond: ID = 0x%08x '%s'", data.first,
&name64(cond.name))); &name64(cond.name)));
} });
} }
// Lightweight Condition Variables // Lightweight Condition Variables
const auto lwc_map = idm::get_map<lv2_lwcond_t>(); if (const u32 count = idm::get_count<lv2_lwcond_t>())
if (lwc_map.size())
{ {
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<lv2_lwcond_t>([&](u32 id, lv2_lwcond_t& lwc)
{ {
const auto& lwc = *data.second; m_tree->AppendItem(node, fmt::format("LWCond: ID = 0x%08x '%s'", id,
m_tree->AppendItem(node, fmt::format("LWCond: ID = 0x%08x '%s'", data.first,
&name64(lwc.name))); &name64(lwc.name)));
} });
} }
// Event Queues // Event Queues
const auto eq_map = idm::get_map<lv2_event_queue_t>(); if (const u32 count = idm::get_count<lv2_event_queue_t>())
if (eq_map.size())
{ {
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<lv2_event_queue_t>([&](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", id,
m_tree->AppendItem(node, fmt::format("Event Queue: ID = 0x%08x '%s', %s, Key = %#llx, Events = %zu/%d, Waiters = %zu", data.first,
&name64(eq.name), eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.ipc_key, eq.events(), eq.size, eq.waiters())); &name64(eq.name), eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.ipc_key, eq.events(), eq.size, eq.waiters()));
} });
} }
// Event Ports // Event Ports
const auto ep_map = idm::get_map<lv2_event_port_t>(); if (const u32 count = idm::get_count<lv2_event_port_t>())
if (ep_map.size())
{ {
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<lv2_event_port_t>([&](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", id,
m_tree->AppendItem(node, fmt::format("Event Port: ID = 0x%08x, Name = %#llx", data.first,
ep.name)); ep.name));
} });
} }
// Event Flags // Event Flags
const auto ef_map = idm::get_map<lv2_event_flag_t>(); if (const u32 count = idm::get_count<lv2_event_flag_t>())
if (ef_map.size())
{ {
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<lv2_event_flag_t>([&](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", id,
&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", data.first, &name64(ef.name), ef.type, ef.pattern.load())); });
}
} }
// Reader/writer Locks // Reader/writer Locks
const auto rwlock_map = idm::get_map<lv2_rwlock_t>(); if (const u32 count = idm::get_count<lv2_rwlock_t>())
if (rwlock_map.size())
{ {
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<lv2_rwlock_t>([&](u32 id, lv2_rwlock_t&)
{ {
const auto& rwlock = *data.second; m_tree->AppendItem(node, fmt::format("RWLock: ID = 0x%08x", id));
});
m_tree->AppendItem(node, fmt::format("RWLock: ID = 0x%08x", data.first));
}
} }
// PRX Libraries // PRX Libraries
const auto prx_map = idm::get_map<lv2_prx_t>(); if (const u32 count = idm::get_count<lv2_prx_t>())
if (prx_map.size())
{ {
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<lv2_prx_t>([&](u32 id, lv2_prx_t&)
{ {
const auto& prx = *data.second; m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x", id));
});
m_tree->AppendItem(node, fmt::format("PRX: ID = 0x%08x", data.first));
}
} }
// Memory Containers // Memory Containers
const auto ct_map = idm::get_map<lv2_memory_container_t>(); if (const u32 count = idm::get_count<lv2_memory_container_t>())
if (ct_map.size())
{ {
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<lv2_memory_container_t>([&](u32 id, lv2_memory_container_t&)
{ {
const auto& ct = *data.second; m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", id));
});
m_tree->AppendItem(node, fmt::format("Memory Container: ID = 0x%08x", data.first));
}
} }
// Memory Objects // Memory Objects
const auto mem_map = idm::get_map<lv2_memory_t>(); if (const u32 count = idm::get_count<lv2_memory_t>())
if (mem_map.size())
{ {
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<lv2_memory_t>([&](u32 id, lv2_memory_t&)
{ {
const auto& mem = *data.second; m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", id));
});
m_tree->AppendItem(node, fmt::format("Memory Object: ID = 0x%08x", data.first));
}
} }
// PPU Threads // PPU Threads
const auto ppu_map = idm::get_map<PPUThread>(); if (const u32 count = idm::get_count<PPUThread>())
if (ppu_map.size())
{ {
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<PPUThread>([&](u32 id, PPUThread& ppu)
{ {
const auto& ppu = *data.second; m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", id, ppu.get_name()));
});
m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", data.first, ppu.get_name()));
}
} }
// SPU Thread Groups // SPU Thread Groups
const auto spu_map = idm::get_map<lv2_spu_group_t>(); if (const u32 count = idm::get_count<lv2_spu_group_t>())
if (spu_map.size())
{ {
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<lv2_spu_group_t>([&](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'", id,
m_tree->AppendItem(node, fmt::format("SPU Thread Group: ID = 0x%08x '%s'", data.first,
tg.name.c_str())); tg.name.c_str()));
} });
} }
// RawSPU Threads (TODO) // RawSPU Threads (TODO)

View File

@ -21,6 +21,8 @@
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
#include <thread>
#ifndef _WIN32 #ifndef _WIN32
#include "frame_icon.xpm" #include "frame_icon.xpm"
#endif #endif

View File

@ -15,6 +15,7 @@
#include "SettingsDialog.h" #include "SettingsDialog.h"
#include <set> #include <set>
#include <unordered_set>
// Node location // Node location
using cfg_location = std::vector<const char*>; using cfg_location = std::vector<const char*>;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "../../Utilities/types.h"
#include "../../Utilities/File.h" #include "../../Utilities/File.h"
enum class elf_os : u8 enum class elf_os : u8
@ -155,26 +156,31 @@ enum class elf_error
// ELF loader error information // ELF loader error information
template<> template<>
struct bijective<elf_error, const char*> struct unveil<elf_error>
{ {
static constexpr bijective_pair<elf_error, const char*> 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" }, case elf_error::stream: return "Invalid stream";
{ elf_error::stream_header, "Failed to read ELF header" }, case elf_error::stream_header: return "Failed to read ELF header";
{ elf_error::stream_phdrs, "Failed to read ELF program headers" }, case elf_error::stream_phdrs: return "Failed to read ELF program headers";
{ elf_error::stream_shdrs, "Failed to read ELF section headers" }, case elf_error::stream_shdrs: return "Failed to read ELF section headers";
{ elf_error::stream_data, "Failed to read ELF program data" }, case elf_error::stream_data: return "Failed to read ELF program data";
{ elf_error::header_magic, "Not an ELF" }, case elf_error::header_magic: return "Not an ELF";
{ elf_error::header_version, "Invalid or unsupported ELF format" }, case elf_error::header_version: return "Invalid or unsupported ELF format";
{ elf_error::header_class, "Invalid ELF class" }, case elf_error::header_class: return "Invalid ELF class";
{ elf_error::header_machine, "Invalid ELF machine" }, case elf_error::header_machine: return "Invalid ELF machine";
{ elf_error::header_endianness, "Invalid ELF data (endianness)" }, case elf_error::header_endianness: return "Invalid ELF data (endianness)";
{ elf_error::header_type, "Invalid ELF type" }, case elf_error::header_type: return "Invalid ELF type";
{ elf_error::header_os, "Invalid ELF OS ABI" }, case elf_error::header_os: return "Invalid ELF OS ABI";
};
default: throw error;
}
}
}; };
// ELF loader with specified parameters. // ELF loader with specified parameters.
@ -185,7 +191,7 @@ class elf_loader
{ {
elf_error m_error{}; elf_error m_error{};
elf_error error(elf_error e) elf_error set_error(elf_error e)
{ {
return m_error = e; return m_error = e;
} }
@ -213,57 +219,57 @@ public:
{ {
// Check stream // Check stream
if (!stream) if (!stream)
return error(elf_error::stream); return set_error(elf_error::stream);
// Read ELF header // Read ELF header
stream.seek(offset); stream.seek(offset);
if (!stream.read(header)) if (!stream.read(header))
return error(elf_error::stream_header); return set_error(elf_error::stream_header);
// Check magic // Check magic
if (header.e_magic != "\177ELF"_u32) if (header.e_magic != "\177ELF"_u32)
return error(elf_error::header_magic); return set_error(elf_error::header_magic);
// Check class // Check class
if (header.e_class != (std::is_same<sz_t, u32>::value ? 1 : 2)) if (header.e_class != (std::is_same<sz_t, u32>::value ? 1 : 2))
return error(elf_error::header_class); return set_error(elf_error::header_class);
// Check endianness // Check endianness
if (header.e_data != (std::is_same<en_t<u32>, le_t<u32>>::value ? 1 : 2)) if (header.e_data != (std::is_same<en_t<u32>, le_t<u32>>::value ? 1 : 2))
return error(elf_error::header_endianness); return set_error(elf_error::header_endianness);
// Check machine // Check machine
if (header.e_machine != 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) // Check OS only if specified (hack)
if (OS != elf_os::none && header.e_os_abi != OS) 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) // Check type only if specified (hack)
if (Type != elf_type::none && header.e_type != Type) 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 // Check version and other params
if (header.e_curver != 1 || header.e_version != 1 || header.e_ehsize != sizeof(ehdr_t)) 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)) 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)) 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 // Load program headers
std::vector<phdr_t> _phdrs(header.e_phnum); std::vector<phdr_t> _phdrs(header.e_phnum);
stream.seek(offset + header.e_phoff); stream.seek(offset + header.e_phoff);
if (!stream.read(_phdrs)) if (!stream.read(_phdrs))
return error(elf_error::stream_phdrs); return set_error(elf_error::stream_phdrs);
shdrs.resize(header.e_shnum); shdrs.resize(header.e_shnum);
stream.seek(offset + header.e_shoff); stream.seek(offset + header.e_shoff);
if (!stream.read(shdrs)) if (!stream.read(shdrs))
return error(elf_error::stream_shdrs); return set_error(elf_error::stream_shdrs);
progs.clear(); progs.clear();
progs.reserve(_phdrs.size()); progs.reserve(_phdrs.size());
@ -275,7 +281,7 @@ public:
progs.back().bin.resize(hdr.p_filesz); progs.back().bin.resize(hdr.p_filesz);
stream.seek(offset + hdr.p_offset); stream.seek(offset + hdr.p_offset);
if (!stream.read(progs.back().bin)) if (!stream.read(progs.back().bin))
return error(elf_error::stream_data); return set_error(elf_error::stream_data);
} }
shdrs.shrink_to_fit(); shdrs.shrink_to_fit();
@ -336,6 +342,11 @@ public:
return m_error; return m_error;
} }
elf_error get_error() const
{
return m_error;
}
// Format-specific loader function (must be specialized) // Format-specific loader function (must be specialized)
typename elf_load_result<elf_loader>::type load() const; typename elf_load_result<elf_loader>::type load() const;
}; };

View File

@ -3,7 +3,7 @@
namespace psf namespace psf
{ {
_log::channel log("PSF", _log::level::notice); logs::channel log("PSF", logs::level::notice);
struct header_t struct header_t
{ {
@ -23,28 +23,49 @@ namespace psf
le_t<u32> data_off; le_t<u32> 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 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; return m_value_string;
} }
u32 entry::as_integer() const u32 entry::as_integer() const
{ {
Expects(m_type == format::integer); EXPECTS(m_type == format::integer);
return m_value_integer; return m_value_integer;
} }
entry& entry::operator =(const std::string& value) 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; m_value_string = value;
return *this; return *this;
} }
entry& entry::operator =(u32 value) entry& entry::operator =(u32 value)
{ {
Expects(m_type == format::integer); EXPECTS(m_type == format::integer);
m_value_integer = value; m_value_integer = value;
return *this; return *this;
} }
@ -64,73 +85,75 @@ namespace psf
throw fmt::exception("Invalid format (0x%x)" HERE, m_type); throw fmt::exception("Invalid format (0x%x)" HERE, m_type);
} }
registry load_object(const std::vector<char>& data) registry load_object(const fs::file& stream)
{ {
registry result; registry result;
// Hack for empty input (TODO) // Hack for empty input (TODO)
if (data.empty()) if (!stream)
{ {
return result; return result;
} }
// Check size // Check size
Expects(data.size() >= sizeof(header_t)); EXPECTS(stream.size() >= sizeof(header_t));
Expects((std::uintptr_t)data.data() % 8 == 0);
// Get header // Get header
const header_t& header = reinterpret_cast<const header_t&>(data[0]); header_t header;
EXPECTS(stream.read(header));
// Check magic and version // Check magic and version
Expects(header.magic == "\0PSF"_u32); EXPECTS(header.magic == "\0PSF"_u32);
Expects(header.version == 0x101); EXPECTS(header.version == 0x101);
Expects(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table); 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_key_table <= header.off_data_table);
Expects(header.off_data_table <= data.size()); EXPECTS(header.off_data_table <= stream.size());
// Get indices (alignment should be fine) // Get indices
const def_table_t* indices = reinterpret_cast<const def_table_t*>(data.data() + sizeof(header_t)); std::vector<def_table_t> 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 // Load entries
for (u32 i = 0; i < header.entries_num; ++i) 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 // Get key name (null-terminated string)
const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off; std::string key(keys.data() + indices[i].key_off);
const auto name_end = std::find(name_ptr , data.begin() + header.off_data_table, '\0');
// Get name (must be unique) EXPECTS(result.count(key) == 0);
std::string key(name_ptr, name_end); 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); // Seek data pointer
Expects(indices[i].param_len <= indices[i].param_max); stream.seek(header.off_data_table + indices[i].data_off);
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;
if (indices[i].param_fmt == format::integer && indices[i].param_max == sizeof(u32) && indices[i].param_len == sizeof(u32)) if (indices[i].param_fmt == format::integer && indices[i].param_max == sizeof(u32) && indices[i].param_len == sizeof(u32))
{ {
// Integer data // Integer data
le_t<u32> value;
EXPECTS(stream.read(value));
result.emplace(std::piecewise_construct, result.emplace(std::piecewise_construct,
std::forward_as_tuple(std::move(key)), std::forward_as_tuple(std::move(key)),
std::forward_as_tuple(reinterpret_cast<const le_t<u32>&>(*value_ptr))); std::forward_as_tuple(value));
} }
else if (indices[i].param_fmt == format::string || indices[i].param_fmt == format::array) else if (indices[i].param_fmt == format::string || indices[i].param_fmt == format::array)
{ {
// String/array data // String/array data
std::string value; std::string value;
EXPECTS(stream.read(value, indices[i].param_len));
if (indices[i].param_fmt == format::string) if (indices[i].param_fmt == format::string)
{ {
// Find null terminator // Find null terminator
value.assign(value_ptr, std::find(value_ptr, value_ptr + indices[i].param_len, '\0')); value.resize(std::strlen(value.c_str()));
}
else
{
value.assign(value_ptr, value_ptr + indices[i].param_len);
} }
result.emplace(std::piecewise_construct, result.emplace(std::piecewise_construct,
@ -147,7 +170,7 @@ namespace psf
return result; return result;
} }
std::vector<char> save_object(const registry& psf) void save_object(const fs::file& stream, const psf::registry& psf)
{ {
std::vector<def_table_t> indices; indices.reserve(psf.size()); std::vector<def_table_t> indices; indices.reserve(psf.size());
@ -182,20 +205,18 @@ namespace psf
header.entries_num = ::narrow<u32>(psf.size()); header.entries_num = ::narrow<u32>(psf.size());
// Save header and indices // Save header and indices
std::vector<char> result; result.reserve(header.off_data_table + data_offset); stream.write(header);
stream.write(indices);
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());
// Save key table // Save key table
for (const auto& entry : psf) for (const auto& entry : psf)
{ {
result.insert(result.end(), entry.first.begin(), entry.first.end()); stream.write(entry.first);
result.push_back('\0'); stream.write('\0');
} }
// Insert zero padding // Skip padding
result.insert(result.end(), header.off_data_table - result.size(), '\0'); stream.seek(header.off_data_table);
// Save data // Save data
for (const auto& entry : psf) for (const auto& entry : psf)
@ -206,7 +227,7 @@ namespace psf
if (fmt == format::integer && max == sizeof(u32)) if (fmt == format::integer && max == sizeof(u32))
{ {
const le_t<u32> value = entry.second.as_integer(); const le_t<u32> 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) 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); 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); stream.write(value);
result.insert(result.end(), max - size, '\0'); // Write zeros up to max_size stream.seek(max - size, fs::seek_cur); // Skip up to max_size
} }
else else
{ {
throw EXCEPTION("Invalid entry format (key='%s', fmt=0x%x)", entry.first, fmt); 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) std::string get_string(const registry& psf, const std::string& key, const std::string& def)

View File

@ -20,22 +20,12 @@ namespace psf
public: public:
// Construct string entry, assign the value // Construct string entry, assign the value
entry(format type, u32 max_size, const std::string& 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);
}
// Construct integer entry, assign the value // Construct integer entry, assign the value
entry(u32 value) entry(u32 value);
: m_type(format::integer)
, m_max_size(sizeof(u32)) ~entry();
, m_value_integer(value)
{
}
const std::string& as_string() const; const std::string& as_string() const;
u32 as_integer() const; u32 as_integer() const;
@ -51,24 +41,11 @@ namespace psf
// Define PSF registry as a sorted map of entries: // Define PSF registry as a sorted map of entries:
using registry = std::map<std::string, entry>; using registry = std::map<std::string, entry>;
// Load PSF registry from SFO binary data // Load PSF registry from SFO binary format
registry load_object(const std::vector<char>&); registry load_object(const fs::file&);
// Load PSF registry from SFO file, if opened
inline registry load_object(const fs::file& f)
{
if (f)
{
return load_object(f.to_vector<char>());
}
else
{
return registry{};
}
}
// Convert PSF registry to SFO binary format // Convert PSF registry to SFO binary format
std::vector<char> save_object(const registry&); void save_object(const fs::file&, const registry&);
// Get string value or default value // Get string value or default value
std::string get_string(const registry& psf, const std::string& key, const std::string& def = {}); std::string get_string(const registry& psf, const std::string& key, const std::string& def = {});

View File

@ -138,7 +138,7 @@ bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& con
const std::string& path = vfs::get(configpath); const std::string& path = vfs::get(configpath);
// TODO: rXmlDocument can open only real file // TODO: rXmlDocument can open only real file
ASSERT(!fs::get_virtual_device(path)); VERIFY(!fs::get_virtual_device(path));
rXmlDocument doc; rXmlDocument doc;
doc.Load(path); doc.Load(path);

View File

@ -16,7 +16,7 @@ bool TRPLoader::Install(const std::string& dest, bool show)
const std::string& local_path = vfs::get(dest); 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; return false;
} }

View File

@ -85,7 +85,7 @@
</ClCompile> </ClCompile>
<ClCompile Include="..\Utilities\Thread.cpp" /> <ClCompile Include="..\Utilities\Thread.cpp" />
<ClCompile Include="..\Utilities\VirtualMemory.cpp" /> <ClCompile Include="..\Utilities\VirtualMemory.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Module.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7Module.cpp" />
<ClCompile Include="Emu\Cell\lv2\lv2.cpp" /> <ClCompile Include="Emu\Cell\lv2\lv2.cpp" />
<ClCompile Include="Emu\Cell\lv2\sys_cond.cpp" /> <ClCompile Include="Emu\Cell\lv2\sys_cond.cpp" />
<ClCompile Include="Emu\Cell\lv2\sys_dbg.cpp" /> <ClCompile Include="Emu\Cell\lv2\sys_dbg.cpp" />
@ -265,70 +265,70 @@
<ClCompile Include="Crypto\utils.cpp"> <ClCompile Include="Crypto\utils.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader> <PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7DisAsm.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7DisAsm.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Interpreter.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7Interpreter.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Thread.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7Thread.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAppMgr.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAppMgr.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAppUtil.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAppUtil.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAudio.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAudio.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAudiodec.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAudiodec.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAudioenc.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAudioenc.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceAudioIn.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceAudioIn.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceCamera.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceCamera.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceCodecEngine.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceCodecEngine.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceCommonDialog.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceCommonDialog.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceCtrl.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceCtrl.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceDbg.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceDbg.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceDeci4p.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceDeci4p.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceDeflt.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceDeflt.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceDisplay.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceDisplay.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceFiber.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceFiber.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceFios.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceFios.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceFpu.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceFpu.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceGxm.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceGxm.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceHttp.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceHttp.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceIme.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceIme.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceJpeg.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceJpeg.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceJpegEnc.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceJpegEnc.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLibKernel.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLibKernel.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLibc.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLibc.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLibm.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLibstdcxx.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLibstdcxx.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLiveArea.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLiveArea.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLocation.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLocation.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceMd5.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceMd5.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceMotion.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceMotion.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceMt19937.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceMt19937.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNet.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNet.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNetCtl.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNetCtl.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNgs.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNgs.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpBasic.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpBasic.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpCommon.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpCommon.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpManager.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpManager.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpMatching.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpMatching.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpScore.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpScore.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceNpUtility.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceNpUtility.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\scePerf.cpp" /> <ClCompile Include="Emu\PSP2\Modules\scePerf.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\scePgf.cpp" /> <ClCompile Include="Emu\PSP2\Modules\scePgf.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\scePhotoExport.cpp" /> <ClCompile Include="Emu\PSP2\Modules\scePhotoExport.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceRazorCapture.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceRazorCapture.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceRtc.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceRtc.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSas.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSas.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceScreenShot.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceScreenShot.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSfmt.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSfmt.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSha.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSha.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSqlite.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSqlite.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSsl.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSsl.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSulpha.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSulpha.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSysmodule.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSysmodule.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceSystemGesture.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceSystemGesture.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceTouch.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceTouch.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceUlt.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceUlt.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceVideodec.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceVideodec.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceVoice.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceVoice.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceVoiceQoS.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceVoiceQoS.cpp" />
<ClCompile Include="Emu\ARMv7\Modules\sceLibXml.cpp" /> <ClCompile Include="Emu\PSP2\Modules\sceLibXml.cpp" />
<ClCompile Include="Emu\ARMv7\ARMv7Function.cpp" /> <ClCompile Include="Emu\PSP2\ARMv7Function.cpp" />
<ClCompile Include="Emu\Audio\AudioDumper.cpp" /> <ClCompile Include="Emu\Audio\AudioDumper.cpp" />
<ClCompile Include="Emu\Cell\MFC.cpp" /> <ClCompile Include="Emu\Cell\MFC.cpp" />
<ClCompile Include="Emu\Cell\PPUThread.cpp" /> <ClCompile Include="Emu\Cell\PPUThread.cpp" />
@ -364,6 +364,8 @@
<ClInclude Include="..\Utilities\event.h" /> <ClInclude Include="..\Utilities\event.h" />
<ClInclude Include="..\Utilities\geometry.h" /> <ClInclude Include="..\Utilities\geometry.h" />
<ClInclude Include="..\Utilities\GSL.h" /> <ClInclude Include="..\Utilities\GSL.h" />
<ClInclude Include="..\Utilities\lockless.h" />
<ClInclude Include="..\Utilities\sync.h" />
<ClInclude Include="..\Utilities\Platform.h" /> <ClInclude Include="..\Utilities\Platform.h" />
<ClInclude Include="..\Utilities\Log.h" /> <ClInclude Include="..\Utilities\Log.h" />
<ClInclude Include="..\Utilities\File.h" /> <ClInclude Include="..\Utilities\File.h" />
@ -372,7 +374,6 @@
<ClInclude Include="..\Utilities\rXml.h" /> <ClInclude Include="..\Utilities\rXml.h" />
<ClInclude Include="..\Utilities\Semaphore.h" /> <ClInclude Include="..\Utilities\Semaphore.h" />
<ClInclude Include="..\Utilities\SharedMutex.h" /> <ClInclude Include="..\Utilities\SharedMutex.h" />
<ClInclude Include="..\Utilities\SleepQueue.h" />
<ClInclude Include="..\Utilities\StrFmt.h" /> <ClInclude Include="..\Utilities\StrFmt.h" />
<ClInclude Include="..\Utilities\StrUtil.h" /> <ClInclude Include="..\Utilities\StrUtil.h" />
<ClInclude Include="..\Utilities\Thread.h" /> <ClInclude Include="..\Utilities\Thread.h" />
@ -389,78 +390,79 @@
<ClInclude Include="Crypto\unself.h" /> <ClInclude Include="Crypto\unself.h" />
<ClInclude Include="Crypto\utils.h" /> <ClInclude Include="Crypto\utils.h" />
<ClInclude Include="define_new_memleakdetect.h" /> <ClInclude Include="define_new_memleakdetect.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h" /> <ClInclude Include="Emu\IPC.h" />
<ClInclude Include="Emu\ARMv7\ARMv7DisAsm.h" /> <ClInclude Include="Emu\PSP2\ARMv7Callback.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Interpreter.h" /> <ClInclude Include="Emu\PSP2\ARMv7DisAsm.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Module.h" /> <ClInclude Include="Emu\PSP2\ARMv7Interpreter.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Opcodes.h" /> <ClInclude Include="Emu\PSP2\ARMv7Module.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Thread.h" /> <ClInclude Include="Emu\PSP2\ARMv7Opcodes.h" />
<ClInclude Include="Emu\ARMv7\ErrorCodes.h" /> <ClInclude Include="Emu\PSP2\ARMv7Thread.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAppMgr.h" /> <ClInclude Include="Emu\PSP2\ErrorCodes.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAppUtil.h" /> <ClInclude Include="Emu\PSP2\Modules\Common.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAudio.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAppMgr.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAudiodec.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAppUtil.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAudioenc.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAudio.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceAudioIn.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAudiodec.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceCamera.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAudioenc.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceCodecEngine.h" /> <ClInclude Include="Emu\PSP2\Modules\sceAudioIn.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceCommonDialog.h" /> <ClInclude Include="Emu\PSP2\Modules\sceCamera.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceCtrl.h" /> <ClInclude Include="Emu\PSP2\Modules\sceCodecEngine.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceDbg.h" /> <ClInclude Include="Emu\PSP2\Modules\sceCommonDialog.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceDeci4p.h" /> <ClInclude Include="Emu\PSP2\Modules\sceCtrl.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceDeflt.h" /> <ClInclude Include="Emu\PSP2\Modules\sceDbg.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceDisplay.h" /> <ClInclude Include="Emu\PSP2\Modules\sceDeci4p.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceFiber.h" /> <ClInclude Include="Emu\PSP2\Modules\sceDeflt.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceFios.h" /> <ClInclude Include="Emu\PSP2\Modules\sceDisplay.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceFpu.h" /> <ClInclude Include="Emu\PSP2\Modules\sceFiber.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceGxm.h" /> <ClInclude Include="Emu\PSP2\Modules\sceFios.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceHttp.h" /> <ClInclude Include="Emu\PSP2\Modules\sceFpu.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceIme.h" /> <ClInclude Include="Emu\PSP2\Modules\sceGxm.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceJpeg.h" /> <ClInclude Include="Emu\PSP2\Modules\sceHttp.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceJpegEnc.h" /> <ClInclude Include="Emu\PSP2\Modules\sceIme.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLibc.h" /> <ClInclude Include="Emu\PSP2\Modules\sceJpeg.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLibKernel.h" /> <ClInclude Include="Emu\PSP2\Modules\sceJpegEnc.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLibm.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLibc.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLibstdcxx.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLibKernel.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLiveArea.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLibm.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLocation.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLibstdcxx.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceMd5.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLiveArea.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceMotion.h" /> <ClInclude Include="Emu\PSP2\Modules\sceLocation.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceMt19937.h" /> <ClInclude Include="Emu\PSP2\Modules\sceMd5.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNet.h" /> <ClInclude Include="Emu\PSP2\Modules\sceMotion.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNetCtl.h" /> <ClInclude Include="Emu\PSP2\Modules\sceMt19937.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNgs.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNet.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpBasic.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNetCtl.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpCommon.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNgs.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpManager.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpBasic.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpMatching.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpCommon.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpScore.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpManager.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceNpUtility.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpMatching.h" />
<ClInclude Include="Emu\ARMv7\Modules\scePerf.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpScore.h" />
<ClInclude Include="Emu\ARMv7\Modules\scePgf.h" /> <ClInclude Include="Emu\PSP2\Modules\sceNpUtility.h" />
<ClInclude Include="Emu\ARMv7\Modules\scePhotoExport.h" /> <ClInclude Include="Emu\PSP2\Modules\scePerf.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceRazorCapture.h" /> <ClInclude Include="Emu\PSP2\Modules\scePgf.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceRtc.h" /> <ClInclude Include="Emu\PSP2\Modules\scePhotoExport.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSas.h" /> <ClInclude Include="Emu\PSP2\Modules\sceRazorCapture.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceScreenShot.h" /> <ClInclude Include="Emu\PSP2\Modules\sceRtc.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSqlite.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSas.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSsl.h" /> <ClInclude Include="Emu\PSP2\Modules\sceScreenShot.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSulpha.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSqlite.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSysmodule.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSsl.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceSystemGesture.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSulpha.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceTouch.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSysmodule.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceUlt.h" /> <ClInclude Include="Emu\PSP2\Modules\sceSystemGesture.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceVideodec.h" /> <ClInclude Include="Emu\PSP2\Modules\sceTouch.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceVoice.h" /> <ClInclude Include="Emu\PSP2\Modules\sceUlt.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceVoiceQoS.h" /> <ClInclude Include="Emu\PSP2\Modules\sceVideodec.h" />
<ClInclude Include="Emu\ARMv7\Modules\sceLibXml.h" /> <ClInclude Include="Emu\PSP2\Modules\sceVoice.h" />
<ClInclude Include="Emu\ARMv7\ARMv7Function.h" /> <ClInclude Include="Emu\PSP2\Modules\sceVoiceQoS.h" />
<ClInclude Include="Emu\PSP2\Modules\sceLibXml.h" />
<ClInclude Include="Emu\PSP2\ARMv7Function.h" />
<ClInclude Include="Emu\Audio\AudioDumper.h" /> <ClInclude Include="Emu\Audio\AudioDumper.h" />
<ClInclude Include="Emu\Audio\AudioThread.h" /> <ClInclude Include="Emu\Audio\AudioThread.h" />
<ClInclude Include="Emu\Audio\Null\NullAudioThread.h" /> <ClInclude Include="Emu\Audio\Null\NullAudioThread.h" />
<ClInclude Include="Emu\Cell\Common.h" /> <ClInclude Include="Emu\Cell\Common.h" />
<ClInclude Include="Emu\Cell\ErrorCodes.h" /> <ClInclude Include="Emu\Cell\ErrorCodes.h" />
<ClInclude Include="Emu\Cell\lv2\IPC.h" />
<ClInclude Include="Emu\Cell\lv2\sys_cond.h" /> <ClInclude Include="Emu\Cell\lv2\sys_cond.h" />
<ClInclude Include="Emu\Cell\lv2\sys_dbg.h" /> <ClInclude Include="Emu\Cell\lv2\sys_dbg.h" />
<ClInclude Include="Emu\Cell\lv2\sys_event.h" /> <ClInclude Include="Emu\Cell\lv2\sys_event.h" />

View File

@ -54,12 +54,6 @@
<Filter Include="Emu\GPU\RSX\Common"> <Filter Include="Emu\GPU\RSX\Common">
<UniqueIdentifier>{2a8841dc-bce0-41bb-9fcb-5bf1f8dda213}</UniqueIdentifier> <UniqueIdentifier>{2a8841dc-bce0-41bb-9fcb-5bf1f8dda213}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Emu\ARMv7">
<UniqueIdentifier>{93b1cff1-0158-4327-a437-e9abcac8d724}</UniqueIdentifier>
</Filter>
<Filter Include="Emu\ARMv7\Modules">
<UniqueIdentifier>{1d9e6fc4-9a79-4329-a8b5-081e24822aaa}</UniqueIdentifier>
</Filter>
<Filter Include="Emu\Cell"> <Filter Include="Emu\Cell">
<UniqueIdentifier>{13d20086-2188-425a-9856-0440fe6f79f2}</UniqueIdentifier> <UniqueIdentifier>{13d20086-2188-425a-9856-0440fe6f79f2}</UniqueIdentifier>
</Filter> </Filter>
@ -69,6 +63,12 @@
<Filter Include="Emu\Cell\Modules"> <Filter Include="Emu\Cell\Modules">
<UniqueIdentifier>{4317ac27-38e4-4f8d-9bac-496f9b00f615}</UniqueIdentifier> <UniqueIdentifier>{4317ac27-38e4-4f8d-9bac-496f9b00f615}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Emu\PSP2">
<UniqueIdentifier>{93b1cff1-0158-4327-a437-e9abcac8d724}</UniqueIdentifier>
</Filter>
<Filter Include="Emu\PSP2\Modules">
<UniqueIdentifier>{1d9e6fc4-9a79-4329-a8b5-081e24822aaa}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Crypto\aes.cpp"> <ClCompile Include="Crypto\aes.cpp">
@ -113,9 +113,6 @@
<ClCompile Include="Emu\CPU\CPUThread.cpp"> <ClCompile Include="Emu\CPU\CPUThread.cpp">
<Filter>Emu\CPU</Filter> <Filter>Emu\CPU</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Thread.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\AudioDumper.cpp"> <ClCompile Include="Emu\Audio\AudioDumper.cpp">
<Filter>Emu\Audio</Filter> <Filter>Emu\Audio</Filter>
</ClCompile> </ClCompile>
@ -161,192 +158,9 @@
<ClCompile Include="Crypto\ec.cpp"> <ClCompile Include="Crypto\ec.cpp">
<Filter>Crypto</Filter> <Filter>Crypto</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Interpreter.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7DisAsm.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLibc.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLibstdcxx.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLibKernel.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\Thread.cpp"> <ClCompile Include="..\Utilities\Thread.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSysmodule.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\scePerf.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceCtrl.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceDeci4p.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceDisplay.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceGxm.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAppMgr.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAppUtil.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAudio.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAudiodec.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAudioenc.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceAudioIn.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceCamera.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceCodecEngine.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceCommonDialog.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceDbg.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceDeflt.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceFiber.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceFios.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceFpu.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceHttp.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceIme.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceJpeg.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceJpegEnc.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLiveArea.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLocation.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceMd5.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceMotion.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceMt19937.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNet.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNetCtl.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNgs.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpBasic.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpCommon.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpManager.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpMatching.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpScore.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceNpUtility.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\scePgf.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\scePhotoExport.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceRazorCapture.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceRtc.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSas.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceScreenShot.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSqlite.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSsl.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSulpha.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSystemGesture.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceTouch.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceUlt.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceVideodec.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceVoice.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceVoiceQoS.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSfmt.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceSha.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\CgBinaryVertexProgram.cpp"> <ClCompile Include="Emu\RSX\CgBinaryVertexProgram.cpp">
<Filter>Emu\GPU\RSX</Filter> <Filter>Emu\GPU\RSX</Filter>
</ClCompile> </ClCompile>
@ -419,9 +233,6 @@
<ClCompile Include="Emu\Cell\PPUDisAsm.cpp"> <ClCompile Include="Emu\Cell\PPUDisAsm.cpp">
<Filter>Emu\Cell</Filter> <Filter>Emu\Cell</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Function.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\Cell\lv2\lv2.cpp"> <ClCompile Include="Emu\Cell\lv2\lv2.cpp">
<Filter>Emu\Cell\lv2</Filter> <Filter>Emu\Cell\lv2</Filter>
</ClCompile> </ClCompile>
@ -833,12 +644,6 @@
<ClCompile Include="Emu\Cell\Modules\sys_libc_.cpp"> <ClCompile Include="Emu\Cell\Modules\sys_libc_.cpp">
<Filter>Emu\Cell\Modules</Filter> <Filter>Emu\Cell\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Module.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\Modules\sceLibXml.cpp">
<Filter>Emu\ARMv7\Modules</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\Config.cpp"> <ClCompile Include="..\Utilities\Config.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </ClCompile>
@ -854,6 +659,201 @@
<ClCompile Include="Emu\IdManager.cpp"> <ClCompile Include="Emu\IdManager.cpp">
<Filter>Emu</Filter> <Filter>Emu</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\PSP2\ARMv7Thread.cpp">
<Filter>Emu\PSP2</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\ARMv7DisAsm.cpp">
<Filter>Emu\PSP2</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\ARMv7Function.cpp">
<Filter>Emu\PSP2</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\ARMv7Interpreter.cpp">
<Filter>Emu\PSP2</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\ARMv7Module.cpp">
<Filter>Emu\PSP2</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAppMgr.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAppUtil.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAudio.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAudiodec.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAudioenc.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceAudioIn.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceCamera.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceCodecEngine.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceCommonDialog.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceCtrl.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceDbg.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceDeci4p.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceDeflt.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceDisplay.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceFiber.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceFios.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceFpu.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceGxm.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceHttp.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceIme.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceJpeg.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceJpegEnc.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLibc.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLibKernel.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLibm.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLibstdcxx.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLibXml.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLiveArea.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceLocation.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceMd5.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceMotion.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceMt19937.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNet.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNetCtl.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNgs.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpBasic.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpCommon.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpManager.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpMatching.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpScore.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceNpUtility.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\scePerf.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\scePgf.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\scePhotoExport.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceRazorCapture.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceRtc.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSas.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceScreenShot.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSfmt.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSha.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSqlite.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSsl.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSulpha.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSysmodule.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceSystemGesture.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceTouch.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceUlt.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceVideodec.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceVoice.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\PSP2\Modules\sceVoiceQoS.cpp">
<Filter>Emu\PSP2\Modules</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -937,18 +937,6 @@
<ClInclude Include="Emu\CPU\CPUThread.h"> <ClInclude Include="Emu\CPU\CPUThread.h">
<Filter>Emu\CPU</Filter> <Filter>Emu\CPU</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7DisAsm.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Interpreter.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Opcodes.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Thread.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\Audio\AudioDumper.h"> <ClInclude Include="Emu\Audio\AudioDumper.h">
<Filter>Emu\Audio</Filter> <Filter>Emu\Audio</Filter>
</ClInclude> </ClInclude>
@ -1057,33 +1045,6 @@
<ClInclude Include="Emu\Audio\AudioThread.h"> <ClInclude Include="Emu\Audio\AudioThread.h">
<Filter>Emu\Audio</Filter> <Filter>Emu\Audio</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Callback.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLibKernel.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceGxm.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAppUtil.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceIme.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNet.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSsl.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceTouch.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpCommon.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\File.h"> <ClInclude Include="..\Utilities\File.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
@ -1099,159 +1060,9 @@
<ClInclude Include="Emu\RSX\Common\VertexProgramDecompiler.h"> <ClInclude Include="Emu\RSX\Common\VertexProgramDecompiler.h">
<Filter>Emu\GPU\RSX\Common</Filter> <Filter>Emu\GPU\RSX\Common</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpMatching.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAppMgr.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAudio.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAudiodec.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAudioenc.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceAudioIn.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceCamera.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceCodecEngine.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceCommonDialog.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceCtrl.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceDbg.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceDeci4p.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceDeflt.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceDisplay.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceFiber.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceFios.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceFpu.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceHttp.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceJpeg.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceJpegEnc.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLibc.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLibm.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLibstdcxx.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLiveArea.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLocation.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceMd5.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceMotion.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceMt19937.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNetCtl.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNgs.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpBasic.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpManager.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpScore.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceNpUtility.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\scePerf.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\scePgf.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\scePhotoExport.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceRazorCapture.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceRtc.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSas.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceScreenShot.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSqlite.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSulpha.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSysmodule.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceSystemGesture.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceUlt.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceVideodec.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceVoice.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceVoiceQoS.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\Semaphore.h"> <ClInclude Include="..\Utilities\Semaphore.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Utilities\SleepQueue.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\Common.h"> <ClInclude Include="Emu\Cell\Common.h">
<Filter>Emu\Cell</Filter> <Filter>Emu\Cell</Filter>
</ClInclude> </ClInclude>
@ -1306,9 +1117,6 @@
<ClInclude Include="Loader\ELF.h"> <ClInclude Include="Loader\ELF.h">
<Filter>Loader</Filter> <Filter>Loader</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Function.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\lv2\sys_cond.h"> <ClInclude Include="Emu\Cell\lv2\sys_cond.h">
<Filter>Emu\Cell\lv2</Filter> <Filter>Emu\Cell\lv2</Filter>
</ClInclude> </ClInclude>
@ -1579,15 +1387,6 @@
<ClInclude Include="Emu\Cell\PPUModule.h"> <ClInclude Include="Emu\Cell\PPUModule.h">
<Filter>Emu\Cell</Filter> <Filter>Emu\Cell</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Module.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ErrorCodes.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\Modules\sceLibXml.h">
<Filter>Emu\ARMv7\Modules</Filter>
</ClInclude>
<ClInclude Include="..\3rdparty\stblib\stb_image.h"> <ClInclude Include="..\3rdparty\stblib\stb_image.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -1606,9 +1405,6 @@
<ClInclude Include="Emu\Memory\wait_engine.h"> <ClInclude Include="Emu\Memory\wait_engine.h">
<Filter>Emu\Memory</Filter> <Filter>Emu\Memory</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\Cell\lv2\IPC.h">
<Filter>Emu\Cell\lv2</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\StrUtil.h"> <ClInclude Include="..\Utilities\StrUtil.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
@ -1618,5 +1414,215 @@
<ClInclude Include="..\Utilities\BitSet.h"> <ClInclude Include="..\Utilities\BitSet.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Callback.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7DisAsm.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Function.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Interpreter.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Module.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Opcodes.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ARMv7Thread.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\ErrorCodes.h">
<Filter>Emu\PSP2</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAppMgr.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAppUtil.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAudio.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAudiodec.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAudioenc.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceAudioIn.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceCamera.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceCodecEngine.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceCommonDialog.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceCtrl.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceDbg.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceDeci4p.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceDeflt.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceDisplay.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceFiber.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceFios.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceFpu.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceGxm.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceHttp.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceIme.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceJpeg.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceJpegEnc.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLibc.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLibKernel.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLibm.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLibstdcxx.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLibXml.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLiveArea.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceLocation.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceMd5.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceMotion.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceMt19937.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNet.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNetCtl.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNgs.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpBasic.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpCommon.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpManager.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpMatching.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpScore.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceNpUtility.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\scePerf.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\scePgf.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\scePhotoExport.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceRazorCapture.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceRtc.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSas.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceScreenShot.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSqlite.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSsl.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSulpha.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSysmodule.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceSystemGesture.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceTouch.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceUlt.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceVideodec.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceVoice.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\sceVoiceQoS.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\PSP2\Modules\Common.h">
<Filter>Emu\PSP2\Modules</Filter>
</ClInclude>
<ClInclude Include="Emu\IPC.h">
<Filter>Emu</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\lockless.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\sync.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -23,20 +23,20 @@
#include <cstdint> #include <cstdint>
#include <climits> #include <climits>
#include <cstring> #include <cstring>
#include <exception>
#include <string> #include <string>
#include <mutex>
#include <condition_variable>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <array> #include <array>
#include <functional> #include <functional>
#include <algorithm>
#include <unordered_set>
#include <unordered_map> #include <unordered_map>
#include <chrono>
using namespace std::string_literals; // MSVC bug workaround
using namespace std::chrono_literals; #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. // Obsolete, throw fmt::exception directly. Use 'HERE' macro, if necessary.
#define EXCEPTION(format_str, ...) fmt::exception("%s(): " format_str HERE, __FUNCTION__, ##__VA_ARGS__) #define EXCEPTION(format_str, ...) fmt::exception("%s(): " format_str HERE, __FUNCTION__, ##__VA_ARGS__)