diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 1d3cf9c261..2a82e943f1 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -2489,7 +2489,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) const auto queue = (std::lock_guard{group->mutex}, this->spup[spup].lock()); - if (!queue) + if (!lv2_event_queue::check(queue)) { spu_log.warning("sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); ch_in_mbox.set_values(1, CELL_ENOTCONN); @@ -2521,7 +2521,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value) const auto queue = (std::lock_guard{group->mutex}, this->spup[spup].lock()); - if (!queue) + if (!lv2_event_queue::check(queue)) { spu_log.warning("sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); return true; @@ -2904,14 +2904,14 @@ bool spu_thread::stop_and_signal(u32 code) { queue = v.second.lock(); - if (queue) + if (lv2_event_queue::check(queue)) { break; } } } - if (!queue) + if (!lv2_event_queue::check(queue)) { check_state(); return ch_in_mbox.set_values(1, CELL_EINVAL), true; // TODO: check error value @@ -3024,14 +3024,14 @@ bool spu_thread::stop_and_signal(u32 code) { if (spuq == v.first) { - if ((queue = v.second.lock())) + if (queue = v.second.lock(); lv2_event_queue::check(queue)) { break; } } } - if (!queue) + if (!lv2_event_queue::check(queue)) { return ch_in_mbox.set_values(1, CELL_EINVAL), true; } diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index f7037a219d..eab69b92c6 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -18,10 +18,29 @@ std::shared_ptr lv2_event_queue::find(u64 ipc_key) if (ipc_key == SYS_EVENT_QUEUE_LOCAL) { // Invalid IPC key - return{}; + return {}; } - return ipc_manager::get(ipc_key); + auto queue = ipc_manager::get(ipc_key); + + if (queue && !queue->exists) + { + queue.reset(); + } + + return queue; +} + +bool lv2_event_queue::check(const std::weak_ptr& wkptr) +{ + const auto queue = wkptr.lock(); + + return queue && queue->exists; +} + +bool lv2_event_queue::check(const std::shared_ptr& sptr) +{ + return sptr && sptr->exists; } bool lv2_event_queue::send(lv2_event event) @@ -153,6 +172,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode) return CELL_EBUSY; } + queue.exists = false; return {}; }); @@ -367,7 +387,7 @@ error_code sys_event_port_destroy(ppu_thread& ppu, u32 eport_id) const auto port = idm::withdraw(eport_id, [](lv2_event_port& port) -> CellError { - if (!port.queue.expired()) + if (lv2_event_queue::check(port.queue)) { return CELL_EISCONN; } @@ -408,7 +428,7 @@ error_code sys_event_port_connect_local(u32 eport_id, u32 equeue_id) return CELL_EINVAL; } - if (!port->queue.expired()) + if (lv2_event_queue::check(port->queue)) { return CELL_EISCONN; } @@ -445,7 +465,7 @@ error_code sys_event_port_connect_ipc(ppu_thread& ppu, u32 eport_id, u64 ipc_key return CELL_EINVAL; } - if (!port->queue.expired()) + if (lv2_event_queue::check(port->queue)) { return CELL_EISCONN; } @@ -470,7 +490,7 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id) return CELL_ESRCH; } - if (port->queue.expired()) + if (!lv2_event_queue::check(port->queue)) { return CELL_ENOTCONN; } @@ -490,7 +510,7 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) const auto port = idm::get(eport_id, [&](lv2_event_port& port) -> CellError { - if (const auto queue = port.queue.lock()) + if (const auto queue = port.queue.lock(); lv2_event_queue::check(queue)) { const u64 source = port.name ? port.name : (s64{process_getpid()} << 32) | u64{eport_id}; diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index 3c3a7e6d1e..3bef33a3cc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -85,6 +85,7 @@ struct lv2_event_queue final : public lv2_obj const u64 key; const s32 size; + atomic_t exists = true; // Existence validation (workaround for shared-ptr ref-counting) shared_mutex mutex; std::deque events; std::deque sq; @@ -107,6 +108,10 @@ struct lv2_event_queue final : public lv2_obj // Get event queue by its global key static std::shared_ptr find(u64 ipc_key); + + // Check queue ptr validity (use 'exists' member) + static bool check(const std::weak_ptr&); + static bool check(const std::shared_ptr&); }; struct lv2_event_port final : lv2_obj diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index cf8fb39aaf..709e9cf797 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -1298,7 +1298,7 @@ error_code sys_spu_thread_group_connect_event(ppu_thread& ppu, u32 id, u32 eq, u std::lock_guard lock(group->mutex); - if (!ep->expired()) + if (lv2_event_queue::check(*ep)) { return CELL_EBUSY; } @@ -1340,7 +1340,7 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et std::lock_guard lock(group->mutex); - if (ep->expired()) + if (!lv2_event_queue::check(*ep)) { return CELL_EINVAL; } @@ -1373,7 +1373,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, auto& port = thread->spup[spup]; - if (!port.expired()) + if (lv2_event_queue::check(port)) { return CELL_EISCONN; } @@ -1406,7 +1406,7 @@ error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 s auto& port = thread->spup[spup]; - if (port.expired()) + if (!lv2_event_queue::check(port)) { return CELL_ENOTCONN; } @@ -1546,7 +1546,7 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i { if (t) { - if (!t->spup[port].expired()) + if (lv2_event_queue::check(t->spup[port])) { found = false; break; diff --git a/rpcs3/Emu/Cell/lv2/sys_timer.cpp b/rpcs3/Emu/Cell/lv2/sys_timer.cpp index 073ce21927..4d84b377fd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_timer.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_timer.cpp @@ -82,7 +82,7 @@ error_code sys_timer_destroy(ppu_thread& ppu, u32 timer_id) const auto timer = idm::withdraw(timer_id, [&](lv2_timer& timer) -> CellError { - if (std::shared_lock lock(timer.mutex); !timer.port.expired()) + if (std::shared_lock lock(timer.mutex); lv2_event_queue::check(timer.port)) { return CELL_EISCONN; } @@ -231,7 +231,7 @@ error_code sys_timer_connect_event_queue(ppu_thread& ppu, u32 timer_id, u32 queu std::lock_guard lock(timer.mutex); - if (!timer.port.expired()) + if (lv2_event_queue::check(timer.port)) { return CELL_EISCONN; } @@ -269,7 +269,7 @@ error_code sys_timer_disconnect_event_queue(ppu_thread& ppu, u32 timer_id) timer.state = SYS_TIMER_STATE_STOP; - if (timer.port.expired()) + if (!lv2_event_queue::check(timer.port)) { return CELL_ENOTCONN; }