mirror of https://github.com/RPCS3/rpcs3.git
SPU: Use waitable atomics for SPU channels interface
This commit is contained in:
parent
3157a10428
commit
a029a94c73
|
@ -1892,6 +1892,7 @@ void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
|
||||||
|
|
||||||
void thread_base::notify_abort() noexcept
|
void thread_base::notify_abort() noexcept
|
||||||
{
|
{
|
||||||
|
m_signal.try_inc();
|
||||||
atomic_storage_futex::raw_notify(+m_state_notifier);
|
atomic_storage_futex::raw_notify(+m_state_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,12 @@ public:
|
||||||
static_cast<thread_base&>(thread).notify();
|
static_cast<thread_base&>(thread).notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void raw_notify(named_thread<T>& thread)
|
||||||
|
{
|
||||||
|
static_cast<thread_base&>(thread).notify_abort();
|
||||||
|
}
|
||||||
|
|
||||||
// Read current state
|
// Read current state
|
||||||
static inline thread_state state()
|
static inline thread_state state()
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ inline void try_start(spu_thread& spu)
|
||||||
}).second)
|
}).second)
|
||||||
{
|
{
|
||||||
spu.state -= cpu_flag::stop;
|
spu.state -= cpu_flag::stop;
|
||||||
thread_ctrl::notify(static_cast<named_thread<spu_thread>&>(spu));
|
thread_ctrl::raw_notify(static_cast<named_thread<spu_thread>&>(spu));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
|
||||||
|
|
||||||
case SPU_Out_MBox_offs:
|
case SPU_Out_MBox_offs:
|
||||||
{
|
{
|
||||||
value = ch_out_mbox.pop(*this);
|
value = ch_out_mbox.pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1247,11 +1247,11 @@ void spu_thread::push_snr(u32 number, u32 value)
|
||||||
// Check corresponding SNR register settings
|
// Check corresponding SNR register settings
|
||||||
if ((snr_config >> number) & 1)
|
if ((snr_config >> number) & 1)
|
||||||
{
|
{
|
||||||
channel->push_or(*this, value);
|
channel->push_or(value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
channel->push(*this, value);
|
channel->push(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2448,19 +2448,8 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
busy_wait();
|
busy_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 out = 0;
|
const s64 out = channel.pop_wait(*this);
|
||||||
|
static_cast<void>(test_stopped());
|
||||||
while (!channel.try_pop(out))
|
|
||||||
{
|
|
||||||
if (is_stopped())
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread_ctrl::wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
check_state();
|
|
||||||
return out;
|
return out;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2508,9 +2497,8 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
|
|
||||||
case MFC_RdTagStat:
|
case MFC_RdTagStat:
|
||||||
{
|
{
|
||||||
if (ch_tag_stat.get_count())
|
if (u32 out; ch_tag_stat.try_read(out))
|
||||||
{
|
{
|
||||||
u32 out = ch_tag_stat.get_value();
|
|
||||||
ch_tag_stat.set_value(0, false);
|
ch_tag_stat.set_value(0, false);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -2536,9 +2524,8 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
|
|
||||||
case MFC_RdAtomicStat:
|
case MFC_RdAtomicStat:
|
||||||
{
|
{
|
||||||
if (ch_atomic_stat.get_count())
|
if (u32 out; ch_atomic_stat.try_read(out))
|
||||||
{
|
{
|
||||||
u32 out = ch_atomic_stat.get_value();
|
|
||||||
ch_atomic_stat.set_value(0, false);
|
ch_atomic_stat.set_value(0, false);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -2549,9 +2536,8 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||||
|
|
||||||
case MFC_RdListStallStat:
|
case MFC_RdListStallStat:
|
||||||
{
|
{
|
||||||
if (ch_stall_stat.get_count())
|
if (u32 out; ch_stall_stat.try_read(out))
|
||||||
{
|
{
|
||||||
u32 out = ch_stall_stat.get_value();
|
|
||||||
ch_stall_stat.set_value(0, false);
|
ch_stall_stat.set_value(0, false);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -2658,16 +2644,14 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||||
{
|
{
|
||||||
if (get_type() >= spu_type::raw)
|
if (get_type() >= spu_type::raw)
|
||||||
{
|
{
|
||||||
while (!ch_out_intr_mbox.try_push(value))
|
if (ch_out_intr_mbox.get_count())
|
||||||
{
|
{
|
||||||
state += cpu_flag::wait;
|
state += cpu_flag::wait;
|
||||||
|
|
||||||
if (is_stopped())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_ctrl::wait();
|
if (!ch_out_intr_mbox.push_wait(*this, value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT);
|
int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT);
|
||||||
|
@ -2798,16 +2782,14 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
|
||||||
|
|
||||||
case SPU_WrOutMbox:
|
case SPU_WrOutMbox:
|
||||||
{
|
{
|
||||||
while (!ch_out_mbox.try_push(value))
|
if (ch_out_mbox.get_count())
|
||||||
{
|
{
|
||||||
state += cpu_flag::wait;
|
state += cpu_flag::wait;
|
||||||
|
|
||||||
if (is_stopped())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_ctrl::wait();
|
if (!ch_out_mbox.push_wait(*this, value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_state();
|
check_state();
|
||||||
|
@ -3196,7 +3178,7 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||||
|
|
||||||
if (thread.get() != this)
|
if (thread.get() != this)
|
||||||
{
|
{
|
||||||
thread_ctrl::notify(*thread);
|
thread_ctrl::raw_notify(*thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3325,7 +3307,7 @@ bool spu_thread::stop_and_signal(u32 code)
|
||||||
if (thread && thread.get() != this)
|
if (thread && thread.get() != this)
|
||||||
{
|
{
|
||||||
thread->state += cpu_flag::stop;
|
thread->state += cpu_flag::stop;
|
||||||
thread_ctrl::notify(*thread);
|
thread_ctrl::raw_notify(*thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,23 +175,20 @@ public:
|
||||||
// Returns true on success
|
// Returns true on success
|
||||||
bool try_push(u32 value)
|
bool try_push(u32 value)
|
||||||
{
|
{
|
||||||
const u64 old = data.fetch_op([value](u64& data)
|
return data.fetch_op([value](u64& data)
|
||||||
{
|
{
|
||||||
if (data & bit_count) [[unlikely]]
|
if (!(data & bit_count)) [[likely]]
|
||||||
{
|
|
||||||
data |= bit_wait;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
data = bit_count | value;
|
data = bit_count | value;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
return !(old & bit_count);
|
return false;
|
||||||
|
}).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push performing bitwise OR with previous value, may require notification
|
// Push performing bitwise OR with previous value, may require notification
|
||||||
void push_or(cpu_thread& spu, u32 value)
|
void push_or(u32 value)
|
||||||
{
|
{
|
||||||
const u64 old = data.fetch_op([value](u64& data)
|
const u64 old = data.fetch_op([value](u64& data)
|
||||||
{
|
{
|
||||||
|
@ -201,7 +198,7 @@ public:
|
||||||
|
|
||||||
if (old & bit_wait)
|
if (old & bit_wait)
|
||||||
{
|
{
|
||||||
spu.notify();
|
data.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,31 +208,28 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push unconditionally (overwriting previous value), may require notification
|
// Push unconditionally (overwriting previous value), may require notification
|
||||||
void push(cpu_thread& spu, u32 value)
|
void push(u32 value)
|
||||||
{
|
{
|
||||||
if (data.exchange(bit_count | value) & bit_wait)
|
if (data.exchange(bit_count | value) & bit_wait)
|
||||||
{
|
{
|
||||||
spu.notify();
|
data.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true on success
|
// Returns true on success
|
||||||
bool try_pop(u32& out)
|
bool try_pop(u32& out)
|
||||||
{
|
{
|
||||||
const u64 old = data.fetch_op([&](u64& data)
|
return data.fetch_op([&](u64& data)
|
||||||
{
|
{
|
||||||
if (data & bit_count) [[likely]]
|
if (data & bit_count) [[likely]]
|
||||||
{
|
{
|
||||||
out = static_cast<u32>(data);
|
out = static_cast<u32>(data);
|
||||||
data = 0;
|
data = 0;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
data |= bit_wait;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (old & bit_count) != 0;
|
return false;
|
||||||
|
}).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading without modification
|
// Reading without modification
|
||||||
|
@ -253,19 +247,95 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop unconditionally (loading last value), may require notification
|
// Pop unconditionally (loading last value), may require notification
|
||||||
u32 pop(cpu_thread& spu)
|
u32 pop()
|
||||||
{
|
{
|
||||||
// Value is not cleared and may be read again
|
// Value is not cleared and may be read again
|
||||||
const u64 old = data.fetch_and(~(bit_count | bit_wait));
|
const u64 old = data.fetch_and(~(bit_count | bit_wait));
|
||||||
|
|
||||||
if (old & bit_wait)
|
if (old & bit_wait)
|
||||||
{
|
{
|
||||||
spu.notify();
|
data.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<u32>(old);
|
return static_cast<u32>(old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Waiting for channel pop state availability, actually popping if specified
|
||||||
|
s64 pop_wait(cpu_thread& spu, bool pop = true)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const u64 old = data.fetch_op([&](u64& data)
|
||||||
|
{
|
||||||
|
if (data & bit_count) [[likely]]
|
||||||
|
{
|
||||||
|
if (pop)
|
||||||
|
{
|
||||||
|
data = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = bit_wait;
|
||||||
|
return true;
|
||||||
|
}).first;
|
||||||
|
|
||||||
|
if (old & bit_count)
|
||||||
|
{
|
||||||
|
return static_cast<u32>(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spu.is_stopped())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.wait(bit_wait);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waiting for channel push state availability, actually pushing if specified
|
||||||
|
bool push_wait(cpu_thread& spu, u32 value, bool push = true)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
u64 state;
|
||||||
|
data.fetch_op([&](u64& data)
|
||||||
|
{
|
||||||
|
if (data & bit_count) [[unlikely]]
|
||||||
|
{
|
||||||
|
data |= bit_wait;
|
||||||
|
}
|
||||||
|
else if (push)
|
||||||
|
{
|
||||||
|
data = bit_count | value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
state = data;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = data;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!(state & bit_wait))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spu.is_stopped())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.wait(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_value(u32 value, bool count = true)
|
void set_value(u32 value, bool count = true)
|
||||||
{
|
{
|
||||||
data.release(u64{count} << off_count | value);
|
data.release(u64{count} << off_count | value);
|
||||||
|
|
|
@ -754,7 +754,7 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
|
||||||
if (thread && ran_threads--)
|
if (thread && ran_threads--)
|
||||||
{
|
{
|
||||||
thread->state -= cpu_flag::stop;
|
thread->state -= cpu_flag::stop;
|
||||||
thread_ctrl::notify(*thread);
|
thread_ctrl::raw_notify(*thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,7 +904,7 @@ error_code sys_spu_thread_group_resume(ppu_thread& ppu, u32 id)
|
||||||
if (thread)
|
if (thread)
|
||||||
{
|
{
|
||||||
thread->state -= cpu_flag::suspend;
|
thread->state -= cpu_flag::suspend;
|
||||||
thread_ctrl::notify(*thread);
|
thread_ctrl::raw_notify(*thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,7 +1011,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value)
|
||||||
{
|
{
|
||||||
if (thread && group->running)
|
if (thread && group->running)
|
||||||
{
|
{
|
||||||
thread_ctrl::notify(*thread);
|
thread_ctrl::raw_notify(*thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2203,7 +2203,7 @@ error_code raw_spu_read_puint_mb(u32 id, vm::ptr<u32> value)
|
||||||
return CELL_ESRCH;
|
return CELL_ESRCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
*value = thread->ch_out_intr_mbox.pop(*thread);
|
*value = thread->ch_out_intr_mbox.pop();
|
||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue