Postpone thread launching on g_fxo->init

This commit is contained in:
Eladash 2023-12-14 22:20:21 +02:00 committed by Elad Ashkenazi
parent a4bcba8971
commit 0c410f8a14
11 changed files with 112 additions and 44 deletions

View File

@ -2040,6 +2040,12 @@ DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined
void thread_base::start() void thread_base::start()
{ {
m_sync.atomic_op([&](u32& v)
{
v &= ~static_cast<u32>(thread_state::mask);
v |= static_cast<u32>(thread_state::created);
});
#ifdef _WIN32 #ifdef _WIN32
m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr); m_thread = ::_beginthreadex(nullptr, 0, entry_point, this, CREATE_SUSPENDED, nullptr);
ensure(m_thread); ensure(m_thread);

View File

@ -5,6 +5,7 @@
#include "util/shared_ptr.hpp" #include "util/shared_ptr.hpp"
#include <string> #include <string>
#include <execution>
#include "mutex.h" #include "mutex.h"
#include "lockless.h" #include "lockless.h"
@ -83,9 +84,9 @@ struct result_storage<Ctx, Args...>
}; };
template <typename T> template <typename T>
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) // 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 // Derived from the callable object Context, possibly a lambda
template <class Context> template <class Context>
class named_thread final : public Context, result_storage<Context>, thread_base class named_thread final : public Context, result_storage<Context>, thread_base
@ -512,17 +518,27 @@ class named_thread final : public Context, result_storage<Context>, thread_base
public: public:
// Forwarding constructor with default name (also potentially the default constructor) // Forwarding constructor with default name (also potentially the default constructor)
template <typename... Args> requires (std::is_constructible_v<Context, Args&&...>) && (NamedThreadName<Context>) template <typename... Args> requires (std::is_constructible_v<Context, Args&&...>) && (!(std::is_same_v<std::remove_cvref_t<Args>, stx::launch_retainer> || ...)) && (NamedThreadName<Context>)
named_thread(Args&&... args) named_thread(Args&&... args) noexcept
: Context(std::forward<Args>(args)...) : Context(std::forward<Args>(args)...)
, thread(trampoline, std::string(Context::thread_name)) , thread(trampoline, std::string(Context::thread_name))
{ {
thread::start(); thread::start();
} }
// Forwarding constructor with default name, does not automatically run the thread
template <typename... Args> requires (std::is_constructible_v<Context, Args&&...>) && (NamedThreadName<Context>)
named_thread(const stx::launch_retainer&, Args&&... args) noexcept
: Context(std::forward<Args>(args)...)
, thread(trampoline, std::string(Context::thread_name))
{
// Create a stand-by thread context
m_sync |= static_cast<u32>(thread_state::finished);
}
// Normal forwarding constructor // Normal forwarding constructor
template <typename... Args> requires (std::is_constructible_v<Context, Args&&...>) template <typename... Args> requires (std::is_constructible_v<Context, Args&&...>) && (!NamedThreadName<Context>)
named_thread(std::string name, Args&&... args) named_thread(std::string name, Args&&... args) noexcept
: Context(std::forward<Args>(args)...) : Context(std::forward<Args>(args)...)
, thread(trampoline, std::move(name)) , thread(trampoline, std::move(name))
{ {
@ -530,7 +546,7 @@ public:
} }
// Lambda constructor, also the implicit deduction guide candidate // 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>)
: Context(std::forward<Context>(f)) : Context(std::forward<Context>(f))
, thread(trampoline, std::string(name)) , thread(trampoline, std::string(name))
{ {
@ -644,12 +660,20 @@ public:
return static_cast<thread_state>(thread::m_sync.load() & 3); return static_cast<thread_state>(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) 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; 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) if (s >= thread_state::aborting && thread::m_sync.fetch_op([](u32& v) { return !(v & 3) && (v |= 1); }).second)
{ {
notify_sync = true; notify_sync = true;

View File

@ -179,11 +179,6 @@ private:
std::unordered_map<s32, rtt_info> rtts; // (sock_id, rtt) std::unordered_map<s32, rtt_info> rtts; // (sock_id, rtt)
}; };
void initialize_tcp_timeout_monitor()
{
g_fxo->need<named_thread<tcp_timeout_monitor>>();
}
u16 u2s_tcp_checksum(const le_t<u16>* buffer, usz size) u16 u2s_tcp_checksum(const le_t<u16>* buffer, usz size)
{ {
u32 cksum = 0; u32 cksum = 0;

View File

@ -50,7 +50,6 @@ enum p2ps_tcp_flags : u8
CWR = (1 << 7), CWR = (1 << 7),
}; };
void initialize_tcp_timeout_monitor();
u16 u2s_tcp_checksum(const le_t<u16>* buffer, usz size); u16 u2s_tcp_checksum(const le_t<u16>* buffer, usz size);
std::vector<u8> generate_u2s_packet(const p2ps_encapsulated_tcp& header, const u8* data, const u32 datasize); std::vector<u8> generate_u2s_packet(const p2ps_encapsulated_tcp& header, const u8* data, const u32 datasize);

View File

@ -77,16 +77,14 @@ std::vector<signaling_message> get_sign_msgs()
return msgs; return msgs;
} }
void need_network() namespace np
{ {
g_fxo->need<network_context>(); void init_np_handler_dependencies();
initialize_tcp_timeout_monitor();
} }
network_thread::network_thread() network_thread::network_thread()
{ {
// Ensures IDM for lv2_socket is always valid when the thread is running np::init_np_handler_dependencies();
g_fxo->init<id_manager::id_map<lv2_socket>>();
} }
void network_thread::bind_sce_np_port() void network_thread::bind_sce_np_port()

