mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-30 21:32:50 +00:00
sys_lwmutex/lwcond: track lwcond waiters (#7826)
In lwmutex destroy syscall, wait for pending waiters.
This commit is contained in:
parent
9de9ec1f01
commit
cccc32fa9d
@ -3044,8 +3044,8 @@ void PPUTranslator::DIVW(ppu_opcode_t op)
|
||||
{
|
||||
const auto a = GetGpr(op.ra, 32);
|
||||
const auto b = GetGpr(op.rb, 32);
|
||||
const auto o = m_ir->CreateOr(IsZero(b), m_ir->CreateAnd(m_ir->CreateICmpEQ(a, m_ir->getInt32(1 << 31)), IsOnes(b)));
|
||||
const auto result = m_ir->CreateSDiv(a, m_ir->CreateSelect(o, m_ir->getInt32(1 << 31), b));
|
||||
const auto o = m_ir->CreateOr(IsZero(b), m_ir->CreateAnd(m_ir->CreateICmpEQ(a, m_ir->getInt32(INT32_MIN)), IsOnes(b)));
|
||||
const auto result = m_ir->CreateSDiv(a, m_ir->CreateSelect(o, m_ir->getInt32(INT32_MIN), b));
|
||||
SetGpr(op.rd, m_ir->CreateSelect(o, m_ir->getInt32(0), result));
|
||||
if (op.rc) SetCrField(0, GetUndef<bool>(), GetUndef<bool>(), GetUndef<bool>());
|
||||
if (op.oe) SetOverflow(o);
|
||||
|
@ -95,7 +95,6 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
|
||||
sys_event_flag.trace("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout);
|
||||
|
||||
// Fix function arguments for external access
|
||||
// TODO: Avoid using registers
|
||||
ppu.gpr[3] = -1;
|
||||
ppu.gpr[4] = bitptn;
|
||||
ppu.gpr[5] = mode;
|
||||
|
@ -140,7 +140,7 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u3
|
||||
{
|
||||
verify(HERE), !mutex->signaled;
|
||||
std::lock_guard lock(mutex->mutex);
|
||||
mutex->sq.emplace_back(result);
|
||||
verify(HERE), mutex->add_waiter(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -228,7 +228,7 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
{
|
||||
verify(HERE), !mutex->signaled;
|
||||
std::lock_guard lock(mutex->mutex);
|
||||
mutex->sq.emplace_back(cpu);
|
||||
verify(HERE), mutex->add_waiter(cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -283,6 +283,23 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to increment lwmutex's lwcond's waiters count
|
||||
if (!mutex->lwcond_waiters.fetch_op([](s32& val)
|
||||
{
|
||||
if (val == INT32_MIN)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
val++;
|
||||
return true;
|
||||
}).second)
|
||||
{
|
||||
// Failed - lwmutex was detroyed and all waiters have quit
|
||||
mutex.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(cond.mutex);
|
||||
|
||||
// Add a waiter
|
||||
@ -343,6 +360,12 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
}
|
||||
}
|
||||
|
||||
if (--mutex->lwcond_waiters == INT32_MIN)
|
||||
{
|
||||
// Notify the thread destroying lwmutex on last waiter
|
||||
mutex->lwcond_waiters.notify_all();
|
||||
}
|
||||
|
||||
// Return cause
|
||||
return not_an_error(ppu.gpr[3]);
|
||||
}
|
||||
|
@ -40,26 +40,54 @@ error_code _sys_lwmutex_destroy(ppu_thread& ppu, u32 lwmutex_id)
|
||||
|
||||
sys_lwmutex.warning("_sys_lwmutex_destroy(lwmutex_id=0x%x)", lwmutex_id);
|
||||
|
||||
const auto mutex = idm::withdraw<lv2_obj, lv2_lwmutex>(lwmutex_id, [&](lv2_lwmutex& mutex) -> CellError
|
||||
{
|
||||
std::lock_guard lock(mutex.mutex);
|
||||
|
||||
if (!mutex.sq.empty())
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
auto mutex = idm::get<lv2_obj, lv2_lwmutex>(lwmutex_id);
|
||||
|
||||
if (!mutex)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (mutex.ret)
|
||||
while (true)
|
||||
{
|
||||
return mutex.ret;
|
||||
if (std::scoped_lock lock(mutex->mutex); mutex->sq.empty())
|
||||
{
|
||||
// Set "destroyed" bit
|
||||
if (mutex->lwcond_waiters.fetch_or(INT32_MIN) & 0x7fff'ffff)
|
||||
{
|
||||
// Deschedule if waiters were found
|
||||
lv2_obj::sleep(ppu);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
// Wait for all lwcond waiters to quit
|
||||
if (const s32 old = mutex->lwcond_waiters; old & 0x7fff'ffff)
|
||||
{
|
||||
if (old > 0)
|
||||
{
|
||||
// Sleep queue is no longer empty
|
||||
// Was set to positive value to announce it
|
||||
continue;
|
||||
}
|
||||
|
||||
mutex->lwcond_waiters.wait(old);
|
||||
|
||||
if (ppu.is_stopped())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!idm::remove_verify<lv2_obj, lv2_lwmutex>(lwmutex_id, std::move(mutex)))
|
||||
{
|
||||
// Other thread has destroyed the lwmutex earlier
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -95,7 +123,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
||||
|
||||
if (old)
|
||||
{
|
||||
if (old == (1 << 31))
|
||||
if (old == INT32_MIN)
|
||||
{
|
||||
ppu.gpr[3] = CELL_EBUSY;
|
||||
}
|
||||
@ -103,7 +131,12 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
||||
return true;
|
||||
}
|
||||
|
||||
mutex.sq.emplace_back(&ppu);
|
||||
if (!mutex.add_waiter(&ppu))
|
||||
{
|
||||
ppu.gpr[3] = CELL_ESRCH;
|
||||
return true;
|
||||
}
|
||||
|
||||
mutex.sleep(ppu, timeout);
|
||||
return false;
|
||||
});
|
||||
@ -229,7 +262,7 @@ error_code _sys_lwmutex_unlock2(ppu_thread& ppu, u32 lwmutex_id)
|
||||
return;
|
||||
}
|
||||
|
||||
mutex.signaled |= 1 << 31;
|
||||
mutex.signaled |= INT32_MIN;
|
||||
});
|
||||
|
||||
if (!mutex)
|
||||
|
@ -62,6 +62,7 @@ struct lv2_lwmutex final : lv2_obj
|
||||
shared_mutex mutex;
|
||||
atomic_t<s32> signaled{0};
|
||||
std::deque<cpu_thread*> sq;
|
||||
atomic_t<s32> lwcond_waiters{0};
|
||||
|
||||
lv2_lwmutex(u32 protocol, vm::ptr<sys_lwmutex_t> control, u64 name)
|
||||
: protocol(protocol)
|
||||
@ -69,6 +70,38 @@ struct lv2_lwmutex final : lv2_obj
|
||||
, name(std::bit_cast<be_t<u64>>(name))
|
||||
{
|
||||
}
|
||||
|
||||
// Try to add a waiter
|
||||
bool add_waiter(cpu_thread* cpu)
|
||||
{
|
||||
if (const auto old = lwcond_waiters.fetch_op([](s32& val)
|
||||
{
|
||||
if (val + 0u <= INT32_MIN + 0u)
|
||||
{
|
||||
// Value was either positive or INT32_MIN
|
||||
return false;
|
||||
}
|
||||
|
||||
// lwmutex was set to be destroyed, but there are lwcond waiters
|
||||
// Turn off the "destroying" bit as we are adding an lwmutex waiter
|
||||
val &= 0x7fff'ffff;
|
||||
return true;
|
||||
}).first; old != INT32_MIN)
|
||||
{
|
||||
sq.emplace_back(cpu);
|
||||
|
||||
if (old < 0)
|
||||
{
|
||||
// Notify lwmutex destroyer (may cause EBUSY to be returned for it)
|
||||
lwcond_waiters.notify_all();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Failed - lwmutex was set to be destroyed and all lwcond waiters quit
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Aux
|
||||
|
@ -1883,7 +1883,7 @@ namespace rsx
|
||||
const s32 default_frequency_mask = (1 << 8);
|
||||
const s32 swap_storage_mask = (1 << 29);
|
||||
const s32 volatile_storage_mask = (1 << 30);
|
||||
const s32 modulo_op_frequency_mask = (1 << 31);
|
||||
const s32 modulo_op_frequency_mask = (INT32_MIN);
|
||||
|
||||
const u32 modulo_mask = rsx::method_registers.frequency_divider_operation_mask();
|
||||
const auto max_index = (first_vertex + vertex_count) - 1;
|
||||
|
@ -600,7 +600,7 @@ enum
|
||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_U = 1 << 28,
|
||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_V = 1 << 29,
|
||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_P = 1 << 30,
|
||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_Q = 1 << 31,
|
||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_Q = 1u << 31,
|
||||
|
||||
CELL_GCM_COLOR_MASK_B = 1 << 0,
|
||||
CELL_GCM_COLOR_MASK_G = 1 << 8,
|
||||
|
Loading…
x
Reference in New Issue
Block a user