mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-24 19:52:37 +01:00
Postpone thread launching on g_fxo->init
This commit is contained in:
parent
a4bcba8971
commit
0c410f8a14
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user