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
#include "types.h"
#include "Platform.h"
// Helper class, provides access to compiler-specific atomic intrinsics
template<typename T, std::size_t Size>
@ -744,9 +745,9 @@ public:
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)
{
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)
{
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)
{
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
#include <unordered_set>
// Regarded as a Debugger Enchantment
namespace debug
{

View File

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

View File

@ -179,7 +179,7 @@ namespace cfg
for (const auto& v : init)
{
// Ensure elements are unique
ASSERT(map.emplace(v.first, v.second).second);
VERIFY(map.emplace(v.first, v.second).second);
}
return map;
@ -529,4 +529,4 @@ namespace cfg
}
// Registered log channel
#define LOG_CHANNEL(name) _log::channel name(#name, _log::level::notice); namespace _log { cfg::enum_entry<_log::level, true> name(cfg::root.log, #name, ::name.enabled); }
#define LOG_CHANNEL(name) extern logs::channel name; namespace logs { static cfg::enum_entry<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);
}
static fs::error to_error(DWORD e)
{
switch (e)
{
case ERROR_FILE_NOT_FOUND: return fs::error::noent;
case ERROR_PATH_NOT_FOUND: return fs::error::noent;
case ERROR_ALREADY_EXISTS: return fs::error::exist;
case ERROR_FILE_EXISTS: return fs::error::exist;
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
default: throw fmt::exception("Unknown Win32 error: %u.", e);
}
}
#else
#include <sys/mman.h>
@ -87,11 +100,22 @@ static time_t to_time(const FILETIME& ft)
#include <sys/sendfile.h>
#endif
static fs::error to_error(int e)
{
switch (e)
{
case ENOENT: return fs::error::noent;
case EEXIST: return fs::error::exist;
case EINVAL: return fs::error::inval;
default: throw fmt::exception("Unknown system error: %d.", e);
}
}
#endif
namespace fs
{
thread_local uint error = 0;
thread_local error g_tls_error = error::ok;
class device_manager final
{
@ -146,7 +170,7 @@ std::shared_ptr<fs::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)
{
Expects(name.size() > 2 && name[0] == '/' && name[1] == '/' && name.find('/', 2) == -1);
EXPECTS(name.size() > 2 && name[0] == '/' && name[1] == '/' && name.find('/', 2) == -1);
return get_device_manager().set_device(name, device);
}
@ -178,26 +202,26 @@ std::string fs::get_parent_dir(const std::string& path)
static const auto test_get_parent_dir = []() -> bool
{
// Success:
ASSERT(fs::get_parent_dir("/x/y///") == "/x");
ASSERT(fs::get_parent_dir("/x/y/") == "/x");
ASSERT(fs::get_parent_dir("/x/y") == "/x");
ASSERT(fs::get_parent_dir("x:/y") == "x:");
ASSERT(fs::get_parent_dir("//x/y") == "//x");
VERIFY(fs::get_parent_dir("/x/y///") == "/x");
VERIFY(fs::get_parent_dir("/x/y/") == "/x");
VERIFY(fs::get_parent_dir("/x/y") == "/x");
VERIFY(fs::get_parent_dir("x:/y") == "x:");
VERIFY(fs::get_parent_dir("//x/y") == "//x");
// Failure:
ASSERT(fs::get_parent_dir("").empty());
ASSERT(fs::get_parent_dir("x/").empty());
ASSERT(fs::get_parent_dir("x").empty());
ASSERT(fs::get_parent_dir("x///").empty());
ASSERT(fs::get_parent_dir("/x/").empty());
ASSERT(fs::get_parent_dir("/x").empty());
ASSERT(fs::get_parent_dir("/").empty());
ASSERT(fs::get_parent_dir("//").empty());
ASSERT(fs::get_parent_dir("//x").empty());
ASSERT(fs::get_parent_dir("//x/").empty());
ASSERT(fs::get_parent_dir("///").empty());
ASSERT(fs::get_parent_dir("///x").empty());
ASSERT(fs::get_parent_dir("///x/").empty());
VERIFY(fs::get_parent_dir("").empty());
VERIFY(fs::get_parent_dir("x/").empty());
VERIFY(fs::get_parent_dir("x").empty());
VERIFY(fs::get_parent_dir("x///").empty());
VERIFY(fs::get_parent_dir("/x/").empty());
VERIFY(fs::get_parent_dir("/x").empty());
VERIFY(fs::get_parent_dir("/").empty());
VERIFY(fs::get_parent_dir("//").empty());
VERIFY(fs::get_parent_dir("//x").empty());
VERIFY(fs::get_parent_dir("//x/").empty());
VERIFY(fs::get_parent_dir("///").empty());
VERIFY(fs::get_parent_dir("///x").empty());
VERIFY(fs::get_parent_dir("///x/").empty());
return false;
}();
@ -213,14 +237,7 @@ bool fs::stat(const std::string& path, stat_t& info)
WIN32_FILE_ATTRIBUTE_DATA attrs;
if (!GetFileAttributesExW(to_wchar(path).get(), GetFileExInfoStandard, &attrs))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -234,7 +251,7 @@ bool fs::stat(const std::string& path, stat_t& info)
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -260,14 +277,7 @@ bool fs::exists(const std::string& path)
#ifdef _WIN32
if (GetFileAttributesW(to_wchar(path).get()) == INVALID_FILE_ATTRIBUTES)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -276,7 +286,7 @@ bool fs::exists(const std::string& path)
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -296,7 +306,7 @@ bool fs::is_file(const std::string& path)
if (info.is_directory)
{
fs::error = EEXIST;
g_tls_error = error::exist;
return false;
}
@ -307,21 +317,14 @@ bool fs::is_file(const std::string& path)
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
if (attrs == INVALID_FILE_ATTRIBUTES)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
#else
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
#endif
@ -333,7 +336,7 @@ bool fs::is_file(const std::string& path)
if (S_ISDIR(file_info.st_mode))
#endif
{
fs::error = EEXIST;
g_tls_error = error::exist;
return false;
}
@ -352,7 +355,7 @@ bool fs::is_dir(const std::string& path)
if (info.is_directory == false)
{
fs::error = EEXIST;
g_tls_error = error::exist;
return false;
}
@ -363,21 +366,14 @@ bool fs::is_dir(const std::string& path)
const DWORD attrs = GetFileAttributesW(to_wchar(path).get());
if (attrs == INVALID_FILE_ATTRIBUTES)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
#else
struct ::stat file_info;
if (::stat(path.c_str(), &file_info) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
#endif
@ -388,7 +384,7 @@ bool fs::is_dir(const std::string& path)
if (!S_ISDIR(file_info.st_mode))
#endif
{
fs::error = EEXIST;
g_tls_error = error::exist;
return false;
}
@ -405,14 +401,7 @@ bool fs::create_dir(const std::string& path)
#ifdef _WIN32
if (!CreateDirectoryW(to_wchar(path).get(), NULL))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_ALREADY_EXISTS: fs::error = EEXIST; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -420,7 +409,7 @@ bool fs::create_dir(const std::string& path)
#else
if (::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -450,13 +439,7 @@ bool fs::remove_dir(const std::string& path)
#ifdef _WIN32
if (!RemoveDirectoryW(to_wchar(path).get()))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -464,7 +447,7 @@ bool fs::remove_dir(const std::string& path)
#else
if (::rmdir(path.c_str()) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -489,13 +472,7 @@ bool fs::rename(const std::string& from, const std::string& to)
#ifdef _WIN32
if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get()))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -503,7 +480,7 @@ bool fs::rename(const std::string& from, const std::string& to)
#else
if (::rename(from.c_str(), to.c_str()) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -523,13 +500,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
#ifdef _WIN32
if (!CopyFileW(to_wchar(from).get(), to_wchar(to).get(), !overwrite))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u.\nFrom: %s\nTo: %s" HERE, error, from, to);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -540,7 +511,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int input = ::open(from.c_str(), O_RDONLY);
if (input == -1)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -550,7 +521,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
const int err = errno;
::close(input);
fs::error = err;
g_tls_error = to_error(err);
return false;
}
@ -569,7 +540,7 @@ bool fs::copy_file(const std::string& from, const std::string& to, bool overwrit
::close(input);
::close(output);
fs::error = err;
g_tls_error = to_error(err);
return false;
}
@ -589,14 +560,7 @@ bool fs::remove_file(const std::string& path)
#ifdef _WIN32
if (!DeleteFileW(to_wchar(path).get()))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -604,7 +568,7 @@ bool fs::remove_file(const std::string& path)
#else
if (::unlink(path.c_str()) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -624,14 +588,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
const auto handle = CreateFileW(to_wchar(path).get(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -641,13 +598,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
// Seek and truncate
if (!SetFilePointerEx(handle, distance, NULL, FILE_BEGIN) || !SetEndOfFile(handle))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break;
default: throw fmt::exception("Unknown Win32 error: %u (length=0x%llx)." HERE, error, length);
}
g_tls_error = to_error(GetLastError());
CloseHandle(handle);
return false;
}
@ -657,7 +608,7 @@ bool fs::truncate_file(const std::string& path, u64 length)
#else
if (::truncate(path.c_str(), length) != 0)
{
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -672,7 +623,7 @@ void fs::file::xnull() const
void fs::file::xfail() const
{
throw fmt::exception("Unexpected fs::file error %u", fs::error);
throw fmt::exception("Unexpected fs::error %u", g_tls_error);
}
bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
@ -704,7 +655,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{
if (mode & fs::excl)
{
fs::error = EINVAL;
g_tls_error = error::inval;
return false;
}
@ -715,15 +666,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (handle == INVALID_HANDLE_VALUE)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_FILE_EXISTS: fs::error = EEXIST; break;
default: throw fmt::exception("Unknown Win32 error: %u (%s)." HERE, error, path);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -747,12 +690,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
FILE_BASIC_INFO basic_info;
if (!GetFileInformationByHandleEx(m_handle, FileBasicInfo, &basic_info, sizeof(FILE_BASIC_INFO)))
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
stat_t info;
@ -773,47 +711,22 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
pos.QuadPart = 0;
if (!SetFilePointerEx(m_handle, pos, &old, FILE_CURRENT)) // get old position
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
g_tls_error = to_error(GetLastError());
return false;
}
pos.QuadPart = length;
if (!SetFilePointerEx(m_handle, pos, NULL, FILE_BEGIN)) // set new position
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_NEGATIVE_SEEK: fs::error = EINVAL; break;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
g_tls_error = to_error(GetLastError());
return false;
}
const BOOL result = SetEndOfFile(m_handle); // change file size
if (!result)
if (!result || !SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN)) // restore position
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
}
if (!SetFilePointerEx(m_handle, old, NULL, FILE_BEGIN) && result) // restore position
{
if (DWORD error = GetLastError())
{
throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
return result != FALSE;
@ -823,16 +736,12 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{
// TODO (call ReadFile multiple times if count is too big)
const int size = ::narrow<int>(count, "Too big count" HERE);
Expects(size >= 0);
EXPECTS(size >= 0);
DWORD nread;
if (!ReadFile(m_handle, buffer, size, &nread, NULL))
{
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
return nread;
@ -842,16 +751,12 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{
// TODO (call WriteFile multiple times if count is too big)
const int size = ::narrow<int>(count, "Too big count" HERE);
Expects(size >= 0);
EXPECTS(size >= 0);
DWORD nwritten;
if (!WriteFile(m_handle, buffer, size, &nwritten, NULL))
{
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
return nwritten;
@ -870,11 +775,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (!SetFilePointerEx(m_handle, pos, &pos, mode))
{
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
return pos.QuadPart;
@ -885,11 +786,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
LARGE_INTEGER size;
if (!GetFileSizeEx(m_handle, &size))
{
switch (DWORD error = GetLastError())
{
case 0:
default: throw fmt::exception("Win32 error: %u." HERE, error);
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
return size.QuadPart;
@ -913,8 +810,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
if (fd == -1)
{
// TODO: errno
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -938,11 +834,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
stat_t info;
@ -960,12 +852,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
{
if (::ftruncate(m_fd, length) != 0)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
g_tls_error = to_error(errno);
return false;
}
@ -977,11 +864,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::read(m_fd, buffer, count);
if (result == -1)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
return result;
@ -992,11 +875,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::write(m_fd, buffer, count);
if (result == -1)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
return result;
@ -1013,11 +892,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
const auto result = ::lseek(m_fd, offset, mode);
if (result == -1)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
return result;
@ -1028,11 +903,7 @@ bool fs::file::open(const std::string& path, bitset_t<open_mode> mode)
struct ::stat file_info;
if (::fstat(m_fd, &file_info) != 0)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
return file_info.st_size;
@ -1049,7 +920,7 @@ fs::file::file(const void* ptr, std::size_t size)
{
class memory_stream : public file_base
{
u64 m_pos{}; // TODO: read/seek could modify m_pos atomically
u64 m_pos{};
const char* const m_ptr;
const u64 m_size;
@ -1063,26 +934,26 @@ fs::file::file(const void* ptr, std::size_t size)
fs::stat_t stat() override
{
throw std::logic_error("memory_stream doesn't support stat()");
throw std::logic_error("Not supported" HERE);
}
bool trunc(u64 length) override
{
throw std::logic_error("memory_stream doesn't support trunc()");
throw std::logic_error("Not allowed" HERE);
}
u64 read(void* buffer, u64 count) override
{
const u64 start = m_pos;
const u64 end = seek(count, fs::seek_cur);
const u64 read_size = end >= start ? end - start : throw std::logic_error("memory_stream::read(): overflow");
const u64 read_size = end >= start ? end - start : throw std::logic_error("Stream overflow" HERE);
std::memcpy(buffer, m_ptr + start, read_size);
return read_size;
}
u64 write(const void* buffer, u64 count) override
{
throw std::logic_error("memory_stream is not writable");
throw std::logic_error("Not allowed" HERE);
}
u64 seek(s64 offset, fs::seek_mode whence) override
@ -1091,7 +962,7 @@ fs::file::file(const void* ptr, std::size_t size)
whence == fs::seek_set ? m_pos = std::min<u64>(offset, 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) :
throw std::logic_error("memory_stream::seek(): invalid whence");
throw fmt::exception("Invalid whence (0x%x)" HERE, whence);
}
u64 size() override
@ -1127,14 +998,7 @@ bool fs::dir::open(const std::string& path)
if (handle == INVALID_HANDLE_VALUE)
{
// TODO: convert Win32 error code to errno
switch (DWORD error = GetLastError())
{
case ERROR_FILE_NOT_FOUND: fs::error = ENOENT; break;
case ERROR_PATH_NOT_FOUND: fs::error = ENOENT; break;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
}
g_tls_error = to_error(GetLastError());
return false;
}
@ -1179,11 +1043,12 @@ bool fs::dir::open(const std::string& path)
WIN32_FIND_DATAW found;
if (!FindNextFileW(m_handle, &found))
{
switch (DWORD error = GetLastError())
if (ERROR_NO_MORE_FILES == GetLastError())
{
case ERROR_NO_MORE_FILES: return false;
default: throw fmt::exception("Unknown Win32 error: %u." HERE, error);
return false;
}
throw fmt::exception("Win32 error: %u." HERE, GetLastError());
}
add_entry(found);
@ -1205,8 +1070,7 @@ bool fs::dir::open(const std::string& path)
if (!ptr)
{
// TODO: errno
fs::error = errno;
g_tls_error = to_error(errno);
return false;
}
@ -1236,11 +1100,7 @@ bool fs::dir::open(const std::string& path)
struct ::stat file_info;
if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0)
{
switch (int error = errno)
{
case 0:
default: throw fmt::exception("Unknown error: %d." HERE, error);
}
throw fmt::exception("System error: %d." HERE, errno);
}
info.name = found->d_name;

View File

@ -10,9 +10,6 @@
namespace fs
{
// Error code returned
extern thread_local uint error;
// File open mode flags
enum struct open_mode : u32
{
@ -265,6 +262,13 @@ namespace fs
return read(&str[0], str.size()) == str.size();
}
// Read std::string
bool read(std::string& str, std::size_t size) const
{
str.resize(size);
return read(&str[0], size) == size;
}
// Read POD, sizeof(T) is used
template<typename T>
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();
}
// 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)
template<typename T>
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
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
#pragma push_macro("new")
#pragma push_macro("Expects")
#pragma push_macro("Ensures")
#undef new
#include <gsl.h>
#pragma pop_macro("new")
#undef Expects
#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_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
{
@ -65,7 +69,7 @@ namespace _log
channel ARMv7("ARMv7");
}
void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const char* fmt...)
void logs::channel::broadcast(const logs::channel& ch, logs::level sev, const char* fmt...)
{
va_list args;
va_start(args, fmt);
@ -75,13 +79,13 @@ void _log::channel::broadcast(const _log::channel& ch, _log::level sev, const ch
[[noreturn]] extern void catch_all_exceptions();
_log::file_writer::file_writer(const std::string& name)
logs::file_writer::file_writer(const std::string& name)
{
try
{
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
{
throw fmt::exception("Can't create log file %s (error %d)", name, fs::error);
throw fmt::exception("Can't create log file %s (error %d)", name, fs::g_tls_error);
}
}
catch (...)
@ -90,17 +94,17 @@ _log::file_writer::file_writer(const std::string& name)
}
}
void _log::file_writer::log(const std::string& text)
void logs::file_writer::log(const std::string& text)
{
m_file.write(text);
}
std::size_t _log::file_writer::size() const
std::size_t logs::file_writer::size() const
{
return m_file.pos();
}
void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text)
void logs::file_listener::log(const logs::channel& ch, logs::level sev, const std::string& text)
{
std::string msg; msg.reserve(text.size() + 200);

View File

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

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_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big")
#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align)
#define CHECK_STORAGE(type, storage) static_assert(sizeof(type) <= sizeof(storage) && alignof(type) <= alignof(decltype(storage)), #type " is too small")
// Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t
#define SIZE_32(type) static_cast<std::uint32_t>(sizeof(type))
@ -60,20 +61,22 @@ constexpr std::uint32_t size32(const T(&)[Size])
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
// Macro set, allows to hide "return" in simple lambda expressions.
// Macro set, wraps an expression into lambda
#define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; }
#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; }
#define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; }
#define return_ return
#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro).
#define ASSERT(expr) if (!(expr)) throw std::runtime_error("Assertion failed: " #expr HERE)
#define VERIFY(expr) do { if (!(expr)) throw std::runtime_error("Verification failed: " #expr HERE); } while (0)
// Expects() and Ensures() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification.
#define Expects ASSERT
#define Ensures ASSERT
// EXPECTS() and ENSURES() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate.
#define EXPECTS(expr) do { if (!(expr)) throw std::runtime_error("Precondition failed: " #expr HERE); } while (0)
#define ENSURES(expr) do { if (!(expr)) throw std::runtime_error("Postcondition failed: " #expr HERE); } while (0)
#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__

View File

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

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()
{
if (UNLIKELY(!m_data))

View File

@ -32,6 +32,9 @@ class shared_mutex final
void lock_hard();
void unlock_notify();
void lock_upgrade_hard();
void lock_degrade_hard();
public:
constexpr shared_mutex() = default;
@ -42,15 +45,9 @@ public:
bool try_lock_shared()
{
auto ctrl = m_ctrl.load();
const u32 ctrl = m_ctrl.load();
if (UNLIKELY(ctrl >= SM_READER_MAX))
{
ctrl = 0;
}
// Weak attempt
return LIKELY(m_ctrl.compare_and_swap_test(ctrl, ctrl + 1));
return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1);
}
void lock_shared()
@ -72,12 +69,12 @@ public:
bool try_lock()
{
return LIKELY(m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK));
return !m_ctrl && m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK);
}
void lock()
{
if (UNLIKELY(!try_lock()))
if (UNLIKELY(!m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)))
{
lock_hard();
}
@ -85,11 +82,39 @@ public:
void unlock()
{
if (UNLIKELY(m_ctrl.fetch_sub(SM_WRITER_LOCK) != SM_WRITER_LOCK))
m_ctrl &= ~SM_WRITER_LOCK;
if (UNLIKELY(m_ctrl))
{
unlock_notify();
}
}
bool try_lock_upgrade()
{
return m_ctrl == 1 && m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK);
}
bool try_lock_degrade()
{
return m_ctrl == SM_WRITER_LOCK && m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1);
}
void lock_upgrade()
{
if (UNLIKELY(!m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK)))
{
lock_upgrade_hard();
}
}
void lock_degrade()
{
if (UNLIKELY(!m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1)))
{
lock_degrade_hard();
}
}
};
//! Simplified shared (reader) lock implementation.
@ -133,3 +158,23 @@ public:
m_mutex.unlock();
}
};
// Exclusive (writer) lock in the scope of shared (reader) lock.
class upgraded_lock final
{
shared_mutex& m_mutex;
public:
upgraded_lock(const writer_lock&) = delete;
upgraded_lock(shared_mutex& mutex)
: m_mutex(mutex)
{
m_mutex.lock_upgrade();
}
~upgraded_lock()
{
m_mutex.lock_degrade();
}
};

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,8 @@
#pragma once
#include <exception>
#include <string>
#include <memory>
#include <thread>
#include "Platform.h"
#include "Atomic.h"
@ -28,17 +28,12 @@ class task_stack
}
};
std::unique_ptr<task_base> m_stack;
public:
template<typename F>
void push(F&& func)
{
struct task_t : task_base
struct task_type : task_base
{
std::remove_reference_t<F> func;
task_t(F&& func)
task_type(F&& func)
: func(std::forward<F>(func))
{
}
@ -50,16 +45,24 @@ public:
}
};
auto _top = new task_t(std::forward<F>(func));
std::unique_ptr<task_base> m_stack;
public:
task_stack() = default;
template<typename F>
task_stack(F&& func)
: m_stack(new task_type<F>(std::forward<F>(func)))
{
}
void push(task_stack stack)
{
auto _top = stack.m_stack.release();
auto _next = m_stack.release();
m_stack.reset(_top);
#ifndef _MSC_VER
while (UNLIKELY(_top->next)) _top = _top->next.get();
_top->next.reset(_next);
#else
auto& next = _top->next;
next.release();
next.reset(_next);
#endif
}
void reset()
@ -79,42 +82,48 @@ public:
// Thread control class
class thread_ctrl final
{
public: // TODO
struct internal;
private:
static thread_local thread_ctrl* g_tls_this_thread;
// Thread handle
std::thread m_thread;
// Thread handle storage
std::aligned_storage_t<16> m_thread;
// Thread join contention counter
atomic_t<uint> m_joining{};
atomic_t<u32> m_joining{};
// Thread internals
atomic_t<internal*> m_data{};
// Fixed name
std::string m_name;
// Thread internals
mutable atomic_t<internal*> m_data{};
// Start thread
static void start(const std::shared_ptr<thread_ctrl>&, task_stack);
// Called at the thread start
void initialize();
// Set std::current_exception
void set_exception() noexcept;
// Called at the thread end
void finalize() noexcept;
// Get atexit function
task_stack& get_atexit() const;
void push_atexit(task_stack);
// Start waiting
void wait_start(u64 timeout);
// Proceed waiting
bool wait_wait(u64 timeout);
// Check exception
void test();
public:
template<typename N>
thread_ctrl(N&& name)
: m_name(std::forward<N>(name))
{
}
thread_ctrl(std::string&& name);
// Disable copy/move constructors and operators
thread_ctrl(const thread_ctrl&) = delete;
~thread_ctrl();
@ -126,54 +135,139 @@ public:
}
// Initialize internal data
void initialize_once() const;
void initialize_once();
// Get thread result (may throw, simultaneous joining allowed)
void join();
// Lock thread mutex
void lock();
// Lock conditionally (double-checked)
template<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)
void lock_notify() const;
void lock_notify();
// Notify the thread, beware the condition change
void notify() const;
// Notify the thread (internal data must be initialized)
void notify();
//
internal* get_data() const;
// Set exception (internal data must be initialized, thread mutex must be locked)
void set_exception(std::exception_ptr);
// Current thread sleeps for specified amount of microseconds.
// Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl.
[[deprecated]] static void sleep(u64 useconds);
// Wait until pred(). Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
template<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)
static const thread_ctrl* get_current()
static thread_ctrl* get_current()
{
return g_tls_this_thread;
}
// Register function at thread exit (for the current thread)
template<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
template<typename N, typename F, typename... Args>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func, Args&&... args)
template<typename N, typename F>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
{
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](Args&&... args)
{
try
{
ctrl->initialize();
task(std::forward<Args>(args)...);
}
catch (...)
{
ctrl->set_exception();
}
ctrl->finalize();
}, std::forward<Args>(args)...);
thread_ctrl::start(ctrl, std::forward<F>(func));
return ctrl;
}
@ -218,22 +312,43 @@ public:
m_thread->join();
}
// Get thread_ctrl
const thread_ctrl* operator->() const
// Access thread_ctrl
thread_ctrl* operator->() const
{
return m_thread.get();
}
};
// Lock mutex, notify condition variable
void lock_notify() const
// Simple thread mutex locker
class thread_lock final
{
thread_ctrl* m_thread;
public:
thread_lock(const thread_lock&) = delete;
// Lock specified thread
thread_lock(thread_ctrl* thread)
: m_thread(thread)
{
m_thread->lock_notify();
m_thread->lock();
}
// Notify condition variable
void notify() const
// Lock specified named_thread
thread_lock(named_thread& thread)
: thread_lock(thread.operator->())
{
m_thread->notify();
}
// Lock current thread
thread_lock()
: thread_lock(thread_ctrl::get_current())
{
}
~thread_lock()
{
m_thread->unlock();
}
};