View File

@ -339,6 +339,28 @@ namespace np
return; return;
} }
extern void init_np_handler_dependencies()
{
if (auto handler = g_fxo->try_get<named_thread<np_handler>>())
{
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<network_context>() && !m_inited_np_handler_dependencies)
{
m_inited_np_handler_dependencies = true;
auto& nc = g_fxo->get<network_context>();
nc.bind_sce_np_port();
std::lock_guard lock(mutex_rpcn);
rpcn = rpcn::rpcn_client::get_instance();
}
}
np_handler::np_handler() np_handler::np_handler()
{ {
g_fxo->need<named_thread<signaling_handler>>(); g_fxo->need<named_thread<signaling_handler>>();
@ -388,16 +410,6 @@ namespace np
if (g_cfg.net.upnp_enabled) if (g_cfg.net.upnp_enabled)
upnp.upnp_enable(); upnp.upnp_enable();
} }
if (is_psn_active && g_cfg.net.psn_status == np_psn_status::psn_rpcn)
{
g_fxo->need<network_context>();
auto& nc = g_fxo->get<network_context>();
nc.bind_sce_np_port();
std::lock_guard lock(mutex_rpcn);
rpcn = rpcn::rpcn_client::get_instance();
}
} }
np_handler::np_handler(utils::serial& ar) np_handler::np_handler(utils::serial& ar)

View File

@ -76,6 +76,7 @@ namespace np
np_handler(utils::serial& ar); np_handler(utils::serial& ar);
void save(utils::serial& ar); void save(utils::serial& ar);
void init_np_handler_dependencies();
const std::array<u8, 6>& get_ether_addr() const; const std::array<u8, 6>& get_ether_addr() const;
const std::string& get_hostname() const; const std::string& get_hostname() const;
u32 get_local_ip_addr() const; u32 get_local_ip_addr() const;
@ -305,6 +306,8 @@ namespace np
shared_mutex mutex_queue_basic_events; shared_mutex mutex_queue_basic_events;
std::queue<basic_event> queue_basic_events; std::queue<basic_event> queue_basic_events;
bool m_inited_np_handler_dependencies = false;
private: private:
bool is_connected = false; bool is_connected = false;
bool is_psn_active = false; bool is_psn_active = false;

View File

@ -17,7 +17,6 @@
LOG_CHANNEL(sign_log, "Signaling"); LOG_CHANNEL(sign_log, "Signaling");
void need_network();
template <> template <>
void fmt_class_string<SignalingCommand>::format(std::string& out, u64 arg) void fmt_class_string<SignalingCommand>::format(std::string& out, u64 arg)
@ -41,7 +40,6 @@ void fmt_class_string<SignalingCommand>::format(std::string& out, u64 arg)
signaling_handler::signaling_handler() signaling_handler::signaling_handler()
{ {
need_network();
} }
///////////////////////////// /////////////////////////////

View File

@ -2875,9 +2875,9 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
for (const auto& [type, data] : *g_fxo) 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 // Join threads
for (const auto& [type, data] : *g_fxo) 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);
} }
} }

View File

