SPU/LV2: Notify SPU events after mutex guards' unlocking

This commit is contained in:
Elad 2025-07-19 21:43:08 +03:00 committed by Elad
commit 620997c193
2 changed files with 38 additions and 6 deletions

View file

@ -6851,7 +6851,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
fmt::throw_exception("Unknown/illegal channel in WRCH (ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
}
extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus)
{
const auto group = spu.group;
@ -6865,7 +6865,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
{
group->run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED;
spu.state += cpu_flag::signal;
spu.state.notify_one();
ensure(spu.state & cpu_flag::suspend);
return;
}
@ -6883,7 +6883,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
thread->state -= cpu_flag::suspend;
}
thread->state.notify_one();
notify_spus[thread->index] = thread;
}
}
}

View file

@ -117,7 +117,7 @@ shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
return g_fxo->get<ipc_manager<lv2_event_queue, u64>>().get(ipc_key);
}
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus);
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
{
@ -126,6 +126,22 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
*notified_thread = false;
}
struct notify_spus_t
{
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
~notify_spus_t() noexcept
{
for (auto& spu : spus)
{
if (spu && spu->state & cpu_flag::wait)
{
spu->state.notify_one();
}
}
}
} notify_spus{};
std::lock_guard lock(mutex);
if (!exists)
@ -199,7 +215,7 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
const u32 data2 = static_cast<u32>(std::get<2>(event));
const u32 data3 = static_cast<u32>(std::get<3>(event));
spu.ch_in_mbox.set_values(4, CELL_OK, data1, data2, data3);
resume_spu_thread_group_from_waiting(spu);
resume_spu_thread_group_from_waiting(spu, notify_spus.spus);
}
return {};
@ -260,6 +276,22 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
return CELL_EINVAL;
}
struct notify_spus_t
{
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
~notify_spus_t() noexcept
{
for (auto& spu : spus)
{
if (spu && spu->state & cpu_flag::wait)
{
spu->state.notify_one();
}
}
}
} notify_spus{};
std::vector<lv2_event> events;
std::unique_lock<shared_mutex> qlock;
@ -357,7 +389,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
for (auto cpu = +queue->sq; cpu; cpu = cpu->next_cpu)
{
cpu->ch_in_mbox.set_values(1, CELL_ECANCELED);
resume_spu_thread_group_from_waiting(*cpu);
resume_spu_thread_group_from_waiting(*cpu, notify_spus.spus);
}
atomic_storage<spu_thread*>::release(queue->sq, nullptr);