View File

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

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.
// For example, `simple_t` may be used to remove endianness.
template<template<typename> class TT, std::size_t S, std::size_t A = S>
struct alignas(A) any_pod
{
enum class byte : char {} data[S];
std::aligned_storage_t<S, A> data;
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.
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fexceptions")
add_compile_options(-msse -msse2 -mcx16 -mssse3)
add_compile_options(-msse -msse2 -mcx16 -mssse3 -march=native)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew /D _CRT_SECURE_NO_DEPRECATE=1 /D _CRT_NON_CONFORMING_SWPRINTFS=1 /D _SCL_SECURE_NO_WARNINGS=1")
endif()

View File

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

View File

@ -1,15 +1,15 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "CPUThread.h"
#include <mutex>
#include <condition_variable>
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr;
extern std::mutex& get_current_thread_mutex();
extern std::condition_variable& get_current_thread_cv();
void cpu_thread::on_task()
{
state -= cpu_state::exit;
@ -61,7 +61,7 @@ void cpu_thread::on_task()
void cpu_thread::on_stop()
{
state += cpu_state::exit;
lock_notify();
(*this)->lock_notify();
}
cpu_thread::~cpu_thread()
@ -121,35 +121,3 @@ bool cpu_thread::check_status()
return false;
}
[[noreturn]] void cpu_thread::xsleep()
{
throw std::runtime_error("cpu_thread: sleep()/awake() inconsistency");
}
std::vector<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 cpu_type type;
const id_value<> id{};
cpu_thread(cpu_type type, const std::string& name);
@ -48,36 +47,34 @@ public:
// Public thread state
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
// Recursively enter sleep state
void sleep()
{
if (!++m_sleep) xsleep();
}
// Public recursive sleep state counter
atomic_t<u32> sleep_counter{};
// Leave sleep state
void awake()
{
if (!m_sleep--) xsleep();
}
// Object associated with sleep state, possibly synchronization primitive (mutex, semaphore, etc.)
atomic_t<void*> owner{};
// Process thread state, return true if the checker must return
bool check_status();
virtual std::string dump() const = 0; // Print CPU state
// Increse sleep counter
void sleep()
{
if (!sleep_counter++) return; //handle_interrupt();
}
// Decrese sleep counter
void awake()
{
if (!--sleep_counter) owner = nullptr;
}
// Print CPU state
virtual std::string dump() const = 0;
virtual void cpu_init() {}
virtual void cpu_task() = 0;
virtual bool handle_interrupt() { return false; }
private:
[[noreturn]] void xsleep();
// Sleep/Awake counter
atomic_t<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
{
extern thread_local cpu_thread* g_tls_current_cpu_thread;
@ -85,4 +82,26 @@ inline cpu_thread* get_current_cpu_thread() noexcept
return g_tls_current_cpu_thread;
}
extern std::vector<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,6 +1,13 @@
#include "stdafx.h"
#include "IdManager.h"
DECLARE(idm::g_map);
DECLARE(idm::g_id);
DECLARE(idm::g_mutex);
DECLARE(fxm::g_map);
DECLARE(fxm::g_mutex);
std::vector<id_manager::typeinfo>& id_manager::typeinfo::access()
{
static std::vector<typeinfo> list;

View File

@ -8,8 +8,6 @@
#include <memory>
#include <vector>
#include <unordered_map>
#include <set>
#include <map>
// Mostly helper namespace
namespace id_manager
@ -37,7 +35,7 @@ namespace id_manager
template<typename T, typename = void>
struct on_init
{
static void func(T*)
static inline void func(T*)
{
}
};
@ -45,7 +43,7 @@ namespace id_manager
template<typename T>
struct on_init<T, decltype(std::declval<T>().on_init())>
{
static void func(T* ptr)
static inline void func(T* ptr)
{
ptr->on_init();
}
@ -55,7 +53,7 @@ namespace id_manager
template<typename T, typename = void>
struct on_stop
{
static void func(T*)
static inline void func(T*)
{
}
};
@ -63,7 +61,7 @@ namespace id_manager
template<typename T>
struct on_stop<T, decltype(std::declval<T>().on_stop())>
{
static void func(T* ptr)
static inline void func(T* ptr)
{
ptr->on_stop();
}
@ -155,15 +153,41 @@ class idm
// Update optional ID storage
template<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;
}
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
static map_type::pointer allocate_id(u32 tag, u32 min, u32 max);
@ -213,7 +237,7 @@ public:
// Add a new ID of specified type with specified constructor arguments (returns object or nullptr)
template<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)...))))
{
@ -226,7 +250,7 @@ public:
// Add a new ID of specified type with specified constructor arguments (returns id)
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)...))))
{
@ -239,7 +263,7 @@ public:
// Add a new ID for an existing object provided (returns new id)
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)))
{
@ -252,7 +276,7 @@ public:
// Add a new ID for an object returned by provider()
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)))
{
@ -263,18 +287,18 @@ public:
return nullptr;
}
// Check whether ID exists
// Check whether the ID exists
template<typename T>
static bool check(u32 id)
static inline bool check(u32 id)
{
reader_lock lock(g_mutex);
return find_id(get_type<T>(), id) != nullptr;
}
// Get ID
// Get the ID
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);
@ -288,25 +312,63 @@ public:
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>
static std::vector<std::shared_ptr<T>> get_all()
static inline u32 get_count()
{
reader_lock lock(g_mutex);
std::vector<std::shared_ptr<T>> result;
for (auto& id : g_map[get_type<T>()])
{
result.emplace_back(id.second, static_cast<T*>(id.second.get()));
}
return result;
return ::size32(g_map[get_type<T>()]);
}
// Remove the ID
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);
@ -320,7 +382,7 @@ public:
// Remove the ID and return it
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);
@ -332,44 +394,29 @@ public:
return{ ptr, static_cast<T*>(ptr.get()) };
}
template<typename T>
static u32 get_count()
// Conditionally remove the ID and return it.
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;
{
writer_lock lock(g_mutex);
return ::size32(g_map[get_type<T>()]);
const auto found = find_id(get_type<T>(), id);
if (UNLIKELY(found == nullptr || !pred(id, *static_cast<T*>(found->second.get()))))
{
return nullptr;
}
// Get sorted list of all IDs of specified type
template<typename T>
static std::set<u32> get_set()
{
reader_lock lock(g_mutex);
ptr = deallocate_id(get_tag<T>(), id);
std::set<u32> result;
for (auto& id : g_map[get_type<T>()])
{
result.emplace(id.first);
g_map[get_type<T>()].erase(id);
}
return result;
}
id_manager::on_stop<T>::func(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;
return{ ptr, static_cast<T*>(ptr.get()) };
}
};
@ -518,7 +565,7 @@ public:
// Check whether the object exists
template<typename T>
static bool check()
static inline bool check()
{
reader_lock lock(g_mutex);
@ -527,7 +574,7 @@ public:
// Get the object (returns nullptr if it doesn't exist)
template<typename T>
static std::shared_ptr<T> get()
static inline std::shared_ptr<T> get()
{
reader_lock lock(g_mutex);
@ -538,7 +585,7 @@ public:
// Delete the object
template<typename T>
static bool remove()
static inline bool remove()
{
auto&& ptr = remove(get_type<T>());
@ -552,7 +599,7 @@ public:
// Delete the object and return it
template<typename T>
static std::shared_ptr<T> withdraw()
static inline std::shared_ptr<T> withdraw()
{
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)
{
Expects(size);
EXPECTS(size);
for (u32 addr = m_range_start; addr <= m_range_start + m_range_size - 1 - GetReservedAmount() - size;)
{
@ -48,7 +48,7 @@ u32 VirtualMemoryBlock::Map(u32 realaddr, u32 size)
bool VirtualMemoryBlock::Map(u32 realaddr, u32 size, u32 addr)
{
Expects(size);
EXPECTS(size);
if (!IsInMyRange(addr, size))
{

View File

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

View File

@ -1,6 +1,7 @@
#pragma once
#include <map>
#include <mutex>
class thread_ctrl;
@ -32,6 +33,9 @@ namespace vm
page_allocated = (1 << 7),
};
// Address type
enum addr_t : u32 {};
struct access_violation : std::runtime_error
{
access_violation(u64 addr, const char* cause);
@ -60,7 +64,7 @@ namespace vm
bool reservation_query(u32 addr, u32 size, bool is_writing, std::function<bool()> callback);
// Returns true if the current thread owns reservation
bool reservation_test(const thread_ctrl* current);
bool reservation_test(thread_ctrl* current);
// Break all reservations created by the current thread
void reservation_free();
@ -133,11 +137,11 @@ namespace vm
std::shared_ptr<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)
inline u32 get_addr(const void* real_ptr)
inline vm::addr_t get_addr(const void* real_ptr)
{
if (!real_ptr)
{
return 0;
return vm::addr_t{};
}
const std::ptrdiff_t diff = static_cast<const u8*>(real_ptr) - g_base_addr;
@ -145,7 +149,7 @@ namespace vm
if (res == diff)
{
return res;
return static_cast<vm::addr_t>(res);
}
throw fmt::exception("Not a virtual memory pointer (%p)", real_ptr);
@ -166,36 +170,57 @@ namespace vm
template<>
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<>
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>
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);
}
static vm::addr_t cast(const se_t<T, Se>& addr)
{
return cast_impl<T>::cast(addr);
}
};
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);
}
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
inline void* base(u32 addr)
{

View File

@ -25,12 +25,12 @@ namespace vm
_ptr_base() = default;
constexpr _ptr_base(addr_type addr, const addr_tag_t&)
_ptr_base(vm::addr_t addr)
: m_addr(addr)
{
}
constexpr addr_type addr() const
addr_type addr() const
{
return m_addr;
}
@ -40,19 +40,21 @@ namespace vm
this->m_addr = addr;
}
static constexpr _ptr_base make(addr_type addr)
static _ptr_base make(addr_type addr)
{
return{ addr, vm::addr };
_ptr_base result;
result.m_addr = addr;
return result;
}
// Enable only the conversions which are originally possible between pointer types
template<typename T2, typename AT2, typename = std::enable_if_t<std::is_convertible<T*, T2*>::value>>
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;
}
@ -61,34 +63,34 @@ namespace vm
template<typename MT, typename T2, typename = if_comparable_t<T, T2>>
_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
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
{
return{ vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr };
return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index);
}
// Get vm reference to a struct member
template<typename MT, typename T2, typename = if_comparable_t<T, T2>>
_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
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
{
return{ vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index, vm::addr };
return vm::cast(vm::cast(m_addr, HERE) + get_offset(mptr) + SIZE_32(ET) * index);
}
// Get vm reference
_ref_base<T, u32> ref() const
{
return{ vm::cast(m_addr, HERE), vm::addr };
return vm::cast(m_addr, HERE);
}
T* get_ptr() const
@ -136,22 +138,22 @@ namespace vm
_ptr_base<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
{
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
{
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)
{
return{ vm::cast(ptr.m_addr, HERE) + count * SIZE_32(T), vm::addr };
return vm::cast(vm::cast(ptr.m_addr, HERE) + count * SIZE_32(T));
}
// Pointer difference operator
@ -163,9 +165,9 @@ namespace vm
_ptr_base operator ++(int)
{
const addr_type result = m_addr;
_ptr_base result = *this;
m_addr = vm::cast(m_addr, HERE) + SIZE_32(T);
return{ result, vm::addr };
return result;
}
_ptr_base& operator ++()
@ -176,9 +178,9 @@ namespace vm
_ptr_base operator --(int)
{
const addr_type result = m_addr;
_ptr_base result = m_addr;
m_addr = vm::cast(m_addr, HERE) - SIZE_32(T);
return{ result, vm::addr };
return result;
}
_ptr_base& operator --()
@ -210,12 +212,12 @@ namespace vm
_ptr_base() = default;
constexpr _ptr_base(addr_type addr, const addr_tag_t&)
_ptr_base(vm::addr_t addr)
: m_addr(addr)
{
}
constexpr addr_type addr() const
addr_type addr() const
{
return m_addr;
}
@ -225,26 +227,28 @@ namespace vm
m_addr = addr;
}
static constexpr _ptr_base make(addr_type addr)
static _ptr_base make(addr_type addr)
{
return{ addr, vm::addr };
_ptr_base result;
result.m_addr = addr;
return result;
}
// Conversion to another function pointer
template<typename AT2>
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;
}
_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
@ -305,14 +309,14 @@ namespace vm
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)
{
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>)
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)
{
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*>()))>
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>)
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)
{
return{ vm::cast(other.addr(), HERE), vm::addr };
return vm::cast(other.addr(), HERE);
}
}
struct null_t
{
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>
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;
}
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;
}
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();
}
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();
}
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();
}
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;
}
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;
}
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();
}
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;
}
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();
}
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;
}
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;
}

