mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +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());
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
@ -2555,13 +2555,13 @@ std::string thread_ctrl::get_name_cached()
|
|||
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)
|
||||
, 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
|
||||
this->exec();
|
||||
|
@ -2602,7 +2602,7 @@ bool thread_base::join(bool dtor) const
|
|||
|
||||
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;
|
||||
|
||||
protected:
|
||||
thread_base(native_entry, std::string name);
|
||||
thread_base(native_entry, std::string name) noexcept;
|
||||
|
||||
~thread_base();
|
||||
~thread_base() noexcept;
|
||||
|
||||
public:
|
||||
// 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
|
||||
struct scoped_priority
|
||||
{
|
||||
explicit scoped_priority(int prio)
|
||||
explicit scoped_priority(int prio) noexcept
|
||||
{
|
||||
set_native_priority(prio);
|
||||
}
|
||||
|
@ -360,7 +360,7 @@ public:
|
|||
|
||||
scoped_priority& operator=(const scoped_priority&) = delete;
|
||||
|
||||
~scoped_priority()
|
||||
~scoped_priority() noexcept
|
||||
{
|
||||
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;
|
||||
|
||||
public:
|
||||
thread_future_t(Ctx&& func, Args&&... args)
|
||||
thread_future_t(Ctx&& func, Args&&... args) noexcept
|
||||
: m_args(std::forward<Args>(args)...)
|
||||
, m_func(std::forward<Ctx>(func))
|
||||
{
|
||||
|
@ -417,7 +417,7 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
~thread_future_t()
|
||||
~thread_future_t() noexcept
|
||||
{
|
||||
if constexpr (!future::empty && !Discard)
|
||||
{
|
||||
|
@ -570,7 +570,7 @@ public:
|
|||
named_thread& operator=(const named_thread&) = delete;
|
||||
|
||||
// Wait for the completion and access result (if not void)
|
||||
[[nodiscard]] decltype(auto) operator()()
|
||||
[[nodiscard]] decltype(auto) operator()() noexcept
|
||||
{
|
||||
thread::join();
|
||||
|
||||
|
@ -581,7 +581,7 @@ public:
|
|||
}
|
||||
|
||||
// Wait for the completion and access result (if not void)
|
||||
[[nodiscard]] decltype(auto) operator()() const
|
||||
[[nodiscard]] decltype(auto) operator()() const noexcept
|
||||
{
|
||||
thread::join();
|
||||
|
||||
|
@ -593,7 +593,7 @@ public:
|
|||
|
||||
// Send command to the thread to invoke directly (references should be passed via std::ref())
|
||||
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.
|
||||
constexpr bool v1 = std::is_invocable_v<Context, Arg&&, Args&&...>;
|
||||
|
@ -667,12 +667,12 @@ public:
|
|||
}
|
||||
|
||||
// Access thread state
|
||||
operator thread_state() const
|
||||
operator thread_state() const noexcept
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
@ -693,7 +693,7 @@ public:
|
|||
|
||||
if constexpr (std::is_assignable_v<Context&, thread_state>)
|
||||
{
|
||||
static_cast<Context&>(*this) = s;
|
||||
static_cast<Context&>(*this) = thread_state::aborting;
|
||||
}
|
||||
|
||||
if (notify_sync)
|
||||
|
@ -706,13 +706,18 @@ public:
|
|||
{
|
||||
// This participates in emulation stopping, use destruction-alike semantics
|
||||
thread::join(true);
|
||||
|
||||
if constexpr (std::is_assignable_v<Context&, thread_state>)
|
||||
{
|
||||
static_cast<Context&>(*this) = thread_state::finished;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Context type doesn't need virtual destructor
|
||||
~named_thread()
|
||||
~named_thread() noexcept
|
||||
{
|
||||
// Assign aborting state forcefully and join thread
|
||||
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)
|
||||
{
|
||||
shared_ptr<lv2_config_service_event> ptr;
|
||||
|
||||
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
|
||||
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
|
||||
|
|
|
@ -390,13 +390,9 @@ public:
|
|||
}
|
||||
|
||||
// Destructor
|
||||
~lv2_config_service_event() noexcept
|
||||
{
|
||||
if (auto global = g_fxo->try_get<lv2_config>())
|
||||
{
|
||||
global->remove_service_event(id);
|
||||
}
|
||||
}
|
||||
lv2_config_service_event& operator=(thread_state s) noexcept;
|
||||
|
||||
~lv2_config_service_event() noexcept = default;
|
||||
|
||||
// Notify queue that this event exists
|
||||
bool notify() const;
|
||||
|
|
|
@ -175,3 +175,14 @@ void lv2_socket::queue_wake(ppu_thread* ppu)
|
|||
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;
|
||||
#endif
|
||||
|
||||
enum class thread_state : u32;
|
||||
|
||||
class lv2_socket
|
||||
{
|
||||
public:
|
||||
|
@ -62,7 +64,8 @@ public:
|
|||
lv2_socket(utils::serial&, lv2_socket_type type);
|
||||
static std::function<void(void*)> load(utils::serial& ar);
|
||||
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();
|
||||
|
||||
|
|
|
@ -57,19 +57,6 @@ void lv2_socket_native::save(utils::serial& ar)
|
|||
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()
|
||||
{
|
||||
ensure(family == SYS_NET_AF_INET);
|
||||
|
@ -1114,10 +1101,12 @@ void lv2_socket_native::close()
|
|||
socket = {};
|
||||
}
|
||||
|
||||
auto& dnshook = g_fxo->get<np::dnshook>();
|
||||
dnshook.remove_dns_spy(lv2_id);
|
||||
if (auto dnshook = g_fxo->try_get<np::dnshook>())
|
||||
{
|
||||
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>>();
|
||||
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(utils::serial& ar, lv2_socket_type type);
|
||||
void save(utils::serial& ar);
|
||||
~lv2_socket_native();
|
||||
s32 create_socket();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!nc.list_p2p_ports.contains(port))
|
||||
|
|
|
@ -944,8 +944,9 @@ void lv2_socket_p2ps::close()
|
|||
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);
|
||||
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>>();
|
||||
tcpm.clear_all_messages(lv2_id);
|
||||
if (const auto tcpm = g_fxo->try_get<named_thread<tcp_timeout_monitor>>())
|
||||
{
|
||||
tcpm->clear_all_messages(lv2_id);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
stx::serial_breathe_and_tag(*idm_capture, "id_map<lv2_memory_container>", false);
|
||||
}
|
||||
|
||||
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&)
|
||||
{
|
||||
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)
|
||||
|
@ -733,7 +733,7 @@ bool gdb_thread::cmd_read_all_registers(gdb_cmd&)
|
|||
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("");
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -2718,8 +2718,15 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
|
|||
cpu.state += cpu_flag::dbg_global_pause;
|
||||
};
|
||||
|
||||
idm::select<named_thread<ppu_thread>>(on_select);
|
||||
idm::select<named_thread<spu_thread>>(on_select);
|
||||
if (g_fxo->is_init<id_manager::id_map<named_thread<ppu_thread>>>())
|
||||
{
|
||||
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>())
|
||||
{
|
||||
|
@ -2760,6 +2767,7 @@ bool Emulator::Pause(bool freeze_emulation, bool show_resume_message)
|
|||
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 = 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
|
||||
s_tls_call_count = 1;
|
||||
s_tls_object_name = "none"sv;
|
||||
}
|
||||
|
||||
s_tls_current_pos = ar.pos;
|
||||
|
|
|
@ -1049,8 +1049,15 @@ void debugger_frame::UpdateUnitList()
|
|||
|
||||
if (emu_state != system_state::stopped)
|
||||
{
|
||||
idm::select<named_thread<ppu_thread>>(on_select, idm::unlocked);
|
||||
idm::select<named_thread<spu_thread>>(on_select, idm::unlocked);
|
||||
if (g_fxo->is_init<id_manager::id_map<named_thread<ppu_thread>>>())
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -154,6 +154,7 @@ namespace stx
|
|||
if (m_ptr) [[likely]]
|
||||
{
|
||||
const auto o = d();
|
||||
ensure(o->refs == 1);
|
||||
o->destroy.load()(o);
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
@ -437,11 +438,15 @@ namespace stx
|
|||
// Set to null
|
||||
void reset() noexcept
|
||||
{
|
||||
const auto o = d();
|
||||
|
||||
if (m_ptr && !--o->refs) [[unlikely]]
|
||||
if (m_ptr) [[unlikely]]
|
||||
{
|
||||
o->destroy(o);
|
||||
const auto o = d();
|
||||
|
||||
if (!--o->refs)
|
||||
{
|
||||
o->destroy(o);
|
||||
}
|
||||
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -571,7 +576,7 @@ namespace stx
|
|||
{
|
||||
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)));
|
||||
}
|
||||
|
@ -581,9 +586,32 @@ namespace stx
|
|||
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>
|
||||
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:
|
||||
using element_type = std::remove_extent_t<T>;
|
||||
|
||||
|
@ -592,11 +620,14 @@ namespace stx
|
|||
constexpr atomic_ptr() noexcept = default;
|
||||
|
||||
// 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
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -604,32 +635,38 @@ namespace stx
|
|||
atomic_ptr(const shared_ptr<U>& r) noexcept
|
||||
{
|
||||
// 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 (m_val)
|
||||
d()->refs += c_ref_mask + 1;
|
||||
if (uptr rval = to_val(r.m_ptr))
|
||||
{
|
||||
m_val.raw() = rval;
|
||||
d(rval)->refs += c_ref_mask + 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||
atomic_ptr(shared_ptr<U>&& r) noexcept
|
||||
{
|
||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||
r.m_ptr = nullptr;
|
||||
if (uptr rval = to_val(r.m_ptr))
|
||||
{
|
||||
m_val.raw() = rval;
|
||||
d(rval)->refs += c_ref_mask;
|
||||
}
|
||||
|
||||
if (m_val)
|
||||
d()->refs += c_ref_mask;
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
template <typename U> requires same_ptr_implicit_v<T, U>
|
||||
atomic_ptr(single_ptr<U>&& r) noexcept
|
||||
{
|
||||
m_val = reinterpret_cast<uptr>(r.m_ptr) << c_ref_size;
|
||||
r.m_ptr = nullptr;
|
||||
if (uptr rval = to_val(r.m_ptr))
|
||||
{
|
||||
m_val.raw() = rval;
|
||||
d(rval)->refs += c_ref_mask;
|
||||
}
|
||||
|
||||
if (m_val)
|
||||
d()->refs += c_ref_mask;
|
||||
r.m_ptr = nullptr;
|
||||
}
|
||||
|
||||
~atomic_ptr()
|
||||
~atomic_ptr() noexcept
|
||||
{
|
||||
const uptr v = m_val.raw();
|
||||
|
||||
|
@ -645,13 +682,13 @@ namespace stx
|
|||
}
|
||||
|
||||
// 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));
|
||||
r.d()->refs.raw() += c_ref_mask;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -704,7 +741,7 @@ namespace stx
|
|||
}
|
||||
|
||||
// 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++;
|
||||
|
||||
// Dereference if still the same pointer
|
||||
|
@ -749,7 +786,7 @@ namespace stx
|
|||
// Set fake unreferenced pointer
|
||||
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
|
||||
|
@ -805,14 +842,17 @@ namespace stx
|
|||
|
||||
// Create an object from variadic args
|
||||
// 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
|
||||
{
|
||||
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
||||
r.d()->refs.raw() += c_ref_mask;
|
||||
|
||||
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
|
||||
|
@ -824,20 +864,23 @@ namespace stx
|
|||
}
|
||||
|
||||
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
|
||||
{
|
||||
shared_type r = make_single<T>(std::forward<Args>(args)...);
|
||||
r.d()->refs.raw() += c_ref_mask;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -850,10 +893,10 @@ namespace stx
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -898,10 +941,10 @@ namespace stx
|
|||
}
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
|
@ -909,7 +952,7 @@ namespace stx
|
|||
}
|
||||
|
||||
// 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++;
|
||||
|
||||
// Dereference if still the same pointer
|
||||
|
@ -977,7 +1020,7 @@ namespace stx
|
|||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue