diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 82a18f4776..2e890a4ec3 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2040,6 +2040,12 @@ DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined void thread_base::start() { + m_sync.atomic_op([&](u32& v) + { + v &= ~static_cast(thread_state::mask); + v |= static_cast(thread_state::created); + }); + #ifdef _WIN32 m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr); ensure(m_thread); diff --git a/Utilities/Thread.h b/Utilities/Thread.h index e8fba73380..576eac264d 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -5,6 +5,7 @@ #include "util/shared_ptr.hpp" #include +#include #include "mutex.h" #include "lockless.h" @@ -83,9 +84,9 @@ struct result_storage }; template -concept NamedThreadName = requires (const T& t) +concept NamedThreadName = requires (const T&) { - std::string(t.thread_name); + std::string(T::thread_name); }; // Base class for task queue (linked list) @@ -446,6 +447,11 @@ public: } }; +namespace stx +{ + struct launch_retainer; +} + // Derived from the callable object Context, possibly a lambda template class named_thread final : public Context, result_storage, thread_base @@ -512,17 +518,27 @@ class named_thread final : public Context, result_storage, thread_base public: // Forwarding constructor with default name (also potentially the default constructor) - template requires (std::is_constructible_v) && (NamedThreadName) - named_thread(Args&&... args) + template requires (std::is_constructible_v) && (!(std::is_same_v, stx::launch_retainer> || ...)) && (NamedThreadName) + named_thread(Args&&... args) noexcept : Context(std::forward(args)...) , thread(trampoline, std::string(Context::thread_name)) { thread::start(); } + // Forwarding constructor with default name, does not automatically run the thread + template requires (std::is_constructible_v) && (NamedThreadName) + named_thread(const stx::launch_retainer&, Args&&... args) noexcept + : Context(std::forward(args)...) + , thread(trampoline, std::string(Context::thread_name)) + { + // Create a stand-by thread context + m_sync |= static_cast(thread_state::finished); + } + // Normal forwarding constructor - template requires (std::is_constructible_v) - named_thread(std::string name, Args&&... args) + template requires (std::is_constructible_v) && (!NamedThreadName) + named_thread(std::string name, Args&&... args) noexcept : Context(std::forward(args)...) , thread(trampoline, std::move(name)) { @@ -530,7 +546,7 @@ public: } // Lambda constructor, also the implicit deduction guide candidate - named_thread(std::string_view name, Context&& f) + named_thread(std::string_view name, Context&& f) noexcept requires (!NamedThreadName) : Context(std::forward(f)) , thread(trampoline, std::string(name)) { @@ -644,12 +660,20 @@ public: return static_cast(thread::m_sync.load() & 3); } - // Try to abort by assigning thread_state::aborting/finished - // Join thread by thread_state::finished named_thread& operator=(thread_state s) { + if (s == thread_state::created) + { + // Run thread + ensure(operator thread_state() == thread_state::finished); + thread::start(); + return *this; + } + bool notify_sync = false; + // Try to abort by assigning thread_state::aborting/finished + // Join thread by thread_state::finished if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u32& v) { return !(v & 3) && (v |= 1); }).second) { notify_sync = true; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp index ea3722faa4..e08ce43308 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.cpp @@ -179,11 +179,6 @@ private: std::unordered_map rtts; // (sock_id, rtt) }; -void initialize_tcp_timeout_monitor() -{ - g_fxo->need>(); -} - u16 u2s_tcp_checksum(const le_t* buffer, usz size) { u32 cksum = 0; diff --git a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h index ec3c3b378d..e06b16aa97 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h +++ b/rpcs3/Emu/Cell/lv2/sys_net/lv2_socket_p2ps.h @@ -50,7 +50,6 @@ enum p2ps_tcp_flags : u8 CWR = (1 << 7), }; -void initialize_tcp_timeout_monitor(); u16 u2s_tcp_checksum(const le_t* buffer, usz size); std::vector generate_u2s_packet(const p2ps_encapsulated_tcp& header, const u8* data, const u32 datasize); diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp index 0a5e010739..15b27b49b8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp @@ -77,16 +77,14 @@ std::vector get_sign_msgs() return msgs; } -void need_network() +namespace np { - g_fxo->need(); - initialize_tcp_timeout_monitor(); + void init_np_handler_dependencies(); } network_thread::network_thread() { - // Ensures IDM for lv2_socket is always valid when the thread is running - g_fxo->init>(); + np::init_np_handler_dependencies(); } void network_thread::bind_sce_np_port() diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index 601beba073..d0721cec4e 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -339,6 +339,28 @@ namespace np return; } + extern void init_np_handler_dependencies() + { + if (auto handler = g_fxo->try_get>()) + { + handler->init_np_handler_dependencies(); + } + } + + void np_handler::init_np_handler_dependencies() + { + if (is_psn_active && g_cfg.net.psn_status == np_psn_status::psn_rpcn && g_fxo->is_init() && !m_inited_np_handler_dependencies) + { + m_inited_np_handler_dependencies = true; + + auto& nc = g_fxo->get(); + nc.bind_sce_np_port(); + + std::lock_guard lock(mutex_rpcn); + rpcn = rpcn::rpcn_client::get_instance(); + } + } + np_handler::np_handler() { g_fxo->need>(); @@ -388,16 +410,6 @@ namespace np if (g_cfg.net.upnp_enabled) upnp.upnp_enable(); } - - if (is_psn_active && g_cfg.net.psn_status == np_psn_status::psn_rpcn) - { - g_fxo->need(); - auto& nc = g_fxo->get(); - nc.bind_sce_np_port(); - - std::lock_guard lock(mutex_rpcn); - rpcn = rpcn::rpcn_client::get_instance(); - } } np_handler::np_handler(utils::serial& ar) diff --git a/rpcs3/Emu/NP/np_handler.h b/rpcs3/Emu/NP/np_handler.h index 043f26bd89..e250b1de27 100644 --- a/rpcs3/Emu/NP/np_handler.h +++ b/rpcs3/Emu/NP/np_handler.h @@ -76,6 +76,7 @@ namespace np np_handler(utils::serial& ar); void save(utils::serial& ar); + void init_np_handler_dependencies(); const std::array& get_ether_addr() const; const std::string& get_hostname() const; u32 get_local_ip_addr() const; @@ -305,6 +306,8 @@ namespace np shared_mutex mutex_queue_basic_events; std::queue queue_basic_events; + bool m_inited_np_handler_dependencies = false; + private: bool is_connected = false; bool is_psn_active = false; diff --git a/rpcs3/Emu/NP/signaling_handler.cpp b/rpcs3/Emu/NP/signaling_handler.cpp index 922ca024c9..f161d24137 100644 --- a/rpcs3/Emu/NP/signaling_handler.cpp +++ b/rpcs3/Emu/NP/signaling_handler.cpp @@ -17,7 +17,6 @@ LOG_CHANNEL(sign_log, "Signaling"); -void need_network(); template <> void fmt_class_string::format(std::string& out, u64 arg) @@ -41,7 +40,6 @@ void fmt_class_string::format(std::string& out, u64 arg) signaling_handler::signaling_handler() { - need_network(); } ///////////////////////////// diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index f6a3fa5d21..de006ee3e6 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -2875,9 +2875,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s for (const auto& [type, data] : *g_fxo) { - if (type.stop) + if (type.thread_op) { - type.stop(data, thread_state::aborting); + type.thread_op(data, thread_state::aborting); } } @@ -2928,9 +2928,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s // Join threads for (const auto& [type, data] : *g_fxo) { - if (type.stop) + if (type.thread_op) { - type.stop(data, thread_state::finished); + type.thread_op(data, thread_state::finished); } } diff --git a/rpcs3/util/fixed_typemap.hpp b/rpcs3/util/fixed_typemap.hpp index 5442c4175f..0679de49c2 100644 --- a/rpcs3/util/fixed_typemap.hpp +++ b/rpcs3/util/fixed_typemap.hpp @@ -15,6 +15,8 @@ extern thread_local std::string_view g_tls_serialize_name; namespace stx { + struct launch_retainer{}; + // Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear(). template class alignas(Align) manual_typemap @@ -62,7 +64,7 @@ namespace stx struct typeinfo { bool(*create)(uchar* ptr, manual_typemap&, utils::serial*, std::string_view) noexcept = nullptr; - void(*stop)(void* ptr, thread_state) noexcept = nullptr; + void(*thread_op)(void* ptr, thread_state) noexcept = nullptr; void(*save)(void* ptr, utils::serial&) noexcept = nullptr; void(*destroy)(void* ptr) noexcept = nullptr; std::string_view name; @@ -72,13 +74,19 @@ namespace stx { if (ar) { - if constexpr (std::is_constructible_v>) + if constexpr (std::is_constructible_v, exact_t>) { g_tls_serialize_name = name; new (ptr) T(_this, exact_t(*ar)); return true; } + if constexpr (std::is_constructible_v, exact_t>) + { + new (ptr) T(exact_t(launch_retainer{}), exact_t(*ar)); + return true; + } + if constexpr (std::is_constructible_v>) { g_tls_serialize_name = name; @@ -88,12 +96,18 @@ namespace stx } // Allow passing reference to "this" - if constexpr (std::is_constructible_v) + if constexpr (std::is_constructible_v>) { new (ptr) T(_this); return true; } + if constexpr (std::is_constructible_v>) + { + new (ptr) T(exact_t(launch_retainer{})); + return true; + } + // Call default constructor only if available if constexpr (std::is_default_constructible_v) { @@ -111,7 +125,7 @@ namespace stx } template - static void call_stop(void* ptr, thread_state state) noexcept + static void call_thread_op(void* ptr, thread_state state) noexcept { // Abort and/or join (expected thread_state::aborting or thread_state::finished) *std::launder(static_cast(ptr)) = state; @@ -134,7 +148,7 @@ namespace stx if constexpr (std::is_assignable_v) { - r.stop = &call_stop; + r.thread_op = &call_thread_op; } if constexpr (!!(requires (T& a) { a.save(std::declval>()); })) @@ -233,6 +247,8 @@ namespace stx return a.first < b.first; }); + const auto info_before = m_info; + for (pos = 0; pos < stx::typelist().count(); pos++) { const auto& type = *order[pos].second; @@ -260,6 +276,15 @@ namespace stx } } + // Launch threads + for (auto it = m_info; it != info_before; it--) + { + if (auto op = (*std::prev(it))->thread_op) + { + op(*std::prev(m_order, m_info - it + 1), thread_state{}); + } + } + g_tls_serialize_name = {}; } diff --git a/rpcs3/util/types.hpp b/rpcs3/util/types.hpp index 23e617e2d9..6a155a8991 100644 --- a/rpcs3/util/types.hpp +++ b/rpcs3/util/types.hpp @@ -1174,13 +1174,21 @@ namespace stx template struct exact_t { + static_assert(std::is_reference_v || std::is_convertible_v); + T obj; - exact_t(T&& _obj) : obj(std::forward(_obj)) {} + explicit exact_t(T&& _obj) : obj(std::forward(_obj)) {} + exact_t& operator=(const exact_t&) = delete; - // TODO: More conversions template requires (std::is_same_v) - operator U&() const { return obj; }; + operator U&() const noexcept { return obj; }; + + template requires (std::is_same_v) + operator const U&() const noexcept { return obj; }; + + template requires (std::is_same_v && std::is_copy_constructible_v) + operator U() const noexcept { return obj; }; }; }