View File

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

View File

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

View File

@ -6,98 +6,70 @@
#include "Utilities/Thread.h"
#include "Utilities/SharedMutex.h"
extern std::condition_variable& get_current_thread_cv();
extern std::mutex& get_current_thread_mutex();
#include <unordered_set>
namespace vm
{
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);
this->addr = addr;
this->mask = ~(size - 1);
this->thread = thread_ctrl::get_current();
{
std::lock_guard<mutex_t> lock(*mutex);
writer_lock lock(s_mutex);
s_waiters.emplace(this);
}
// Wait until thread == nullptr
thread_lock(), thread_ctrl::wait(WRAP_EXPR(!thread || test()));
}
bool waiter_base::try_notify()
{
const auto _t = atomic_storage<thread_ctrl*>::load(thread);
if (UNLIKELY(!_t))
{
// Return if thread not found
return false;
}
// Lock the thread
_t->lock();
try
{
// Test predicate
if (!pred || !pred())
if (UNLIKELY(!thread || !test()))
{
_t->unlock();
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);
};
// Capture any exception thrown by the predicate
_t->set_exception(std::current_exception());
}
// Set addr and mask to invalid values to prevent further polling
addr = 0;
mask = ~0;
}
// Signal thread
cond->notify_one();
// Signal the thread with nullptr
atomic_storage<thread_ctrl*>::store(thread, nullptr);
_t->unlock();
_t->notify();
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);
waiter_base::~waiter_base()
{
writer_lock lock(s_mutex);
s_waiters.emplace(&m_waiter);
}
m_lock.lock();
}
void waiter_lock::wait()
{
// If another thread successfully called pred(), it must be set to null
while (m_waiter.pred)
{
// If pred() called by another thread threw an exception, it'll be rethrown
if (m_waiter.pred())
{
return;
}
CHECK_EMU_STATUS;
m_waiter.cond->wait(m_lock);
}
}
waiter_lock::~waiter_lock()
{
if (m_lock) m_lock.unlock();
writer_lock lock(s_mutex);
s_waiters.erase(&m_waiter);
s_waiters.erase(this);
}
void notify_at(u32 addr, u32 size)
@ -114,44 +86,37 @@ namespace vm
}
}
static bool notify_all()
// Return amount of threads which are not notified
static std::size_t notify_all()
{
reader_lock lock(s_mutex);
std::size_t waiters = 0;
std::size_t signaled = 0;
for (const auto _w : s_waiters)
{
if (_w->addr)
{
waiters++;
if (_w->try_notify())
{
signaled++;
}
}
}
// return true if waiter list is empty or all available waiters were signaled
return waiters == signaled;
return s_waiters.size() - signaled;
}
void start()
{
// start notification thread
thread_ctrl::spawn("vm::start thread", []()
thread_ctrl::spawn("vm::wait", []()
{
while (!Emu.IsStopped())
{
// poll waiters periodically (TODO)
while (!notify_all() && !Emu.IsPaused())
// Poll waiters periodically (TODO)
while (notify_all() && !Emu.IsPaused())
{
std::this_thread::yield();
thread_ctrl::sleep(50);
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
thread_ctrl::sleep(1000);
}
});
}

View File

@ -1,61 +1,50 @@
#pragma once
#include <mutex>
#include <condition_variable>
#include <functional>
#include "Utilities/types.h"
#include "Utilities/Macro.h"
class named_thread;
class thread_ctrl;
namespace vm
{
using mutex_t = std::mutex;
using cond_t = std::condition_variable;
struct waiter
struct waiter_base
{
u32 addr;
u32 mask;
mutex_t* mutex;
cond_t* cond;
std::function<bool()> pred;
~waiter();
thread_ctrl* thread{};
void initialize(u32 addr, u32 size);
bool try_notify();
protected:
~waiter_base();
virtual bool test() = 0;
};
class waiter_lock
// Wait until pred() returns true, addr must be aligned to size which must be a power of 2.
// It's possible for pred() to be called from any thread once the waiter is registered.
template<typename F>
auto wait_op(u32 addr, u32 size, F&& pred) -> decltype(static_cast<void>(pred()))
{
waiter m_waiter;
std::unique_lock<mutex_t> m_lock;
if (LIKELY(pred())) return;
public:
waiter_lock(u32 addr, u32 size);
waiter* operator ->()
struct waiter : waiter_base
{
std::conditional_t<sizeof(F) <= sizeof(void*), std::remove_reference_t<F>, F&&> func;
waiter(F&& func)
: func(std::forward<F>(func))
{
return &m_waiter;
}
void wait();
~waiter_lock();
bool test() override
{
return func();
}
};
// Wait until pred() returns true, addr must be aligned to size which must be a power of 2, pred() may be called by any thread
template<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();
waiter(std::forward<F>(pred)).initialize(addr, size);
}
// 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 "Emu/RSX/RSXFragmentProgram.h"
#include <algorithm>
void CgBinaryDisasm::AddCodeAsm(const std::string& code)
{
Expects(m_opcode < 70);
EXPECTS(m_opcode < 70);
std::string op_name = "";
if (dst.dest_reg == 63)
@ -223,7 +225,7 @@ void CgBinaryDisasm::TaskFP()
{
m_size = 0;
u32* data = (u32*)&m_buffer[m_offset];
Expects((m_buffer_size - m_offset) % sizeof(u32) == 0);
EXPECTS((m_buffer_size - m_offset) % sizeof(u32) == 0);
for (u32 i = 0; i < (m_buffer_size - m_offset) / sizeof(u32); i++)
{
data[i] = se_storage<u32>::swap(data[i]); // WTF, cannot use be_t<> there?
@ -471,7 +473,7 @@ void CgBinaryDisasm::TaskFP()
break;
}
Ensures(m_step % sizeof(u32) == 0);
ENSURES(m_step % sizeof(u32) == 0);
data += m_step / sizeof(u32);
}
}

View File

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

View File

@ -6,13 +6,13 @@
void CgBinaryDisasm::AddScaCodeDisasm(const std::string& code)
{
Expects(m_sca_opcode < 21);
EXPECTS(m_sca_opcode < 21);
m_arb_shader += rsx_vp_sca_op_names[m_sca_opcode] + code + " ";
}
void CgBinaryDisasm::AddVecCodeDisasm(const std::string& code)
{
Expects(m_vec_opcode < 26);
EXPECTS(m_vec_opcode < 26);
m_arb_shader += rsx_vp_vec_op_names[m_vec_opcode] + code + " ";
}

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)
{
Expects(vector_element_count > 0);
EXPECTS(vector_element_count > 0);
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 max_index = 0;
Expects(dst.size_bytes() >= src.size_bytes());
EXPECTS(dst.size_bytes() >= src.size_bytes());
size_t dst_idx = 0;
for (T index : src)
@ -124,7 +124,7 @@ std::tuple<T, T> expand_indexed_triangle_fan(gsl::span<to_be_t<const T>> src, gs
T min_index = -1;
T max_index = 0;
Expects(dst.size() >= 3 * (src.size() - 2));
EXPECTS(dst.size() >= 3 * (src.size() - 2));
const T index0 = src[0];
if (!is_primitive_restart_enabled || index0 != -1) // Cut
@ -174,7 +174,7 @@ std::tuple<T, T> expand_indexed_quads(gsl::span<to_be_t<const T>> src, gsl::span
T min_index = -1;
T max_index = 0;
Expects(4 * dst.size_bytes() >= 6 * src.size_bytes());
EXPECTS(4 * dst.size_bytes() >= 6 * src.size_bytes());
size_t dst_idx = 0;
while (!src.empty())
@ -353,7 +353,7 @@ std::tuple<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));
Expects(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0);
EXPECTS(rsx::method_registers[NV4097_SET_VERTEX_DATA_BASE_INDEX] == 0);
bool is_primitive_restart_enabled = !!rsx::method_registers[NV4097_SET_RESTART_INDEX_ENABLE];
u32 primitive_restart_index = rsx::method_registers[NV4097_SET_RESTART_INDEX];
@ -363,7 +363,7 @@ std::tuple<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> &next_range = first_count_arguments[i + 1];
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
}
u32 first = std::get<0>(first_count_arguments.front());
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
@ -415,7 +415,7 @@ std::tuple<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> &next_range = first_count_arguments[i + 1];
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
}
u32 first = std::get<0>(first_count_arguments.front());
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;
@ -438,7 +438,7 @@ std::tuple<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> &next_range = first_count_arguments[i + 1];
Expects(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
EXPECTS(std::get<0>(range) + std::get<1>(range) == std::get<0>(next_range));
}
u32 first = std::get<0>(first_count_arguments.front());
u32 count = std::get<0>(first_count_arguments.back()) + std::get<1>(first_count_arguments.back()) - first;

View File

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

View File

@ -227,7 +227,7 @@ public:
0x6, 0x7, 0x4, 0x5,
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;
for (size_t offset_in_fragment_program : I->second.FragmentConstantOffsetCache)

View File

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

View File

@ -21,7 +21,7 @@ namespace
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.");
Expects(dst.size() == src.size());
EXPECTS(dst.size() == src.size());
std::copy(src.begin(), src.end(), dst.begin());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#ifdef _MSC_VER
#include "stdafx.h"
#include "stdafx_d3d12.h"
#ifdef _MSC_VER
#include "Utilities/Config.h"
#include "D3D12GSRender.h"
#include <wrl/client.h>
@ -43,13 +43,13 @@ HMODULE D3DCompiler;
void loadD3D12FunctionPointers()
{
ASSERT(D3D12Module = LoadLibrary(L"d3d12.dll"));
VERIFY(D3D12Module = LoadLibrary(L"d3d12.dll"));
wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice");
wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface");
wrapD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)GetProcAddress(D3D12Module, "D3D12SerializeRootSignature");
ASSERT(D3D11Module = LoadLibrary(L"d3d11.dll"));
VERIFY(D3D11Module = LoadLibrary(L"d3d11.dll"));
wrapD3D11On12CreateDevice = (PFN_D3D11ON12_CREATE_DEVICE)GetProcAddress(D3D11Module, "D3D11On12CreateDevice");
ASSERT(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll"));
VERIFY(D3DCompiler = LoadLibrary(L"d3dcompiler_47.dll"));
wrapD3DCompile = (pD3DCompile)GetProcAddress(D3DCompiler, "D3DCompile");
}
@ -486,7 +486,7 @@ void D3D12GSRender::flip(int buffer)
if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])))
{
resource_storage &storage = get_current_resource_storage();
ASSERT(storage.ram_framebuffer == nullptr);
VERIFY(storage.ram_framebuffer == nullptr);
size_t w = 0, h = 0, row_pitch = 0;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@
#include <stack>
#include <deque>
#include <set>
#include <mutex>
#include "GCM.h"
#include "RSXTexture.h"
#include "RSXVertexProgram.h"
@ -52,13 +53,18 @@ namespace rsx
}
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" },
{ rsx::shader_language::hlsl, "hlsl" },
};
switch (in)
{
case rsx::shader_language::glsl: return "glsl";
case rsx::shader_language::hlsl: return "hlsl";
}
return "";
}
};
namespace rsx

