diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 2393c05ecf..7302473fc2 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -4083,11 +4083,6 @@ s64 spu_thread::get_ch_value(u32 ch) do_mfc(); } - for (int i = 0; i < 10 && channel.get_count() == 0; i++) - { - busy_wait(); - } - const s64 out = channel.pop_wait(*this); if (state & cpu_flag::wait) @@ -4119,11 +4114,6 @@ s64 spu_thread::get_ch_value(u32 ch) do_mfc(); } - for (int i = 0; i < 10 && ch_in_mbox.get_count() == 0; i++) - { - busy_wait(); - } - const auto [old_count, out] = ch_in_mbox.pop_wait(*this); if (old_count) @@ -5427,6 +5417,191 @@ spu_thread::priority_t::operator s32() const return _this->group->prio; } +s64 spu_channel::pop_wait(cpu_thread& spu, bool pop) +{ + u64 old = data.fetch_op([&](u64& data) + { + if (data & bit_count) [[likely]] + { + if (pop) + { + data = 0; + return true; + } + + return false; + } + + data = bit_wait; + jostling_value.release(bit_wait); + return true; + }).first; + + if (old & bit_count) + { + return static_cast(old); + } + + for (int i = 0; i < 10; i++) + { + busy_wait(); + + if (!(data & bit_wait)) + { + return static_cast(jostling_value); + } + } + + while (true) + { + thread_ctrl::wait_on(data, bit_wait); + old = data; + + if (!(old & bit_wait)) + { + return static_cast(jostling_value); + } + + if (spu.is_stopped()) + { + // Abort waiting and test if a value has been received + if (u64 v = jostling_value.exchange(0); !(v & bit_wait)) + { + return static_cast(v); + } + + ensure(data.bit_test_reset(off_wait)); + return -1; + } + } +} + +// Waiting for channel push state availability, actually pushing if specified +bool spu_channel::push_wait(cpu_thread& spu, u32 value, bool push) +{ + u64 state{}; + data.fetch_op([&](u64& data) + { + if (data & bit_count) [[unlikely]] + { + jostling_value.release(push ? value : static_cast(data)); + data |= bit_wait; + } + else if (push) + { + data = bit_count | value; + } + else + { + state = data; + return false; + } + + state = data; + return true; + }); + + for (int i = 0; i < 10; i++) + { + if (!(state & bit_wait)) + { + if (!push) + { + data &= ~bit_count; + } + + return true; + } + + busy_wait(); + state = data; + } + + while (true) + { + if (!(state & bit_wait)) + { + if (!push) + { + data &= ~bit_count; + } + + return true; + } + + if (spu.is_stopped()) + { + data &= ~bit_wait; + return false; + } + + thread_ctrl::wait_on(data, state); + state = data; + } +} + +std::pair spu_channel_4_t::pop_wait(cpu_thread& spu) +{ + auto old = values.fetch_op([&](sync_var_t& data) + { + if (data.count != 0) + { + data.waiting = 0; + data.count--; + + data.value0 = data.value1; + data.value1 = data.value2; + data.value2 = this->value3; + } + else + { + data.waiting = 1; + jostling_value.release(bit_wait); + } + }); + + if (old.count) + { + return {old.count, old.value0}; + } + + old.waiting = 1; + + for (int i = 0; i < 10; i++) + { + busy_wait(); + + if (!atomic_storage::load(values.raw().waiting)) + { + return {1, static_cast(jostling_value)}; + } + } + + while (true) + { + thread_ctrl::wait_on(values, old); + old = values; + + if (!old.waiting) + { + // Count of 1 because a value has been inserted and popped in the same step. + return {1, static_cast(jostling_value)}; + } + + if (spu.is_stopped()) + { + // Abort waiting and test if a value has been received + if (u64 v = jostling_value.exchange(0); !(v & bit_wait)) + { + return {1, static_cast(v)}; + } + + ensure(atomic_storage::exchange(values.raw().waiting, 0)); + return {}; + } + } +} + template <> void fmt_class_string::format(std::string& out, u64 arg) { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 4480f4763d..0cd0e689fb 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -297,102 +297,10 @@ public: } // Waiting for channel pop state availability, actually popping if specified - s64 pop_wait(cpu_thread& spu, bool pop = true) - { - u64 old = data.fetch_op([&](u64& data) - { - if (data & bit_count) [[likely]] - { - if (pop) - { - data = 0; - return true; - } - - return false; - } - - data = bit_wait; - jostling_value.release(bit_wait); - return true; - }).first; - - if (old & bit_count) - { - return static_cast(old); - } - - while (true) - { - thread_ctrl::wait_on(data, bit_wait); - old = data; - - if (!(old & bit_wait)) - { - return static_cast(jostling_value); - } - - if (spu.is_stopped()) - { - // Abort waiting and test if a value has been received - if (u64 v = jostling_value.exchange(0); !(v & bit_wait)) - { - return static_cast(v); - } - - ensure(data.bit_test_reset(off_wait)); - return -1; - } - } - } + s64 pop_wait(cpu_thread& spu, bool pop = true); // Waiting for channel push state availability, actually pushing if specified - bool push_wait(cpu_thread& spu, u32 value, bool push = true) - { - u64 state; - data.fetch_op([&](u64& data) - { - if (data & bit_count) [[unlikely]] - { - jostling_value.release(push ? value : static_cast(data)); - data |= bit_wait; - } - else if (push) - { - data = bit_count | value; - } - else - { - state = data; - return false; - } - - state = data; - return true; - }); - - while (true) - { - if (!(state & bit_wait)) - { - if (!push) - { - data &= ~bit_count; - } - - return true; - } - - if (spu.is_stopped()) - { - data &= ~bit_wait; - return false; - } - - thread_ctrl::wait_on(data, state); - state = data; - } - } + bool push_wait(cpu_thread& spu, u32 value, bool push = true); void set_value(u32 value, bool count = true) { @@ -504,59 +412,7 @@ struct spu_channel_4_t } // Returns [previous count, value] (if aborted 0 count is returned) - std::pair pop_wait(cpu_thread& spu) - { - u32 out_value = 0; - auto old = values.fetch_op([&](sync_var_t& data) - { - if (data.count != 0) - { - data.waiting = 0; - data.count--; - out_value = data.value0; - - data.value0 = data.value1; - data.value1 = data.value2; - data.value2 = this->value3; - } - else - { - data.waiting = 1; - jostling_value.release(bit_wait); - } - }); - - if (old.count) - { - return {old.count, out_value}; - } - - old.waiting = 1; - - while (true) - { - thread_ctrl::wait_on(values, old); - old = values; - - if (!old.waiting) - { - // Count of 1 because a value has been inserted and popped in the same step. - return {1, static_cast(jostling_value)}; - } - - if (spu.is_stopped()) - { - // Abort waiting and test if a value has been received - if (u64 v = jostling_value.exchange(0); !(v & bit_wait)) - { - return {1, static_cast(v)}; - } - - ensure(atomic_storage::exchange(values.raw().waiting, 0)); - return {}; - } - } - } + std::pair pop_wait(cpu_thread& spu); // returns current queue size without modification uint try_read(u32 (&out)[4]) const