@ -15,6 +15,8 @@ extern thread_local std::string_view g_tls_serialize_name;
namespace stx namespace stx
{ {
struct launch_retainer{};
// Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear(). // Simplified typemap with exactly one object of each used type, non-moveable. Initialized on init(). Destroyed on clear().
template <typename Tag /*Tag should be unique*/, u32 Size = 0, u32 Align = (Size ? 64 : __STDCPP_DEFAULT_NEW_ALIGNMENT__)> template <typename Tag /*Tag should be unique*/, u32 Size = 0, u32 Align = (Size ? 64 : __STDCPP_DEFAULT_NEW_ALIGNMENT__)>
class alignas(Align) manual_typemap class alignas(Align) manual_typemap
@ -62,7 +64,7 @@ namespace stx
struct typeinfo struct typeinfo
{ {
bool(*create)(uchar* ptr, manual_typemap&, utils::serial*, std::string_view) noexcept = nullptr; 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(*save)(void* ptr, utils::serial&) noexcept = nullptr;
void(*destroy)(void* ptr) noexcept = nullptr; void(*destroy)(void* ptr) noexcept = nullptr;
std::string_view name; std::string_view name;
@ -72,13 +74,19 @@ namespace stx
{ {
if (ar) if (ar)
{ {
if constexpr (std::is_constructible_v<T, manual_typemap&, exact_t<utils::serial&>>) if constexpr (std::is_constructible_v<T, exact_t<manual_typemap&>, exact_t<utils::serial&>>)
{ {
g_tls_serialize_name = name; g_tls_serialize_name = name;
new (ptr) T(_this, exact_t<utils::serial&>(*ar)); new (ptr) T(_this, exact_t<utils::serial&>(*ar));
return true; return true;
} }
if constexpr (std::is_constructible_v<T, exact_t<const launch_retainer&>, exact_t<utils::serial&>>)
{
new (ptr) T(exact_t<const launch_retainer&>(launch_retainer{}), exact_t<utils::serial&>(*ar));
return true;
}
if constexpr (std::is_constructible_v<T, exact_t<utils::serial&>>) if constexpr (std::is_constructible_v<T, exact_t<utils::serial&>>)
{ {
g_tls_serialize_name = name; g_tls_serialize_name = name;
@ -88,12 +96,18 @@ namespace stx
} }
// Allow passing reference to "this" // Allow passing reference to "this"
if constexpr (std::is_constructible_v<T, manual_typemap&>) if constexpr (std::is_constructible_v<T, exact_t<manual_typemap&>>)
{ {
new (ptr) T(_this); new (ptr) T(_this);
return true; return true;
} }
if constexpr (std::is_constructible_v<T, exact_t<const launch_retainer&>>)
{
new (ptr) T(exact_t<const launch_retainer&>(launch_retainer{}));
return true;
}
// Call default constructor only if available // Call default constructor only if available
if constexpr (std::is_default_constructible_v<T>) if constexpr (std::is_default_constructible_v<T>)
{ {
@ -111,7 +125,7 @@ namespace stx
} }
template <typename T> template <typename T>
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) // Abort and/or join (expected thread_state::aborting or thread_state::finished)
*std::launder(static_cast<T*>(ptr)) = state; *std::launder(static_cast<T*>(ptr)) = state;
@ -134,7 +148,7 @@ namespace stx
if constexpr (std::is_assignable_v<T&, thread_state>) if constexpr (std::is_assignable_v<T&, thread_state>)
{ {
r.stop = &call_stop<T>; r.thread_op = &call_thread_op<T>;
} }
if constexpr (!!(requires (T& a) { a.save(std::declval<stx::exact_t<utils::serial&>>()); })) if constexpr (!!(requires (T& a) { a.save(std::declval<stx::exact_t<utils::serial&>>()); }))
@ -233,6 +247,8 @@ namespace stx
return a.first < b.first; return a.first < b.first;
}); });
const auto info_before = m_info;
for (pos = 0; pos < stx::typelist<typeinfo>().count(); pos++) for (pos = 0; pos < stx::typelist<typeinfo>().count(); pos++)
{ {
const auto& type = *order[pos].second; 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 = {}; g_tls_serialize_name = {};
} }

View File

@ -1174,13 +1174,21 @@ namespace stx
template <typename T> template <typename T>
struct exact_t struct exact_t
{ {
static_assert(std::is_reference_v<T> || std::is_convertible_v<T, const T&>);
T obj; T obj;
exact_t(T&& _obj) : obj(std::forward<T>(_obj)) {} explicit exact_t(T&& _obj) : obj(std::forward<T>(_obj)) {}
exact_t& operator=(const exact_t&) = delete;
// TODO: More conversions
template <typename U> requires (std::is_same_v<U&, T>) template <typename U> requires (std::is_same_v<U&, T>)
operator U&() const { return obj; }; operator U&() const noexcept { return obj; };
template <typename U> requires (std::is_same_v<const U&, T>)
operator const U&() const noexcept { return obj; };
template <typename U> requires (std::is_same_v<U, T> && std::is_copy_constructible_v<T>)
operator U() const noexcept { return obj; };
}; };
} }