mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-08-08 09:09:46 +00:00
update
This commit is contained in:
parent
f33b4a2932
commit
650947aada
18 changed files with 228 additions and 90 deletions
|
@ -566,9 +566,41 @@ void fmt_class_string<std::source_location>::format(std::string& out, u64 arg)
|
||||||
fmt::append(out, "\n(in file %s", loc.file_name());
|
fmt::append(out, "\n(in file %s", loc.file_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto func = loc.function_name(); func && func[0])
|
if (std::string_view full_func{loc.function_name() ? loc.function_name() : ""}; !full_func.empty())
|
||||||
{
|
{
|
||||||
fmt::append(out, ", in function %s)", func);
|
// Remove useless disambiguators
|
||||||
|
std::string func = fmt::replace_all(std::string(full_func), {
|
||||||
|
{"struct ", ""},
|
||||||
|
{"class ", ""},
|
||||||
|
{"enum ", ""},
|
||||||
|
{"typename ", ""},
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
{"__cdecl ", ""},
|
||||||
|
#endif
|
||||||
|
{"unsigned long long", "ullong"},
|
||||||
|
//{"unsigned long", "ulong"}, // ullong
|
||||||
|
{"unsigned int", "uint"},
|
||||||
|
{"unsigned short", "ushort"},
|
||||||
|
{"unsigned char", "uchar"}});
|
||||||
|
|
||||||
|
// Remove function argument signature for long names
|
||||||
|
for (usz index = func.find_first_of('('); index != umax && func.size() >= 100u; index = func.find_first_of('(', index))
|
||||||
|
{
|
||||||
|
// Operator() function
|
||||||
|
if (func.compare(0, 3, "()("sv) == 0 || func.compare(0, 3, "() "sv))
|
||||||
|
{
|
||||||
|
if (usz not_space = func.find_first_not_of(' ', index + 2); not_space != umax && func[not_space] == '(')
|
||||||
|
{
|
||||||
|
index += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func = func.substr(0, index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::append(out, ", in function '%s')", func);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -2555,13 +2555,13 @@ std::string thread_ctrl::get_name_cached()
|
||||||
return *name_cache;
|
return *name_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_base::thread_base(native_entry entry, std::string name)
|
thread_base::thread_base(native_entry entry, std::string name) noexcept
|
||||||
: entry_point(entry)
|
: entry_point(entry)
|
||||||
, m_tname(make_single_value(std::move(name)))
|
, m_tname(make_single_value(std::move(name)))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_base::~thread_base()
|
thread_base::~thread_base() noexcept
|
||||||
{
|
{
|
||||||
// Cleanup abandoned tasks: initialize default results and signal
|
// Cleanup abandoned tasks: initialize default results and signal
|
||||||
this->exec();
|
this->exec();
|
||||||
|
@ -2602,7 +2602,7 @@ bool thread_base::join(bool dtor) const
|
||||||
|
|
||||||
if (i >= 16 && !(i & (i - 1)) && timeout != atomic_wait_timeout::inf)
|
if (i >= 16 && !(i & (i - 1)) && timeout != atomic_wait_timeout::inf)
|
||||||
{
|
{
|
||||||
sig_log.error(u8"Thread [%s] is too sleepy. Waiting for it %.3fus already!", *m_tname.load(), (utils::get_tsc() - stamp0) / (utils::get_tsc_freq() / 1000000.));
|
sig_log.error("Thread [%s] is too sleepy. Waiting for it %.3fus already!", *m_tname.load(), (utils::get_tsc() - stamp0) / (utils::get_tsc_freq() / 1000000.));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,9 +172,9 @@ private:
|
||||||
friend class named_thread;
|
friend class named_thread;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
thread_base(native_entry, std::string name);
|
thread_base(native_entry, std::string name) noexcept;
|
||||||
|
|
||||||
~thread_base();
|
~thread_base() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Get CPU cycles since last time this function was called. First call returns 0.
|
// Get CPU cycles since last time this function was called. First call returns 0.
|
||||||
|
@ -351,7 +351,7 @@ public:
|
||||||
// Sets the native thread priority and returns it to zero at destructor
|
// Sets the native thread priority and returns it to zero at destructor
|
||||||
struct scoped_priority
|
struct scoped_priority
|
||||||
{
|
{
|
||||||
explicit scoped_priority(int prio)
|
explicit scoped_priority(int prio) noexcept
|
||||||
{
|
{
|
||||||
set_native_priority(prio);
|
set_native_priority(prio);
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ public:
|
||||||
|
|
||||||
scoped_priority& operator=(const scoped_priority&) = delete;
|
scoped_priority& operator=(const scoped_priority&) = delete;
|
||||||
|
|
||||||
~scoped_priority()
|
~scoped_priority() noexcept
|
||||||
{
|
{
|
||||||
set_native_priority(0);
|
set_native_priority(0);
|
||||||
}
|
}
|
||||||
|
@ -388,7 +388,7 @@ class thread_future_t : public thread_future, result_storage<Ctx, std::condition
|
||||||
using future = thread_future_t;
|
using future = thread_future_t;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
thread_future_t(Ctx&& func, Args&&... args)
|
thread_future_t(Ctx&& func, Args&&... args) noexcept
|
||||||
: m_args(std::forward<Args>(args)...)
|
: m_args(std::forward<Args>(args)...)
|
||||||
, m_func(std::forward<Ctx>(func))
|
, m_func(std::forward<Ctx>(func))
|
||||||
{
|
{
|
||||||
|
@ -417,7 +417,7 @@ public:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
~thread_future_t()
|
~thread_future_t() noexcept
|
||||||
{
|
{
|
||||||
if constexpr (!future::empty && !Discard)
|
if constexpr (!future::empty && !Discard)
|
||||||
{
|
{
|
||||||
|
@ -570,7 +570,7 @@ public:
|
||||||
named_thread& operator=(const named_thread&) = delete;
|
named_thread& operator=(const named_thread&) = delete;
|
||||||
|
|
||||||
// Wait for the completion and access result (if not void)
|
// Wait for the completion and access result (if not void)
|
||||||
[[nodiscard]] decltype(auto) operator()()
|
[[nodiscard]] decltype(auto) operator()() noexcept
|
||||||
{
|
{
|
||||||
thread::join();
|
thread::join();
|
||||||
|
|
||||||
|
@ -581,7 +581,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the completion and access result (if not void)
|
// Wait for the completion and access result (if not void)
|
||||||
[[nodiscard]] decltype(auto) operator()() const
|
[[nodiscard]] decltype(auto) operator()() const noexcept
|
||||||
{
|
{
|
||||||
thread::join();
|
thread::join();
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ public:
|
||||||
|
|
||||||
// Send command to the thread to invoke directly (references should be passed via std::ref())
|
// Send command to the thread to invoke directly (references should be passed via std::ref())
|
||||||
template <bool Discard = true, typename Arg, typename... Args>
|
template <bool Discard = true, typename Arg, typename... Args>
|
||||||
auto operator()(Arg&& arg, Args&&... args)
|
auto operator()(Arg&& arg, Args&&... args) noexcept
|
||||||
{
|
{
|
||||||
// Overloaded operator() of the Context.
|
// Overloaded operator() of the Context.
|
||||||
constexpr bool v1 = std::is_invocable_v<Context, Arg&&, Args&&...>;
|
constexpr bool v1 = std::is_invocable_v<Context, Arg&&, Args&&...>;
|
||||||
|
@ -667,12 +667,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access thread state
|
// Access thread state
|
||||||
operator thread_state() const
|
operator thread_state() const noexcept
|
||||||
{
|
{
|
||||||
return static_cast<thread_state>(thread::m_sync.load() & 3);
|
return static_cast<thread_state>(thread::m_sync.load() & 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
named_thread& operator=(thread_state s)
|
named_thread& operator=(thread_state s) noexcept
|
||||||
{
|
{
|
||||||
if (s == thread_state::created)
|
if (s == thread_state::created)
|
||||||
{
|
{
|
||||||
|
@ -693,7 +693,7 @@ public:
|
||||||
|
|
||||||
if constexpr (std::is_assignable_v<Context&, thread_state>)
|
if constexpr (std::is_assignable_v<Context&, thread_state>)
|
||||||
{
|
{
|
||||||
static_cast<Context&>(*this) = s;
|
static_cast<Context&>(*this) = thread_state::aborting;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify_sync)
|
if (notify_sync)
|
||||||
|
@ -706,13 +706,18 @@ public:
|
||||||
{
|
{
|
||||||
// This participates in emulation stopping, use destruction-alike semantics
|
// This participates in emulation stopping, use destruction-alike semantics
|
||||||
thread::join(true);
|
thread::join(true);
|
||||||
|
|
||||||
|
if constexpr (std::is_assignable_v<Context&, thread_state>)
|
||||||
|
{
|
||||||
|
static_cast<Context&>(*this) = thread_state::finished;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context type doesn't need virtual destructor
|
// Context type doesn't need virtual destructor
|
||||||
~named_thread()
|
~named_thread() noexcept
|
||||||
{
|
{
|
||||||
// Assign aborting state forcefully and join thread
|
// Assign aborting state forcefully and join thread
|
||||||
operator=(thread_state::finished);
|
operator=(thread_state::finished);
|
||||||
|
|
|
@ -109,10 +109,29 @@ void lv2_config::add_service_event(shared_ptr<lv2_config_service_event> event)
|
||||||
|
|
||||||
void lv2_config::remove_service_event(u32 id)
|
void lv2_config::remove_service_event(u32 id)
|
||||||
{
|
{
|
||||||
|
shared_ptr<lv2_config_service_event> ptr;
|
||||||
|
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
events.erase(id);
|
|
||||||
|
if (auto it = events.find(id); it != events.end())
|
||||||
|
{
|
||||||
|
ptr = std::move(it->second);
|
||||||
|
events.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept
|
||||||
|
{
|
||||||
|
if (s == thread_state::finished)
|
||||||
|
{
|
||||||
|
if (auto global = g_fxo->try_get<lv2_config>())
|
||||||
|
{
|
||||||
|
global->remove_service_event(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
// LV2 Config Service Listener
|
// LV2 Config Service Listener
|
||||||
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
|
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
|
||||||
|
|
|
@ -390,13 +390,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
~lv2_config_service_event() noexcept
|
lv2_config_service_event& operator=(thread_state s) noexcept;
|
||||||
{
|
|
||||||
if (auto global = g_fxo->try_get<lv2_config>())
|
~lv2_config_service_event() noexcept = default;
|
||||||
{
|
|
||||||
global->remove_service_event(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify queue that this event exists
|
// Notify queue that this event exists
|
||||||
bool notify() const;
|
bool notify() const;
|
||||||
|
|
|
@ -175,3 +175,14 @@ void lv2_socket::queue_wake(ppu_thread* ppu)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lv2_socket& lv2_socket::operator=(thread_state s) noexcept
|
||||||
|
{
|
||||||
|
if (s == thread_state::finished)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ using socket_type = uptr;
|
||||||
using socket_type = int;
|
using socket_type = int;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum class thread_state : u32;
|
||||||
|
|
||||||
class lv2_socket
|
class lv2_socket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -62,7 +64,8 @@ public:
|
||||||
lv2_socket(utils::serial&, lv2_socket_type type);
|
lv2_socket(utils::serial&, lv2_socket_type type);
|
||||||
static std::function<void(void*)> load(utils::serial& ar);
|
static std::function<void(void*)> load(utils::serial& ar);
|
||||||
void save(utils::serial&, bool save_only_this_class = false);
|
void save(utils::serial&, bool save_only_this_class = false);
|
||||||
virtual ~lv2_socket() = default;
|
~lv2_socket() noexcept = default;
|
||||||
|
lv2_socket& operator=(thread_state s) noexcept;
|
||||||
|
|
||||||
std::unique_lock<shared_mutex> lock();
|
std::unique_lock<shared_mutex> lock();
|
||||||
|
|
||||||
|
|
|
@ -57,19 +57,6 @@ void lv2_socket_native::save(utils::serial& ar)
|
||||||
ar(is_socket_connected());
|
ar(is_socket_connected());
|
||||||
}
|
}
|
||||||
|
|
||||||
lv2_socket_native::~lv2_socket_native()
|
|
||||||
{
|
|
||||||
std::lock_guard lock(mutex);
|
|
||||||
if (socket)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
::closesocket(socket);
|
|
||||||
#else
|
|
||||||
::close(socket);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 lv2_socket_native::create_socket()
|
s32 lv2_socket_native::create_socket()
|
||||||
{
|
{
|
||||||
ensure(family == SYS_NET_AF_INET);
|
ensure(family == SYS_NET_AF_INET);
|
||||||
|
@ -1114,10 +1101,12 @@ void lv2_socket_native::close()
|
||||||
socket = {};
|
socket = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& dnshook = g_fxo->get<np::dnshook>();
|
if (auto dnshook = g_fxo->try_get<np::dnshook>())
|
||||||
dnshook.remove_dns_spy(lv2_id);
|
{
|
||||||
|
dnshook->remove_dns_spy(lv2_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (bound_port)
|
if (bound_port && g_fxo->is_init<named_thread<np::np_handler>>())
|
||||||
{
|
{
|
||||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||||
nph.upnp_remove_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP");
|
nph.upnp_remove_port_mapping(bound_port, type == SYS_NET_SOCK_STREAM ? "TCP" : "UDP");
|
||||||
|
|
|
@ -35,7 +35,6 @@ public:
|
||||||
lv2_socket_native(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol);
|
lv2_socket_native(lv2_socket_family family, lv2_socket_type type, lv2_ip_protocol protocol);
|
||||||
lv2_socket_native(utils::serial& ar, lv2_socket_type type);
|
lv2_socket_native(utils::serial& ar, lv2_socket_type type);
|
||||||
void save(utils::serial& ar);
|
void save(utils::serial& ar);
|
||||||
~lv2_socket_native();
|
|
||||||
s32 create_socket();
|
s32 create_socket();
|
||||||
|
|
||||||
std::tuple<bool, s32, shared_ptr<lv2_socket>, sys_net_sockaddr> accept(bool is_lock = true) override;
|
std::tuple<bool, s32, shared_ptr<lv2_socket>, sys_net_sockaddr> accept(bool is_lock = true) override;
|
||||||
|
|
|
@ -330,8 +330,9 @@ void lv2_socket_p2p::close()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& nc = g_fxo->get<p2p_context>();
|
if (g_fxo->is_init<p2p_context>())
|
||||||
{
|
{
|
||||||
|
auto& nc = g_fxo->get<p2p_context>();
|
||||||
std::lock_guard lock(nc.list_p2p_ports_mutex);
|
std::lock_guard lock(nc.list_p2p_ports_mutex);
|
||||||
|
|
||||||
if (!nc.list_p2p_ports.contains(port))
|
if (!nc.list_p2p_ports.contains(port))
|
||||||
|
|
|
@ -944,8 +944,9 @@ void lv2_socket_p2ps::close()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& nc = g_fxo->get<p2p_context>();
|
if (g_fxo->is_init<p2p_context>())
|
||||||
{
|
{
|
||||||
|
auto& nc = g_fxo->get<p2p_context>();
|
||||||
std::lock_guard lock(nc.list_p2p_ports_mutex);
|
std::lock_guard lock(nc.list_p2p_ports_mutex);
|
||||||
auto& p2p_port = ::at32(nc.list_p2p_ports, port);
|
auto& p2p_port = ::at32(nc.list_p2p_ports, port);
|
||||||
{
|
{
|
||||||
|
@ -973,8 +974,10 @@ void lv2_socket_p2ps::close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& tcpm = g_fxo->get<named_thread<tcp_timeout_monitor>>();
|
if (const auto tcpm = g_fxo->try_get<named_thread<tcp_timeout_monitor>>())
|
||||||
tcpm.clear_all_messages(lv2_id);
|
{
|
||||||
|
tcpm->clear_all_messages(lv2_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 lv2_socket_p2ps::shutdown([[maybe_unused]] s32 how)
|
s32 lv2_socket_p2ps::shutdown([[maybe_unused]] s32 how)
|
||||||
|
|
|
@ -434,9 +434,12 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector<std::string>& argv, std::vector<
|
||||||
using namespace id_manager;
|
using namespace id_manager;
|
||||||
|
|
||||||
shared_ptr<utils::serial> idm_capture = make_shared<utils::serial>();
|
shared_ptr<utils::serial> idm_capture = make_shared<utils::serial>();
|
||||||
|
|
||||||
|
if (!is_real_reboot)
|
||||||
{
|
{
|
||||||
reader_lock rlock{g_mutex};
|
reader_lock rlock{id_manager::g_mutex};
|
||||||
g_fxo->get<id_map<lv2_memory_container>>().save(*idm_capture);
|
g_fxo->get<id_map<lv2_memory_container>>().save(*idm_capture);
|
||||||
|
stx::serial_breathe_and_tag(*idm_capture, "id_map<lv2_memory_container>", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
idm_capture->set_reading_state();
|
idm_capture->set_reading_state();
|
||||||
|
|
|
@ -587,7 +587,7 @@ bool gdb_thread::cmd_thread_info(gdb_cmd&)
|
||||||
|
|
||||||
bool gdb_thread::cmd_current_thread(gdb_cmd&)
|
bool gdb_thread::cmd_current_thread(gdb_cmd&)
|
||||||
{
|
{
|
||||||
return send_cmd_ack(selected_thread && selected_thread->state.none_of(cpu_flag::exit) ? "" : ("QC" + u64_to_padded_hex(selected_thread->id)));
|
return send_cmd_ack(selected_thread && selected_thread->state.none_of(cpu_flag::exit) ? ("QC" + u64_to_padded_hex(selected_thread->id)) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gdb_thread::cmd_read_register(gdb_cmd& cmd)
|
bool gdb_thread::cmd_read_register(gdb_cmd& cmd)
|
||||||
|
@ -733,7 +733,7 @@ bool gdb_thread::cmd_read_all_registers(gdb_cmd&)
|
||||||
return send_cmd_ack(result);
|
return send_cmd_ack(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDB.warning("Unimplemented thread type %d.", selected_thread ->id_type());
|
GDB.warning("Unimplemented thread type %d.", selected_thread->id_type());
|
||||||
return send_cmd_ack("");
|
return send_cmd_ack("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -801,6 +801,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_assignable_v<Get&, thread_state>)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
constexpr thread_state finished{3};
|
||||||
|
*static_cast<Get*>(ptr.get()) = finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,6 +833,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_assignable_v<Get&, thread_state>)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
{
|
||||||
|
constexpr thread_state finished{3};
|
||||||
|
*static_cast<Get*>(ptr.get()) = finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2718,8 +2718,15 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
|
||||||
cpu.state += cpu_flag::dbg_global_pause;
|
cpu.state += cpu_flag::dbg_global_pause;
|
||||||
};
|
};
|
||||||
|
|
||||||
idm::select<named_thread<ppu_thread>>(on_select);
|
if (g_fxo->is_init<id_manager::id_map<named_thread<ppu_thread>>>())
|
||||||
idm::select<named_thread<spu_thread>>(on_select);
|
{
|
||||||
|
idm::select<named_thread<ppu_thread>>(on_select);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_fxo->is_init<id_manager::id_map<named_thread<spu_thread>>>())
|
||||||
|
{
|
||||||
|
idm::select<named_thread<spu_thread>>(on_select);
|
||||||
|
}
|
||||||
|
|
||||||
if (auto rsx = g_fxo->try_get<rsx::thread>())
|
if (auto rsx = g_fxo->try_get<rsx::thread>())
|
||||||
{
|
{
|
||||||
|
@ -2760,6 +2767,7 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
|
||||||
std::unique_ptr<named_thread<decltype(refresh_l)>> m_thread;
|
std::unique_ptr<named_thread<decltype(refresh_l)>> m_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
g_fxo->need<thread_t>();
|
||||||
g_fxo->get<thread_t>().m_thread.reset();
|
g_fxo->get<thread_t>().m_thread.reset();
|
||||||
g_fxo->get<thread_t>().m_thread = std::make_unique<named_thread<decltype(refresh_l)>>("Pause Message Thread"sv, std::move(refresh_l));
|
g_fxo->get<thread_t>().m_thread = std::make_unique<named_thread<decltype(refresh_l)>>("Pause Message Thread"sv, std::move(refresh_l));
|
||||||
});
|
});
|
||||||
|
|
|
@ -372,6 +372,7 @@ namespace stx
|
||||||
{
|
{
|
||||||
// Reset, probably a new utils::serial object
|
// Reset, probably a new utils::serial object
|
||||||
s_tls_call_count = 1;
|
s_tls_call_count = 1;
|
||||||
|
s_tls_object_name = "none"sv;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_tls_current_pos = ar.pos;
|
s_tls_current_pos = ar.pos;
|
||||||
|
|
|
@ -1049,8 +1049,15 @@ void debugger_frame::UpdateUnitList()
|
||||||
|
|
||||||
if (emu_state != system_state::stopped)
|
if (emu_state != system_state::stopped)
|
||||||
{
|
{
|
||||||
idm::select<named_thread<ppu_thread>>(on_select, idm::unlocked);
|
if (g_fxo->is_init<id_manager::id_map<named_thread<ppu_thread>>>())
|
||||||
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
|
{
|
||||||
|
idm::select<named_thread<ppu_thread>>(on_select, idm::unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_fxo->is_init<id_manager::id_map<named_thread<spu_thread>>>())
|
||||||
|
{
|
||||||
|
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
if (const auto render = g_fxo->try_get<rsx::thread>(); render && render->ctrl)
|
if (const auto render = g_fxo->try_get<rsx::thread>(); render && render->ctrl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -154,6 +154,7 @@ namespace stx
|
||||||
if (m_ptr) [[likely]]
|
if (m_ptr) [[likely]]
|
||||||
{
|
{
|
||||||
const auto o = d();
|
const auto o = d();
|
||||||
|
ensure(o->refs == 1);
|
||||||
o->destroy.load()(o);
|
o->destroy.load()(o);
|
||||||
m_ptr = nullptr;
|
m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -437,11 +438,15 @@ namespace stx
|
||||||
// Set to null
|
// Set to null
|
||||||
void reset() noexcept
|
void reset() noexcept
|
||||||
{
|
{
|
||||||
const auto o = d();
|
if (m_ptr) [[unlikely]]
|
||||||
|
|
||||||
if (m_ptr && !--o->refs) [[unlikely]]
|
|
||||||
{
|
{
|
||||||
o->destroy(o);
|
const auto o = d();
|
||||||
|
|
||||||
|
if (!--o->refs)
|
||||||
|
{
|
||||||
|
o->destroy(o);
|
||||||
|
}
|
||||||
|
|
||||||
m_ptr = nullptr;
|
m_ptr = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,7 +576,7 @@ namespace stx
|
||||||
{
|
{
|
||||||
mutable atomic_t<uptr> m_val{0};
|
mutable atomic_t<uptr> m_val{0};
|
||||||
|
|
||||||
static shared_counter* d(uptr val)
|
static shared_counter* d(uptr val) noexcept
|
||||||
{
|
{
|
||||||
return std::launder(reinterpret_cast<shared_counter*>((val >> c_ref_size) - sizeof(shared_counter)));
|
return std::launder(reinterpret_cast<shared_counter*>((val >> c_ref_size) - sizeof(shared_counter)));
|
||||||
}
|
}
|
||||||
|
@ -581,9 +586,32 @@ namespace stx
|
||||||
return d(m_val);
|
return d(m_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uptr to_val(const volatile std::remove_extent_t<T>* ptr) noexcept
|
||||||
|
{
|
||||||
|
return (reinterpret_cast<uptr>(ptr) << c_ref_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::remove_extent_t<T>* ptr_to(uptr val) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<std::remove_extent_t<T>*>(val >> c_ref_size);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
friend class atomic_ptr;
|
friend class atomic_ptr;
|
||||||
|
|
||||||
|
// Helper struct to check if a type is an instance of a template
|
||||||
|
template <typename T1, template <typename> class Template>
|
||||||
|
struct is_instance_of : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T1, template <typename> class Template>
|
||||||
|
struct is_instance_of<Template<T1>, Template> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
static constexpr bool is_stx_pointer = false
|
||||||
|
|| is_instance_of<std::remove_cv_t<T1>, shared_ptr>::value
|
||||||
|
|| is_instance_of<std::remove_cv_t<T1>, single_ptr>::value
|
||||||
|
|| is_instance_of<std::remove_cv_t<T1>, atomic_ptr>::value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using element_type = std::remove_extent_t<T>;
|
using element_type = std::remove_extent_t<T>;
|
||||||
|
|
||||||
|
@ -592,11 +620,14 @@ namespace stx
|
||||||
constexpr atomic_ptr() noexcept = default;
|
constexpr atomic_ptr() noexcept = default;
|
||||||
|
|
||||||
// Optimized value construct
|
// Optimized value construct
|
||||||
template <typename... Args> requires (!(sizeof...(Args) == 1 && (std::is_same_v<std::remove_cvref_t<Args>, shared_type> || ...)) && std::is_constructible_v<T, Args...>)
|
template <typename... Args> requires (true
|
||||||
|
&& sizeof...(Args) != 0
|
||||||
|
&& !(sizeof...(Args) == 1 && (is_stx_pointer<Args> || ...))
|
||||||
|
&& std::is_constructible_v<element_type, Args&&...>)
|
||||||
explicit atomic_ptr(Args&&... args) noexcept
|
explicit atomic_ptr(Args&&... args) noexcept
|
||||||
{
|
{
|
||||||
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
||||||
m_val = reinterpret_cast<uptr>(std::exchange(r.m_ptr, nullptr)) << c_ref_size;
|
m_val.raw() = to_val(std::exchange(r.m_ptr, nullptr));
|
||||||
d()->refs.raw() += c_ref_mask;
|
d()->refs.raw() += c_ref_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -604,32 +635,38 @@ namespace stx
|
||||||
atomic_ptr(const shared_ptr<U>& r) noexcept
|
atomic_ptr(const shared_ptr<U>& r) noexcept
|
||||||
{
|
{
|
||||||
// Obtain a ref + as many refs as an atomic_ptr can additionally reference
|
// Obtain a ref + as many refs as an atomic_ptr can additionally reference
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
if (uptr rval = to_val(r.m_ptr))
|
||||||
if (m_val)
|
{
|
||||||
d()->refs += c_ref_mask + 1;
|
m_val.raw() = rval;
|
||||||
|
d(rval)->refs += c_ref_mask + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U> requires same_ptr_implicit_v<T, U>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr(shared_ptr<U>&& r) noexcept
|
atomic_ptr(shared_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
if (uptr rval = to_val(r.m_ptr))
|
||||||
r.m_ptr = nullptr;
|
{
|
||||||
|
m_val.raw() = rval;
|
||||||
|
d(rval)->refs += c_ref_mask;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_val)
|
r.m_ptr = nullptr;
|
||||||
d()->refs += c_ref_mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename U> requires same_ptr_implicit_v<T, U>
|
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||||
atomic_ptr(single_ptr<U>&& r) noexcept
|
atomic_ptr(single_ptr<U>&& r) noexcept
|
||||||
{
|
{
|
||||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
if (uptr rval = to_val(r.m_ptr))
|
||||||
r.m_ptr = nullptr;
|
{
|
||||||
|
m_val.raw() = rval;
|
||||||
|
d(rval)->refs += c_ref_mask;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_val)
|
r.m_ptr = nullptr;
|
||||||
d()->refs += c_ref_mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~atomic_ptr()
|
~atomic_ptr() noexcept
|
||||||
{
|
{
|
||||||
const uptr v = m_val.raw();
|
const uptr v = m_val.raw();
|
||||||
|
|
||||||
|
@ -645,13 +682,13 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized value assignment
|
// Optimized value assignment
|
||||||
atomic_ptr& operator=(std::remove_cv_t<T> value) noexcept
|
atomic_ptr& operator=(std::remove_cv_t<T> value) noexcept requires (!is_stx_pointer<T>)
|
||||||
{
|
{
|
||||||
shared_type r = make_single<T>(std::move(value));
|
shared_type r = make_single<T>(std::move(value));
|
||||||
r.d()->refs.raw() += c_ref_mask;
|
r.d()->refs.raw() += c_ref_mask;
|
||||||
|
|
||||||
atomic_ptr old;
|
atomic_ptr old;
|
||||||
old.m_val.raw() = m_val.exchange(reinterpret_cast<uptr>(std::exchange(r.m_ptr, nullptr)) << c_ref_size);
|
old.m_val.raw() = m_val.exchange(to_val(std::exchange(r.m_ptr, nullptr)));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,7 +741,7 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set referenced pointer
|
// Set referenced pointer
|
||||||
r.m_ptr = std::launder(reinterpret_cast<element_type*>(prev >> c_ref_size));
|
r.m_ptr = std::launder(ptr_to(prev));
|
||||||
r.d()->refs++;
|
r.d()->refs++;
|
||||||
|
|
||||||
// Dereference if still the same pointer
|
// Dereference if still the same pointer
|
||||||
|
@ -749,7 +786,7 @@ namespace stx
|
||||||
// Set fake unreferenced pointer
|
// Set fake unreferenced pointer
|
||||||
if (did_ref)
|
if (did_ref)
|
||||||
{
|
{
|
||||||
r.m_ptr = std::launder(reinterpret_cast<element_type*>(prev >> c_ref_size));
|
r.m_ptr = std::launder(ptr_to(prev));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result temp storage
|
// Result temp storage
|
||||||
|
@ -805,14 +842,17 @@ namespace stx
|
||||||
|
|
||||||
// Create an object from variadic args
|
// Create an object from variadic args
|
||||||
// If a type needs shared_type to be constructed, std::reference_wrapper can be used
|
// If a type needs shared_type to be constructed, std::reference_wrapper can be used
|
||||||
template <typename... Args> requires (!(sizeof...(Args) == 1 && (std::is_same_v<std::remove_cvref_t<Args>, shared_type> || ...)) && std::is_constructible_v<T, Args...>)
|
template <typename... Args> requires (true
|
||||||
|
&& sizeof...(Args) != 0
|
||||||
|
&& !(sizeof...(Args) == 1 && (is_stx_pointer<Args> || ...))
|
||||||
|
&& std::is_constructible_v<element_type, Args&&...>)
|
||||||
void store(Args&&... args) noexcept
|
void store(Args&&... args) noexcept
|
||||||
{
|
{
|
||||||
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
||||||
r.d()->refs.raw() += c_ref_mask;
|
r.d()->refs.raw() += c_ref_mask;
|
||||||
|
|
||||||
atomic_ptr old;
|
atomic_ptr old;
|
||||||
old.m_val.raw() = m_val.exchange(reinterpret_cast<uptr>(std::exchange(r.m_ptr, nullptr)) << c_ref_size);
|
old.m_val.raw() = m_val.exchange(to_val(std::exchange(r.m_ptr, nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void store(shared_type value) noexcept
|
void store(shared_type value) noexcept
|
||||||
|
@ -824,20 +864,23 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_ptr old;
|
atomic_ptr old;
|
||||||
old.m_val.raw() = m_val.exchange(reinterpret_cast<uptr>(std::exchange(value.m_ptr, nullptr)) << c_ref_size);
|
old.m_val.raw() = m_val.exchange(to_val(std::exchange(value.m_ptr, nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args> requires (!(sizeof...(Args) == 1 && (std::is_same_v<std::remove_cvref_t<Args>, shared_type> || ...)) && std::is_constructible_v<T, Args...>)
|
template <typename... Args> requires (true
|
||||||
|
&& sizeof...(Args) != 0
|
||||||
|
&& !(sizeof...(Args) == 1 && (is_stx_pointer<Args> || ...))
|
||||||
|
&& std::is_constructible_v<element_type, Args&...>)
|
||||||
[[nodiscard]] shared_type exchange(Args&&... args) noexcept
|
[[nodiscard]] shared_type exchange(Args&&... args) noexcept
|
||||||
{
|
{
|
||||||
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
||||||
r.d()->refs.raw() += c_ref_mask;
|
r.d()->refs.raw() += c_ref_mask;
|
||||||
|
|
||||||
atomic_ptr old;
|
atomic_ptr old;
|
||||||
old.m_val.raw() += m_val.exchange(reinterpret_cast<uptr>(r.m_ptr) << c_ref_size);
|
old.m_val.raw() = m_val.exchange(to_val(r.m_ptr));
|
||||||
old.m_val.raw() += 1;
|
old.m_val.raw() += 1;
|
||||||
|
|
||||||
r.m_ptr = std::launder(reinterpret_cast<element_type*>(old.m_val >> c_ref_size));
|
r.m_ptr = std::launder(ptr_to(old.m_val));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,10 +893,10 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_ptr old;
|
atomic_ptr old;
|
||||||
old.m_val.raw() += m_val.exchange(reinterpret_cast<uptr>(value.m_ptr) << c_ref_size);
|
old.m_val.raw() = m_val.exchange(to_val(value.m_ptr));
|
||||||
old.m_val.raw() += 1;
|
old.m_val.raw() += 1;
|
||||||
|
|
||||||
value.m_ptr = std::launder(reinterpret_cast<element_type*>(old.m_val >> c_ref_size));
|
value.m_ptr = std::launder(ptr_to(old.m_val));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,10 +941,10 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_ptr old_exch;
|
atomic_ptr old_exch;
|
||||||
old_exch.m_val.raw() = reinterpret_cast<uptr>(std::exchange(exch.m_ptr, nullptr)) << c_ref_size;
|
old_exch.m_val.raw() = to_val(std::exchange(exch.m_ptr, nullptr));
|
||||||
|
|
||||||
// Set to reset old cmp_and_old value
|
// Set to reset old cmp_and_old value
|
||||||
old.m_val.raw() = (reinterpret_cast<uptr>(cmp_and_old.m_ptr) << c_ref_size) | c_ref_mask;
|
old.m_val.raw() = to_val(cmp_and_old.m_ptr) | c_ref_mask;
|
||||||
|
|
||||||
if (!_val)
|
if (!_val)
|
||||||
{
|
{
|
||||||
|
@ -909,7 +952,7 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set referenced pointer
|
// Set referenced pointer
|
||||||
cmp_and_old.m_ptr = std::launder(reinterpret_cast<element_type*>(_val >> c_ref_size));
|
cmp_and_old.m_ptr = std::launder(ptr_to(_val));
|
||||||
cmp_and_old.d()->refs++;
|
cmp_and_old.d()->refs++;
|
||||||
|
|
||||||
// Dereference if still the same pointer
|
// Dereference if still the same pointer
|
||||||
|
@ -977,7 +1020,7 @@ namespace stx
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failure (return references)
|
// Failure (return references)
|
||||||
old.m_val.raw() = reinterpret_cast<uptr>(std::exchange(exch.m_ptr, nullptr)) << c_ref_size;
|
old.m_val.raw() = to_val(std::exchange(exch.m_ptr, nullptr));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue