From 43d3ccce95c8b7021c4d0a0c01e000653720940f Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 17 Jul 2015 19:27:12 +0300 Subject: [PATCH] SPU Channels improved --- rpcs3/Emu/Cell/RawSPUThread.cpp | 27 +++- rpcs3/Emu/Cell/SPUThread.cpp | 192 +++++++++++++++---------- rpcs3/Emu/Cell/SPUThread.h | 173 +++++++++++++++------- rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_cond.cpp | 17 +-- rpcs3/Emu/SysCalls/lv2/sys_interrupt.h | 5 +- rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_spu.cpp | 32 ++++- 8 files changed, 293 insertions(+), 157 deletions(-) diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index b0be2d46b9..afc6b1b369 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -68,7 +68,18 @@ bool RawSPUThread::ReadReg(const u32 addr, u32& value) case SPU_Out_MBox_offs: { - value = ch_out_mbox.pop_uncond(); + bool notify; + + std::tie(value, notify) = ch_out_mbox.pop(); + + if (notify) + { + // notify if necessary + std::lock_guard lock(mutex); + + cv.notify_one(); + } + return true; } @@ -169,8 +180,14 @@ bool RawSPUThread::WriteReg(const u32 addr, const u32 value) case SPU_In_MBox_offs: { - ch_in_mbox.push_uncond(value); - cv.notify_one(); + if (ch_in_mbox.push(value)) + { + // notify if necessary + std::lock_guard lock(mutex); + + cv.notify_one(); + } + return true; } @@ -207,13 +224,13 @@ bool RawSPUThread::WriteReg(const u32 addr, const u32 value) case SPU_RdSigNotify1_offs: { - write_snr(0, value); + push_snr(0, value); return true; } case SPU_RdSigNotify2_offs: { - write_snr(1, value); + push_snr(1, value); return true; } } diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index c6c25d6b28..86480a1766 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -326,7 +326,7 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) } else if ((cmd & MFC_PUT_CMD) && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2)) { - spu.write_snr(SYS_SPU_THREAD_SNR2 == offset, read32(args.lsa)); + spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, read32(args.lsa)); return; } else @@ -399,7 +399,7 @@ void SPUThread::do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args) if (rec->sb & 0x8000) { - ch_stall_stat.push_bit_or(1 << args.tag); + ch_stall_stat.set_value((1 << args.tag) | ch_stall_stat.get_value()); spu_mfc_arg_t stalled; stalled.ea = (args.ea & ~0xffffffff) | (list_addr + (i + 1) * 8); @@ -466,7 +466,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) last_raddr = raddr; - return ch_atomic_stat.push_uncond(MFC_GETLLAR_SUCCESS); + return ch_atomic_stat.set_value(MFC_GETLLAR_SUCCESS); } case MFC_PUTLLC_CMD: // store conditionally @@ -485,7 +485,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) last_raddr = 0; - return ch_atomic_stat.push_uncond(MFC_PUTLLC_SUCCESS); + return ch_atomic_stat.set_value(MFC_PUTLLC_SUCCESS); } else { @@ -496,7 +496,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) last_raddr = 0; } - return ch_atomic_stat.push_uncond(MFC_PUTLLC_FAILURE); + return ch_atomic_stat.set_value(MFC_PUTLLC_FAILURE); } } @@ -522,7 +522,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) if (cmd == MFC_PUTLLUC_CMD) { - ch_atomic_stat.push_uncond(MFC_PUTLLUC_SUCCESS); + ch_atomic_stat.set_value(MFC_PUTLLUC_SUCCESS); } return; @@ -643,10 +643,18 @@ u32 SPUThread::get_ch_value(u32 ch) { std::unique_lock lock(mutex, std::defer_lock); - u32 result; - - while (!channel.try_pop(result)) + while (true) { + bool result; + u32 value; + + std::tie(result, value) = channel.try_pop(); + + if (result) + { + return value; + } + CHECK_EMU_STATUS; if (IsStopped()) throw CPUThreadStop{}; @@ -657,10 +665,8 @@ u32 SPUThread::get_ch_value(u32 ch) continue; } - cv.wait_for(lock, std::chrono::milliseconds(1)); + cv.wait(lock); } - - return result; }; switch (ch) @@ -672,10 +678,24 @@ u32 SPUThread::get_ch_value(u32 ch) { std::unique_lock lock(mutex, std::defer_lock); - u32 result, count; - - while (!ch_in_mbox.try_pop(result, count)) + while (true) { + bool result; + u32 value; + u32 count; + + std::tie(result, value, count) = ch_in_mbox.try_pop(); + + if (result) + { + if (count + 1 == 4 /* SPU_IN_MBOX_THRESHOLD */) // TODO: check this + { + int_ctrl[2].set(SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT); + } + + return value; + } + CHECK_EMU_STATUS; if (IsStopped()) throw CPUThreadStop{}; @@ -686,15 +706,8 @@ u32 SPUThread::get_ch_value(u32 ch) continue; } - cv.wait_for(lock, std::chrono::milliseconds(1)); + cv.wait(lock); } - - if (count + 1 == 4 /* SPU_IN_MBOX_THRESHOLD */) // TODO: check this - { - int_ctrl[2].set(SPU_INT2_STAT_SPU_MAILBOX_THRESHOLD_INT); - } - - return result; } case MFC_RdTagStat: @@ -813,7 +826,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) continue; } - cv.wait_for(lock, std::chrono::milliseconds(1)); + cv.wait(lock); } int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT); @@ -826,57 +839,68 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { /* ===== sys_spu_thread_send_event (used by spu_printf) ===== */ - u8 spup = code & 63; + LV2_LOCK; - u32 data; - if (!ch_out_mbox.try_pop(data)) + const u8 spup = code & 63; + + if (!ch_out_mbox.get_count()) { throw EXCEPTION("sys_spu_thread_send_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup); } + if (u32 count = ch_in_mbox.get_count()) + { + throw EXCEPTION("sys_spu_thread_send_event(value=0x%x, spup=%d): In_MBox is not empty (count=%d)", value, spup, count); + } + + const u32 data = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(data, 0); + if (Ini.HLELogging.GetValue()) { LOG_NOTICE(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data); } - LV2_LOCK; - const auto queue = this->spup[spup].lock(); if (!queue) { LOG_WARNING(SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (value & 0x00ffffff), data); - return ch_in_mbox.push_uncond(CELL_ENOTCONN); // TODO: check error passing + return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing } if (queue->events.size() >= queue->size) { - return ch_in_mbox.push_uncond(CELL_EBUSY); + return ch_in_mbox.set_values(1, CELL_EBUSY); } queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (value & 0x00ffffff), data); - return ch_in_mbox.push_uncond(CELL_OK); + return ch_in_mbox.set_values(1, CELL_OK); } else if (code < 128) { /* ===== sys_spu_thread_throw_event ===== */ + LV2_LOCK; + const u8 spup = code & 63; - u32 data; - if (!ch_out_mbox.try_pop(data)) + if (!ch_out_mbox.get_count()) { throw EXCEPTION("sys_spu_thread_throw_event(value=0x%x, spup=%d): Out_MBox is empty", value, spup); } + const u32 data = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(data, 0); + if (Ini.HLELogging.GetValue()) { LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, value & 0x00ffffff, data); } - LV2_LOCK; - const auto queue = this->spup[spup].lock(); if (!queue) @@ -898,17 +922,28 @@ void SPUThread::set_ch_value(u32 ch, u32 value) else if (code == 128) { /* ===== sys_event_flag_set_bit ===== */ - u32 flag = value & 0xffffff; - u32 data; - if (!ch_out_mbox.try_pop(data)) + LV2_LOCK; + + const u32 flag = value & 0xffffff; + + if (!ch_out_mbox.get_count()) { throw EXCEPTION("sys_event_flag_set_bit(value=0x%x (flag=%d)): Out_MBox is empty", value, flag); } + if (u32 count = ch_in_mbox.get_count()) + { + throw EXCEPTION("sys_event_flag_set_bit(value=0x%x (flag=%d)): In_MBox is not empty (%d)", value, flag, count); + } + + const u32 data = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(data, 0); + if (flag > 63) { - throw EXCEPTION("sys_event_flag_set_bit(id=%d, value=0x%x): flag > 63", data, value, flag); + throw EXCEPTION("sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag); } if (Ini.HLELogging.GetValue()) @@ -916,13 +951,11 @@ void SPUThread::set_ch_value(u32 ch, u32 value) LOG_WARNING(SPU, "sys_event_flag_set_bit(id=%d, value=0x%x (flag=%d))", data, value, flag); } - LV2_LOCK; - const auto ef = Emu.GetIdManager().get(data); if (!ef) { - return ch_in_mbox.push_uncond(CELL_ESRCH); + return ch_in_mbox.set_values(1, CELL_ESRCH); } while (ef->cancelled) @@ -937,22 +970,28 @@ void SPUThread::set_ch_value(u32 ch, u32 value) ef->cv.notify_all(); } - return ch_in_mbox.push_uncond(CELL_OK); + return ch_in_mbox.set_values(1, CELL_OK); } else if (code == 192) { /* ===== sys_event_flag_set_bit_impatient ===== */ - u32 flag = value & 0xffffff; - u32 data; - if (!ch_out_mbox.try_pop(data)) + LV2_LOCK; + + const u32 flag = value & 0xffffff; + + if (!ch_out_mbox.get_count()) { throw EXCEPTION("sys_event_flag_set_bit_impatient(value=0x%x (flag=%d)): Out_MBox is empty", value, flag); } + const u32 data = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(data, 0); + if (flag > 63) { - throw EXCEPTION("sys_event_flag_set_bit_impatient(id=%d, value=0x%x): flag > 63", data, value, flag); + throw EXCEPTION("sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d)): Invalid flag", data, value, flag); } if (Ini.HLELogging.GetValue()) @@ -960,8 +999,6 @@ void SPUThread::set_ch_value(u32 ch, u32 value) LOG_WARNING(SPU, "sys_event_flag_set_bit_impatient(id=%d, value=0x%x (flag=%d))", data, value, flag); } - LV2_LOCK; - const auto ef = Emu.GetIdManager().get(data); if (!ef) @@ -1013,7 +1050,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) continue; } - cv.wait_for(lock, std::chrono::milliseconds(1)); + cv.wait(lock); } return; @@ -1027,7 +1064,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) case MFC_WrTagUpdate: { - ch_tag_stat.push_uncond(ch_tag_mask); // hack + ch_tag_stat.set_value(ch_tag_mask); // hack return; } @@ -1210,25 +1247,28 @@ void SPUThread::stop_and_signal(u32 code) { /* ===== sys_spu_thread_receive_event ===== */ - u32 spuq = 0; - if (!ch_out_mbox.try_pop(spuq)) + LV2_LOCK; + + if (!ch_out_mbox.get_count()) { - throw EXCEPTION("sys_spu_thread_receive_event(): cannot read Out_MBox"); + throw EXCEPTION("sys_spu_thread_receive_event(): Out_MBox is empty"); } - if (ch_in_mbox.get_count()) + if (u32 count = ch_in_mbox.get_count()) { - LOG_ERROR(SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq); - return ch_in_mbox.push_uncond(CELL_EBUSY); + LOG_ERROR(SPU, "sys_spu_thread_receive_event(): In_MBox is not empty (%d)", count); + return ch_in_mbox.set_values(1, CELL_EBUSY); } + const u32 spuq = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(spuq, 0); + if (Ini.HLELogging.GetValue()) { LOG_NOTICE(SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); } - LV2_LOCK; - const auto group = tg.lock(); if (!group) @@ -1238,7 +1278,7 @@ void SPUThread::stop_and_signal(u32 code) if (group->type & SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) // this check may be inaccurate { - return ch_in_mbox.push_uncond(CELL_EINVAL); + return ch_in_mbox.set_values(1, CELL_EINVAL); } std::shared_ptr queue; @@ -1258,7 +1298,7 @@ void SPUThread::stop_and_signal(u32 code) if (!queue) { - return ch_in_mbox.push_uncond(CELL_EINVAL); // TODO: check error value + return ch_in_mbox.set_values(1, CELL_EINVAL); // TODO: check error value } // check thread group status @@ -1301,15 +1341,12 @@ void SPUThread::stop_and_signal(u32 code) if (queue->cancelled) { - ch_in_mbox.push_uncond(CELL_ECANCELED); + ch_in_mbox.set_values(1, CELL_ECANCELED); } else { auto& event = queue->events.front(); - ch_in_mbox.push_uncond(CELL_OK); - ch_in_mbox.push_uncond((u32)event.data1); - ch_in_mbox.push_uncond((u32)event.data2); - ch_in_mbox.push_uncond((u32)event.data3); + ch_in_mbox.set_values(4, CELL_OK, static_cast(event.data1), static_cast(event.data2), static_cast(event.data3)); queue->events.pop_front(); queue->waiters--; @@ -1348,19 +1385,22 @@ void SPUThread::stop_and_signal(u32 code) { /* ===== sys_spu_thread_group_exit ===== */ - u32 value; - if (!ch_out_mbox.try_pop(value)) + LV2_LOCK; + + if (!ch_out_mbox.get_count()) { - throw EXCEPTION("sys_spu_thread_group_exit(): cannot read Out_MBox"); + throw EXCEPTION("sys_spu_thread_group_exit(): Out_MBox is empty"); } + const u32 value = ch_out_mbox.get_value(); + + ch_out_mbox.set_value(value, 0); + if (Ini.HLELogging.GetValue()) { LOG_NOTICE(SPU, "sys_spu_thread_group_exit(status=0x%x)", value); } - LV2_LOCK; - const auto group = tg.lock(); if (!group) @@ -1388,6 +1428,8 @@ void SPUThread::stop_and_signal(u32 code) { /* ===== sys_spu_thread_exit ===== */ + LV2_LOCK; + if (!ch_out_mbox.get_count()) { throw EXCEPTION("sys_spu_thread_exit(): Out_MBox is empty"); @@ -1398,8 +1440,6 @@ void SPUThread::stop_and_signal(u32 code) LOG_NOTICE(SPU, "sys_spu_thread_exit(status=0x%x)", ch_out_mbox.get_value()); } - LV2_LOCK; - const auto group = tg.lock(); if (!group) @@ -1416,11 +1456,11 @@ void SPUThread::stop_and_signal(u32 code) if (!ch_out_mbox.get_count()) { - throw EXCEPTION("Unknown STOP code: 0x%x", code); + throw EXCEPTION("Unknown STOP code: 0x%x (Out_MBox is empty)", code); } else { - throw EXCEPTION("Unknown STOP code: 0x%x; Out_MBox=0x%x", code, ch_out_mbox.get_value()); + throw EXCEPTION("Unknown STOP code: 0x%x (Out_MBox=0x%x)", code, ch_out_mbox.get_value()); } } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 856872a364..834da5f284 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -139,49 +139,48 @@ union spu_channel_t { struct sync_var_t { - u32 count; + struct + { + u32 waiting : 1; // waiting flag (0..1) + u32 count : 1; // channel count (0..1) + }; + u32 value; }; atomic_t sync_var; public: + // returns true on success bool try_push(u32 value) { return sync_var.atomic_op([=](sync_var_t& data) -> bool { if (data.count == 0) { + data.waiting = 0; data.count = 1; data.value = value; return true; } + data.waiting = 1; return false; }); } - void push_bit_or(u32 value) + // push performing bitwise OR with previous value, returns true if needs signaling + bool push_or(u32 value) { - sync_var._or({ 1, value }); - } - - void push_uncond(u32 value) - { - sync_var.exchange({ 1, value }); - } - - bool try_pop(u32& out_value) - { - return sync_var.atomic_op([&](sync_var_t& data) -> bool + return sync_var.atomic_op([=](sync_var_t& data) -> bool { - if (data.count != 0) - { - out_value = data.value; + data.count = 1; + data.value |= value; - data.count = 0; - data.value = 0; + if (data.waiting) + { + data.waiting = 0; return true; } @@ -190,20 +189,58 @@ public: }); } - u32 pop_uncond() + // push unconditionally (overwriting previous value), returns true if needs signaling + bool push(u32 value) { - return sync_var.atomic_op([](sync_var_t& data) -> u32 + return sync_var.atomic_op([=](sync_var_t& data) -> bool { - data.count = 0; + data.count = 1; + data.value = value; + if (data.waiting) + { + data.waiting = 0; + + return true; + } + + return false; + }); + } + + // returns true on success and u32 value + std::tuple try_pop() + { + return sync_var.atomic_op([](sync_var_t& data) + { + const auto result = std::make_tuple(data.count != 0, u32{ data.value }); + + data.waiting = data.count == 0; + data.count = 0; + data.value = 0; + + return result; + }); + } + + // pop unconditionally (loading last value), returns u32 value and bool value (true if needs signaling) + std::tuple pop() + { + return sync_var.atomic_op([](sync_var_t& data) + { + const auto result = std::make_tuple(u32{ data.value }, data.waiting != 0); + + data.waiting = 0; + data.count = 0; // value is not cleared and may be read again - return data.value; + + return result; }); } void set_value(u32 value, u32 count = 1) { - sync_var.store({ count, value }); + sync_var.store({ { 0, count }, value }); } u32 get_value() volatile @@ -221,7 +258,12 @@ struct spu_channel_4_t { struct sync_var_t { - u32 count; + struct + { + u32 waiting : 1; + u32 count : 3; + }; + u32 value0; u32 value1; u32 value2; @@ -237,11 +279,12 @@ public: value3 = {}; } - void push_uncond(u32 value) + // push unconditionally (overwriting latest value), returns true if needs signaling + bool push(u32 value) { value3.exchange(value); - sync_var.atomic_op([value](sync_var_t& data) + return sync_var.atomic_op([=](sync_var_t& data) -> bool { switch (data.count++) { @@ -250,36 +293,57 @@ public: case 2: data.value2 = value; break; default: data.count = 4; } + + if (data.waiting) + { + data.waiting = 0; + + return true; + } + + return false; }); } - // out_count: count after removing first element - bool try_pop(u32& out_value, u32& out_count) + // returns true on success and two u32 values: data and count after removing the first element + std::tuple try_pop() { - bool out_result; - - const u32 last_value = value3.load_sync(); - - sync_var.atomic_op([&out_result, &out_value, &out_count, last_value](sync_var_t& data) + return sync_var.atomic_op([this](sync_var_t& data) { - if ((out_result = (data.count != 0))) + const auto result = std::make_tuple(data.count != 0, u32{ data.value0 }, u32{ data.count - 1u }); + + if (data.count != 0) { - out_value = data.value0; - out_count = --data.count; + data.waiting = 0; + data.count--; data.value0 = data.value1; data.value1 = data.value2; - data.value2 = last_value; + data.value2 = value3.load_sync(); + } + else + { + data.waiting = 1; } - }); - return out_result; + return result; + }); } u32 get_count() volatile { return sync_var.data.count; } + + void set_values(u32 count, u32 value0, u32 value1 = 0, u32 value2 = 0, u32 value3 = 0) + { + sync_var.data.waiting = 0; + sync_var.data.count = count; + sync_var.data.value0 = value0; + sync_var.data.value1 = value1; + sync_var.data.value2 = value2; + this->value3.store(value3); + } }; struct spu_int_ctrl_t @@ -526,31 +590,38 @@ public: const u32 index; // SPU index const u32 offset; // SPU LS offset - void write_snr(bool number, u32 value) + void push_snr(u32 number, u32 value) { - if (!number) + if (number == 0) { if (snr_config & 1) { - ch_snr1.push_bit_or(value); + if (!ch_snr1.push_or(value)) return; } else { - ch_snr1.push_uncond(value); + if (!ch_snr1.push(value)) return; + } + } + else if (number == 1) + { + if (snr_config & 2) + { + if (!ch_snr2.push_or(value)) return; + } + else + { + if (!ch_snr2.push(value)) return; } } else { - if (snr_config & 2) - { - ch_snr2.push_bit_or(value); - } - else - { - ch_snr2.push_uncond(value); - } + throw EXCEPTION("Unexpected"); } + // notify if required + std::lock_guard lock(mutex); + cv.notify_one(); } diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp index f6895edd71..59f82f67a0 100644 --- a/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp @@ -10,7 +10,7 @@ sleep_queue_entry_t::sleep_queue_entry_t(CPUThread& cpu, sleep_queue_t& queue) : m_queue(queue) , m_thread(cpu) { - m_queue.emplace_back(std::move(cpu.shared_from_this())); + m_queue.emplace_back(cpu.shared_from_this()); m_thread.Sleep(); } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index a5719bfca1..17f28b7e2e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -167,22 +167,11 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout) return CELL_EPERM; } - // unlock mutex - cond->mutex->owner.reset(); - - // save recursive value + // save the recursive value const u32 recursive_value = cond->mutex->recursive_count.exchange(0); - if (cond->mutex->sq.size()) - { - // pick another owner; protocol is ignored in current implementation - cond->mutex->owner = cond->mutex->sq.front(); - - if (!cond->mutex->owner->Signal()) - { - throw EXCEPTION("Mutex owner not signaled"); - } - } + // unlock the mutex + cond->mutex->unlock(lv2_lock); { // add waiter; protocol is ignored in current implementation diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h index 16af8b9c5e..7cfee3f0a2 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.h @@ -6,14 +6,11 @@ class PPUThread; struct lv2_int_tag_t { - //const u32 class_id; // 0 or 2 for RawSPU const u32 id; - //const std::weak_ptr thread; // RawSPU thread - std::shared_ptr handler; - lv2_int_tag_t(/*u32 class_id, const std::shared_ptr thread*/); + lv2_int_tag_t(); }; REG_ID_TYPE(lv2_int_tag_t, 0x0A); // SYS_INTR_TAG_OBJECT diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index 012a970776..3a80240a1a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -24,7 +24,7 @@ void lv2_mutex_t::unlock(lv2_lock_t& lv2_lock) if (!owner->Signal()) { - throw EXCEPTION("Mutex owner not signaled"); + throw EXCEPTION("Mutex owner already signaled"); } } } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 3e469797c5..f7ba0b6c42 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -209,7 +209,14 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status) // TODO: check CELL_ESTAT condition - *status = thread->ch_out_mbox.pop_uncond(); + bool notify; + + std::tie(*status, notify) = thread->ch_out_mbox.pop(); + + if (notify) + { + throw EXCEPTION("Unexpected"); + } return CELL_OK; } @@ -694,8 +701,13 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) return CELL_ESTAT; } - thread->ch_in_mbox.push_uncond(value); - thread->cv.notify_one(); + if (thread->ch_in_mbox.push(value)) + { + // notify if necessary + std::lock_guard lock(thread->mutex); + + thread->cv.notify_one(); + } return CELL_OK; } @@ -771,7 +783,7 @@ s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) // return CELL_ESTAT; //} - thread->write_snr(number, value); + thread->push_snr(number, value); return CELL_OK; } @@ -1306,7 +1318,17 @@ s32 sys_raw_spu_read_puint_mb(u32 id, vm::ptr value) return CELL_ESRCH; } - *value = thread->ch_out_intr_mbox.pop_uncond(); + bool notify; + + std::tie(*value, notify) = thread->ch_out_intr_mbox.pop(); + + if (notify) + { + // notify if necessary + std::lock_guard lock(thread->mutex); + + thread->cv.notify_one(); + } return CELL_OK; }