mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-24 18:39:56 +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 a = GetGpr(op.ra, 32);
|
||||||
const auto b = GetGpr(op.rb, 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 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(1 << 31), 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));
|
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.rc) SetCrField(0, GetUndef<bool>(), GetUndef<bool>(), GetUndef<bool>());
|
||||||
if (op.oe) SetOverflow(o);
|
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);
|
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
|
// Fix function arguments for external access
|
||||||
// TODO: Avoid using registers
|
|
||||||
ppu.gpr[3] = -1;
|
ppu.gpr[3] = -1;
|
||||||
ppu.gpr[4] = bitptn;
|
ppu.gpr[4] = bitptn;
|
||||||
ppu.gpr[5] = mode;
|
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;
|
verify(HERE), !mutex->signaled;
|
||||||
std::lock_guard lock(mutex->mutex);
|
std::lock_guard lock(mutex->mutex);
|
||||||
mutex->sq.emplace_back(result);
|
verify(HERE), mutex->add_waiter(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -228,7 +228,7 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
|||||||
{
|
{
|
||||||
verify(HERE), !mutex->signaled;
|
verify(HERE), !mutex->signaled;
|
||||||
std::lock_guard lock(mutex->mutex);
|
std::lock_guard lock(mutex->mutex);
|
||||||
mutex->sq.emplace_back(cpu);
|
verify(HERE), mutex->add_waiter(cpu);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -283,6 +283,23 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
|||||||
return;
|
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);
|
std::lock_guard lock(cond.mutex);
|
||||||
|
|
||||||
// Add a waiter
|
// 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 cause
|
||||||
return not_an_error(ppu.gpr[3]);
|
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);
|
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
|
auto mutex = idm::get<lv2_obj, lv2_lwmutex>(lwmutex_id);
|
||||||
{
|
|
||||||
std::lock_guard lock(mutex.mutex);
|
|
||||||
|
|
||||||
if (!mutex.sq.empty())
|
|
||||||
{
|
|
||||||
return CELL_EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!mutex)
|
if (!mutex)
|
||||||
{
|
{
|
||||||
return CELL_ESRCH;
|
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;
|
return CELL_OK;
|
||||||
@ -95,7 +123,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
|||||||
|
|
||||||
if (old)
|
if (old)
|
||||||
{
|
{
|
||||||
if (old == (1 << 31))
|
if (old == INT32_MIN)
|
||||||
{
|
{
|
||||||
ppu.gpr[3] = CELL_EBUSY;
|
ppu.gpr[3] = CELL_EBUSY;
|
||||||
}
|
}
|
||||||
@ -103,7 +131,12 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex.sq.emplace_back(&ppu);
|
if (!mutex.add_waiter(&ppu))
|
||||||
|
{
|
||||||
|
ppu.gpr[3] = CELL_ESRCH;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
mutex.sleep(ppu, timeout);
|
mutex.sleep(ppu, timeout);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
@ -229,7 +262,7 @@ error_code _sys_lwmutex_unlock2(ppu_thread& ppu, u32 lwmutex_id)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex.signaled |= 1 << 31;
|
mutex.signaled |= INT32_MIN;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!mutex)
|
if (!mutex)
|
||||||
|
@ -62,6 +62,7 @@ struct lv2_lwmutex final : lv2_obj
|
|||||||
shared_mutex mutex;
|
shared_mutex mutex;
|
||||||
atomic_t<s32> signaled{0};
|
atomic_t<s32> signaled{0};
|
||||||
std::deque<cpu_thread*> sq;
|
std::deque<cpu_thread*> sq;
|
||||||
|
atomic_t<s32> lwcond_waiters{0};
|
||||||
|
|
||||||
lv2_lwmutex(u32 protocol, vm::ptr<sys_lwmutex_t> control, u64 name)
|
lv2_lwmutex(u32 protocol, vm::ptr<sys_lwmutex_t> control, u64 name)
|
||||||
: protocol(protocol)
|
: protocol(protocol)
|
||||||
@ -69,6 +70,38 @@ struct lv2_lwmutex final : lv2_obj
|
|||||||
, name(std::bit_cast<be_t<u64>>(name))
|
, 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
|
// Aux
|
||||||
|
@ -1883,7 +1883,7 @@ namespace rsx
|
|||||||
const s32 default_frequency_mask = (1 << 8);
|
const s32 default_frequency_mask = (1 << 8);
|
||||||
const s32 swap_storage_mask = (1 << 29);
|
const s32 swap_storage_mask = (1 << 29);
|
||||||
const s32 volatile_storage_mask = (1 << 30);
|
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 u32 modulo_mask = rsx::method_registers.frequency_divider_operation_mask();
|
||||||
const auto max_index = (first_vertex + vertex_count) - 1;
|
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_U = 1 << 28,
|
||||||
CELL_GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_V = 1 << 29,
|
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_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_B = 1 << 0,
|
||||||
CELL_GCM_COLOR_MASK_G = 1 << 8,
|
CELL_GCM_COLOR_MASK_G = 1 << 8,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user