View File

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

View File

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

View File

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

View File

@ -9,7 +9,9 @@
#include "Emu/Cell/PPUCallback.h"
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/RawSPUThread.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/PSP2/ARMv7Thread.h"
#include "Emu/IdManager.h"
#include "Emu/RSX/GSRender.h"
@ -21,6 +23,8 @@
#include "../Crypto/unself.h"
#include <thread>
cfg::bool_entry g_cfg_autostart(cfg::root.misc, "Always start after boot");
cfg::bool_entry g_cfg_autoexit(cfg::root.misc, "Exit RPCS3 when process finishes");
@ -31,6 +35,8 @@ extern cfg::string_entry g_cfg_vfs_app_home;
extern atomic_t<u32> g_thread_count;
extern atomic_t<u32> g_ppu_core[2];
extern u64 get_system_time();
fs::file g_tty;
@ -60,6 +66,9 @@ void Emulator::Init()
idm::init();
fxm::init();
g_ppu_core[0] = 0;
g_ppu_core[1] = 0;
// Reset defaults, cache them
cfg::root.from_default();
g_cfg_defaults = cfg::root.to_string();
@ -252,10 +261,10 @@ void Emulator::Load()
{
LOG_ERROR(LOADER, "Invalid or unsupported file format: %s", m_path);
LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", bijective_find<elf_error>(ppu_exec, "???"));
LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", bijective_find<elf_error>(ppu_prx, "???"));
LOG_WARNING(LOADER, "** spu_exec_loader -> %s", bijective_find<elf_error>(spu_exec, "???"));
LOG_WARNING(LOADER, "** arm_exec_loader -> %s", bijective_find<elf_error>(arm_exec, "???"));
LOG_WARNING(LOADER, "** ppu_exec_loader -> %s", ppu_exec.get_error());
LOG_WARNING(LOADER, "** ppu_prx_loader -> %s", ppu_prx.get_error());
LOG_WARNING(LOADER, "** spu_exec_loader -> %s", spu_exec.get_error());
LOG_WARNING(LOADER, "** arm_exec_loader -> %s", arm_exec.get_error());
return;
}
@ -294,11 +303,11 @@ void Emulator::Run()
m_pause_amend_time = 0;
m_status = Running;
for (auto& thread : get_all_cpu_threads())
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{
thread->state -= cpu_state::stop;
thread->lock_notify();
}
cpu.state -= cpu_state::stop;
cpu->lock_notify();
});
SendDbgCommand(DID_STARTED_EMU);
}
@ -323,10 +332,10 @@ bool Emulator::Pause()
SendDbgCommand(DID_PAUSE_EMU);
for (auto& thread : get_all_cpu_threads())
idm::select<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);
@ -357,11 +366,11 @@ void Emulator::Resume()
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;
thread->lock_notify();
}
cpu.state -= cpu_state::dbg_global_pause;
cpu->lock_notify();
});
rpcs3::on_resume()();
@ -383,11 +392,11 @@ void Emulator::Stop()
{
LV2_LOCK;
for (auto& thread : get_all_cpu_threads())
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
{
thread->state += cpu_state::dbg_global_stop;
thread->lock_notify();
}
cpu.state += cpu_state::dbg_global_stop;
cpu->lock_notify();
});
}
LOG_NOTICE(GENERAL, "All threads signaled...");
@ -424,16 +433,3 @@ void Emulator::Stop()
}
Emulator Emu;
DECLARE(idm::g_map);
DECLARE(idm::g_id);
DECLARE(idm::g_mutex);
DECLARE(fxm::g_map);
DECLARE(fxm::g_mutex);
#ifndef _MSC_VER
constexpr DECLARE(bijective<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 "Gui/ConLogFrame.h"
#include <chrono>
enum
{
id_log_copy, // Copy log to ClipBoard
@ -210,19 +212,19 @@ void LogFrame::OnTimer(wxTimerEvent& event)
if (text[pos + 2] == ' ')
{
_log::level level;
logs::level level;
wxColour color;
switch (text[pos + 1].GetValue())
{
case 'A': level = _log::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan
case 'F': level = _log::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia
case 'E': level = _log::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red
case 'U': level = _log::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange
case 'S': level = _log::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green
case 'W': level = _log::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow
case '!': level = _log::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White
case 'T': level = _log::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray
case 'A': level = logs::level::always; color.Set(0x00, 0xFF, 0xFF); break; // Cyan
case 'F': level = logs::level::fatal; color.Set(0xFF, 0x00, 0xFF); break; // Fuchsia
case 'E': level = logs::level::error; color.Set(0xFF, 0x00, 0x00); break; // Red
case 'U': level = logs::level::todo; color.Set(0xFF, 0x60, 0x00); break; // Orange
case 'S': level = logs::level::success; color.Set(0x00, 0xFF, 0x00); break; // Green
case 'W': level = logs::level::warning; color.Set(0xFF, 0xFF, 0x00); break; // Yellow
case '!': level = logs::level::notice; color.Set(0xFF, 0xFF, 0xFF); break; // White
case 'T': level = logs::level::trace; color.Set(0x80, 0x80, 0x80); break; // Gray
default: continue;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,22 +20,12 @@ namespace psf
public:
// Construct string entry, assign the value
entry(format type, u32 max_size, const std::string& value = {})
: m_type(type)
, m_max_size(max_size)
, m_value_string(value)
{
Expects(type == format::string || type == format::array);
Expects(max_size);
}
entry(format type, u32 max_size, const std::string& value = {});
// Construct integer entry, assign the value
entry(u32 value)
: m_type(format::integer)
, m_max_size(sizeof(u32))
, m_value_integer(value)
{
}
entry(u32 value);
~entry();
const std::string& as_string() const;
u32 as_integer() const;
@ -51,24 +41,11 @@ namespace psf
// Define PSF registry as a sorted map of entries:
using registry = std::map<std::string, entry>;
// Load PSF registry from SFO binary data
registry load_object(const std::vector<char>&);
// 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{};
}
}
// Load PSF registry from SFO binary format
registry load_object(const fs::file&);
// 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
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);
// TODO: rXmlDocument can open only real file
ASSERT(!fs::get_virtual_device(path));
VERIFY(!fs::get_virtual_device(path));
rXmlDocument doc;
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);
if (!fs::create_dir(local_path) && fs::error != EEXIST)
if (!fs::create_dir(local_path) && fs::g_tls_error != fs::error::exist)
{
return false;
}

View File

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

View File

@ -54,12 +54,6 @@
<Filter Include="Emu\GPU\RSX\Common">
<UniqueIdentifier>{2a8841dc-bce0-41bb-9fcb-5bf1f8dda213}</UniqueIdentifier>
</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">
<UniqueIdentifier>{13d20086-2188-425a-9856-0440fe6f79f2}</UniqueIdentifier>
</Filter>
@ -69,6 +63,12 @@
<Filter Include="Emu\Cell\Modules">
<UniqueIdentifier>{4317ac27-38e4-4f8d-9bac-496f9b00f615}</UniqueIdentifier>
</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>
<ClCompile Include="Crypto\aes.cpp">
@ -113,9 +113,6 @@
<ClCompile Include="Emu\CPU\CPUThread.cpp">
<Filter>Emu\CPU</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Thread.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\Audio\AudioDumper.cpp">
<Filter>Emu\Audio</Filter>
</ClCompile>
@ -161,192 +158,9 @@
<ClCompile Include="Crypto\ec.cpp">
<Filter>Crypto</Filter>
</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">
<Filter>Utilities</Filter>
</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">
<Filter>Emu\GPU\RSX</Filter>
</ClCompile>
@ -419,9 +233,6 @@
<ClCompile Include="Emu\Cell\PPUDisAsm.cpp">
<Filter>Emu\Cell</Filter>
</ClCompile>
<ClCompile Include="Emu\ARMv7\ARMv7Function.cpp">
<Filter>Emu\ARMv7</Filter>
</ClCompile>
<ClCompile Include="Emu\Cell\lv2\lv2.cpp">
<Filter>Emu\Cell\lv2</Filter>
</ClCompile>
@ -833,12 +644,6 @@
<ClCompile Include="Emu\Cell\Modules\sys_libc_.cpp">
<Filter>Emu\Cell\Modules</Filter>
</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">
<Filter>Utilities</Filter>
</ClCompile>
@ -854,6 +659,201 @@
<ClCompile Include="Emu\IdManager.cpp">
<Filter>Emu</Filter>
</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>
<ClInclude Include="Crypto\aes.h">
@ -937,18 +937,6 @@
<ClInclude Include="Emu\CPU\CPUThread.h">
<Filter>Emu\CPU</Filter>
</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">
<Filter>Emu\Audio</Filter>
</ClInclude>
@ -1057,33 +1045,6 @@
<ClInclude Include="Emu\Audio\AudioThread.h">
<Filter>Emu\Audio</Filter>
</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">
<Filter>Utilities</Filter>
</ClInclude>
@ -1099,159 +1060,9 @@
<ClInclude Include="Emu\RSX\Common\VertexProgramDecompiler.h">
<Filter>Emu\GPU\RSX\Common</Filter>
</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">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\SleepQueue.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\Common.h">
<Filter>Emu\Cell</Filter>
</ClInclude>
@ -1306,9 +1117,6 @@
<ClInclude Include="Loader\ELF.h">
<Filter>Loader</Filter>
</ClInclude>
<ClInclude Include="Emu\ARMv7\ARMv7Function.h">
<Filter>Emu\ARMv7</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\lv2\sys_cond.h">
<Filter>Emu\Cell\lv2</Filter>
</ClInclude>
@ -1579,15 +1387,6 @@
<ClInclude Include="Emu\Cell\PPUModule.h">
<Filter>Emu\Cell</Filter>
</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">
<Filter>Header Files</Filter>
</ClInclude>
@ -1606,9 +1405,6 @@
<ClInclude Include="Emu\Memory\wait_engine.h">
<Filter>Emu\Memory</Filter>
</ClInclude>
<ClInclude Include="Emu\Cell\lv2\IPC.h">
<Filter>Emu\Cell\lv2</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\StrUtil.h">
<Filter>Utilities</Filter>
</ClInclude>
@ -1618,5 +1414,215 @@
<ClInclude Include="..\Utilities\BitSet.h">
<Filter>Utilities</Filter>
</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>
</Project>

View File

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