SMutex eliminated

This commit is contained in:
Nekotekina 2014-12-23 02:31:11 +03:00
parent 0fb092f2a5
commit b2de24db73
48 changed files with 768 additions and 907 deletions

View File

@ -30,7 +30,7 @@ public:
{ {
//wait until there's actually something to get //wait until there's actually something to get
//throwing an exception might be better, blocking here is a little awkward //throwing an exception might be better, blocking here is a little awkward
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
size_t ret = mGet; size_t ret = mGet;
mGet = moveGet(); mGet = moveGet();
@ -45,7 +45,7 @@ public:
{ {
//if this is reached a lot it's time to increase the buffer size //if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing //or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
mBuffer[mPut] = std::forward(putEle); mBuffer[mPut] = std::forward(putEle);
mPut = movePut(); mPut = movePut();
@ -94,7 +94,7 @@ public:
{ {
//if this is reached a lot it's time to increase the buffer size //if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing //or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (mPut + length <= mBuffer.size()) if (mPut + length <= mBuffer.size())
{ {

View File

@ -1,10 +0,0 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Utilities/SMutex.h"
bool SM_IsAborted()
{
return Emu.IsStopped();
}

View File

@ -1,129 +0,0 @@
#pragma once
#include "Emu/Memory/atomic_type.h"
bool SM_IsAborted();
enum SMutexResult
{
SMR_OK = 0, // succeeded (lock, trylock, unlock)
SMR_FAILED, // failed (trylock, unlock)
SMR_DEADLOCK, // mutex reached deadlock (lock, trylock)
SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread
SMR_PERMITTED, // not owner of the mutex (unlock)
SMR_ABORT, // emulator has been stopped (lock, trylock, unlock)
SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock)
SMR_TIMEOUT, // timed out (lock)
};
template
<
typename T,
const u64 free_value = 0,
const u64 dead_value = 0xffffffffffffffffull
>
class SMutexBase
{
static_assert(sizeof(T) == sizeof(atomic_le_t<T>), "Invalid SMutexBase type");
T owner;
typedef atomic_le_t<T> AT;
public:
static const T GetFreeValue()
{
static const u64 value = free_value;
return (T&)value;
}
static const T GetDeadValue()
{
static const u64 value = dead_value;
return (T&)value;
}
void initialize()
{
owner = GetFreeValue();
}
void finalize()
{
owner = GetDeadValue();
}
__forceinline T GetOwner() const
{
return (T&)owner;
}
SMutexResult trylock(T tid)
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(GetFreeValue(), tid);
if (old != GetFreeValue())
{
if (old == tid)
{
return SMR_DEADLOCK;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_FAILED;
}
return SMR_OK;
}
SMutexResult unlock(T tid, T to = GetFreeValue())
{
if (SM_IsAborted())
{
return SMR_ABORT;
}
T old = reinterpret_cast<AT&>(owner).compare_and_swap(tid, to);
if (old != tid)
{
if (old == GetFreeValue())
{
return SMR_FAILED;
}
if (old == GetDeadValue())
{
return SMR_DESTROYED;
}
return SMR_PERMITTED;
}
return SMR_OK;
}
SMutexResult lock(T tid, u64 timeout = 0)
{
u64 counter = 0;
while (true)
{
switch (SMutexResult res = trylock(tid))
{
case SMR_FAILED: break;
default: return res;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (timeout && counter++ > timeout)
{
return SMR_TIMEOUT;
}
}
}
};
typedef SMutexBase<u32> SMutex;

View File

@ -38,7 +38,7 @@ public:
return false; return false;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
@ -65,7 +65,7 @@ public:
return false; return false;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
@ -100,7 +100,7 @@ public:
return false; return false;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }

View File

@ -160,10 +160,10 @@ public:
// register waiter // register waiter
waiter_reg_t waiter(*this, signal_id); waiter_reg_t waiter(*this, signal_id);
// check condition or if emulator is stopped // check the condition or if the emulator is stopped
while (!waiter_func() && !is_stopped(signal_id)) while (!waiter_func() && !is_stopped(signal_id))
{ {
// initialize waiter (only first time) // initialize waiter (only once)
waiter.init(); waiter.init();
// wait for 1 ms or until signal arrived // wait for 1 ms or until signal arrived
waiter.thread->WaitForAnySignal(1); waiter.thread->WaitForAnySignal(1);

View File

@ -21,8 +21,6 @@ CPUThread::CPUThread(CPUThreadType type)
, m_stack_addr(0) , m_stack_addr(0)
, m_offset(0) , m_offset(0)
, m_prio(0) , m_prio(0)
, m_sync_wait(false)
, m_wait_thread_id(-1)
, m_dec(nullptr) , m_dec(nullptr)
, m_is_step(false) , m_is_step(false)
, m_is_branch(false) , m_is_branch(false)
@ -44,7 +42,7 @@ bool CPUThread::IsStopped() const { return m_status == Stopped; }
void CPUThread::Close() void CPUThread::Close()
{ {
ThreadBase::Stop(m_sync_wait); ThreadBase::Stop(false);
DoStop(); DoStop();
delete m_dec; delete m_dec;
@ -55,9 +53,6 @@ void CPUThread::Reset()
{ {
CloseStack(); CloseStack();
m_sync_wait = 0;
m_wait_thread_id = -1;
SetPc(0); SetPc(0);
cycle = 0; cycle = 0;
m_is_branch = false; m_is_branch = false;
@ -89,24 +84,6 @@ void CPUThread::SetName(const std::string& name)
NamedThreadBase::SetThreadName(name); NamedThreadBase::SetThreadName(name);
} }
void CPUThread::Wait(bool wait)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_sync_wait = wait;
}
void CPUThread::Wait(const CPUThread& thr)
{
std::lock_guard<std::mutex> lock(m_cs_sync);
m_wait_thread_id = thr.GetId();
m_sync_wait = true;
}
bool CPUThread::Sync()
{
return m_sync_wait;
}
int CPUThread::ThreadStatus() int CPUThread::ThreadStatus()
{ {
if(Emu.IsStopped() || IsStopped() || IsPaused()) if(Emu.IsStopped() || IsStopped() || IsPaused())
@ -124,7 +101,7 @@ int CPUThread::ThreadStatus()
return CPUThread_Step; return CPUThread_Step;
} }
if (Emu.IsPaused() || Sync()) if (Emu.IsPaused())
{ {
return CPUThread_Sleeping; return CPUThread_Sleeping;
} }
@ -334,7 +311,7 @@ void CPUThread::Task()
if (status == CPUThread_Sleeping) if (status == CPUThread_Sleeping)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }

View File

@ -136,23 +136,6 @@ protected:
public: public:
virtual ~CPUThread(); virtual ~CPUThread();
u32 m_wait_thread_id;
std::mutex m_cs_sync;
bool m_sync_wait;
void Wait(bool wait);
void Wait(const CPUThread& thr);
bool Sync();
template<typename T>
void WaitFor(T func)
{
while(func(ThreadStatus()))
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int ThreadStatus(); int ThreadStatus();
void NextPc(u8 instr_size); void NextPc(u8 instr_size);
@ -280,7 +263,7 @@ public:
thread->SetJoinable(false); thread->SetJoinable(false);
while (thread->IsRunning()) while (thread->IsRunning())
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return thread->GetExitStatus(); return thread->GetExitStatus();
} }

View File

@ -72,12 +72,6 @@ void CPUThreadManager::RemoveThread(const u32 id)
for (u32 i = 0; i < m_threads.size(); ++i) for (u32 i = 0; i < m_threads.size(); ++i)
{ {
if (m_threads[i]->m_wait_thread_id == id)
{
m_threads[i]->Wait(false);
m_threads[i]->m_wait_thread_id = -1;
}
if (m_threads[i]->GetId() != id) continue; if (m_threads[i]->GetId() != id) continue;
thr = m_threads[i]; thr = m_threads[i];

View File

@ -3,12 +3,13 @@
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SQueue.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/ErrorCodes.h" #include "Emu/SysCalls/ErrorCodes.h"
#include "Utilities/SMutex.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h" #include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_time.h"
@ -588,7 +589,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
while (!SPU.Out_IntrMBox.Push(v)) while (!SPU.Out_IntrMBox.Push(v))
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
@ -721,21 +722,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
return; return;
} }
const u32 tid = GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag; ef->flags |= (u64)1 << flag;
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.Push(target, nullptr);
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
} }
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond(CELL_OK);
return; return;
} }
@ -769,21 +762,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
return; return;
} }
const u32 tid = GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag; ef->flags |= (u64)1 << flag;
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.Push(target, nullptr);
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
} }
else
{
ef->m_mutex.unlock(tid);
}
return; return;
} }
else else
@ -806,7 +791,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
case SPU_WrOutMbox: case SPU_WrOutMbox:
{ {
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@ -917,13 +905,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
case SPU_RdInMbox: case SPU_RdInMbox:
{ {
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
case MFC_RdTagStat: case MFC_RdTagStat:
{ {
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@ -937,11 +931,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
if (cfg.value & 1) if (cfg.value & 1)
{ {
while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
else else
{ {
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
break; break;
} }
@ -950,24 +950,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{ {
if (cfg.value & 2) if (cfg.value & 2)
{ {
while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
else else
{ {
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
} }
break; break;
} }
case MFC_RdAtomicStat: case MFC_RdAtomicStat:
{ {
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
case MFC_RdListStallStat: case MFC_RdListStallStat:
{ {
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!StallStat.Pop(v) && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
break; break;
} }
@ -985,7 +997,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
case SPU_RdEventStat: case SPU_RdEventStat:
{ {
while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); while (!CheckEvents() && !Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
v = m_events & m_event_mask; v = m_events & m_event_mask;
break; break;
} }
@ -1067,43 +1082,51 @@ void SPUThread::StopAndSignal(u32 code)
u32 tid = GetId(); u32 tid = GetId();
eq->sq.push(tid); // add thread to sleep queue eq->sq.push(tid, eq->protocol); // add thread to sleep queue
while (true) while (true)
{ {
switch (eq->owner.trylock(tid)) u32 old_owner = eq->owner.compare_and_swap(0, tid);
switch (s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0)
{ {
case SMR_OK: case 0:
if (!eq->events.count())
{ {
eq->owner.unlock(tid); const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0;
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid) if (next != tid)
{ {
eq->owner.unlock(tid, next); if (!eq->owner.compare_and_swap_test(tid, next))
{
assert(!"sys_spu_thread_receive_event() failed (I)");
}
break; break;
} }
// fallthrough
} }
case SMR_SIGNAL: case 1:
{ {
sys_event_data event; sys_event_data event;
eq->events.pop(event); eq->events.pop(event);
eq->owner.unlock(tid); if (!eq->owner.compare_and_swap_test(tid, 0))
{
assert(!"sys_spu_thread_receive_event() failed (II)");
}
SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond(CELL_OK);
SPU.In_MBox.PushUncond((u32)event.data1); SPU.In_MBox.PushUncond((u32)event.data1);
SPU.In_MBox.PushUncond((u32)event.data2); SPU.In_MBox.PushUncond((u32)event.data2);
SPU.In_MBox.PushUncond((u32)event.data3); SPU.In_MBox.PushUncond((u32)event.data3);
return; return;
} }
case SMR_FAILED: break;
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (!~old_owner)
{
eq->sq.invalidate(tid);
SPU.In_MBox.PushUncond(CELL_ECANCELED);
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "Utilities/SMutex.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "PPCThread.h" #include "PPCThread.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "MFC.h" #include "MFC.h"

View File

@ -1,9 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_event.h"
#include "Event.h" #include "Event.h"

View File

@ -2215,7 +2215,7 @@ void RSXThread::Task()
continue; continue;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
is_vblank_stopped = true; is_vblank_stopped = true;
@ -2246,7 +2246,7 @@ void RSXThread::Task()
m_sem_flush.post_and_wait(); m_sem_flush.post_and_wait();
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
@ -2332,7 +2332,7 @@ void RSXThread::Task()
while (!is_vblank_stopped) while (!is_vblank_stopped)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
LOG_NOTICE(RSX, "RSX thread ended"); LOG_NOTICE(RSX, "RSX thread ended");

View File

@ -244,12 +244,6 @@ u32 adecOpen(AudioDecoder* data)
break; break;
} }
//if (!adec.job.GetCountUnsafe() && adec.is_running)
//{
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// continue;
//}
if (!adec.job.Pop(task, &adec.is_closed)) if (!adec.job.Pop(task, &adec.is_closed))
{ {
break; break;
@ -576,7 +570,7 @@ int cellAdecClose(u32 handle)
cellAdec->Warning("cellAdecClose(%d) aborted", handle); cellAdec->Warning("cellAdecClose(%d) aborted", handle);
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId()); if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId());

View File

@ -6,9 +6,8 @@
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Utilities/SQueue.h" #include "Utilities/SQueue.h"
#include "Utilities/SMutex.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_time.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioManager.h"
@ -461,7 +460,7 @@ abort:
while (!internal_finished) while (!internal_finished)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
m_config.m_is_audio_finalized = true; m_config.m_is_audio_finalized = true;
@ -475,7 +474,7 @@ abort:
cellAudio->Warning("cellAudioInit() aborted"); cellAudio->Warning("cellAudioInit() aborted");
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
return CELL_OK; return CELL_OK;
@ -494,7 +493,7 @@ int cellAudioQuit()
while (!m_config.m_is_audio_finalized) while (!m_config.m_is_audio_finalized)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
cellAudio->Warning("cellAudioQuit(): aborted"); cellAudio->Warning("cellAudioQuit(): aborted");

View File

@ -288,9 +288,9 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptr<const CellCodecEsFilt
const u32 esSpecificInfo_addr, vm::ptr<CellDmuxEsAttr> attr) const u32 esSpecificInfo_addr, vm::ptr<CellDmuxEsAttr> attr)
{ {
if (esFilterId->filterIdMajor >= 0xe0) if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3 attr->memSize = 0x400000; // 0x45fa49 from ps3
else else
attr->memSize = 0x8000; // 0x73d9 from ps3 attr->memSize = 0x6000; // 0x73d9 from ps3
cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
@ -454,7 +454,7 @@ u32 dmuxOpen(Demuxer* data)
if (es.raw_data.size() > 1024 * 1024) if (es.raw_data.size() > 1024 * 1024)
{ {
stream = backup; stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
@ -550,7 +550,7 @@ u32 dmuxOpen(Demuxer* data)
if (es.isfull(old_size)) if (es.isfull(old_size))
{ {
stream = backup; stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
@ -714,7 +714,7 @@ u32 dmuxOpen(Demuxer* data)
{ {
if (Emu.IsStopped() || dmux.is_closed) break; if (Emu.IsStopped() || dmux.is_closed) break;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0);
@ -868,7 +868,7 @@ int cellDmuxClose(u32 demuxerHandle)
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId()); if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId());
@ -936,7 +936,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
return CELL_OK; return CELL_OK;
} }

View File

@ -156,7 +156,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
cellSysutil->Warning("MsgDialog thread aborted"); cellSysutil->Warning("MsgDialog thread aborted");
return; return;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0) while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0)
@ -166,7 +166,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogAbort; g_msg_dialog_state = msgDialogAbort;
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (callback && (g_msg_dialog_state != msgDialogAbort)) if (callback && (g_msg_dialog_state != msgDialogAbort))

View File

@ -4,8 +4,10 @@
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SQueue.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_spu.h"
@ -558,13 +560,13 @@ s64 spursInit(
if (spurs->m.flags1 & SF1_EXIT_IF_NO_WORK) if (spurs->m.flags1 & SF1_EXIT_IF_NO_WORK)
{ {
if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0))
{ {
assert(!"sys_lwmutex_lock() failed"); assert(!"sys_lwmutex_lock() failed");
} }
if (spurs->m.xD66.read_relaxed()) if (spurs->m.xD66.read_relaxed())
{ {
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@ -620,7 +622,7 @@ s64 spursInit(
spurs->m.xD65.exchange(1); spurs->m.xD65.exchange(1);
if (spurs->m.xD64.read_relaxed() == 0) if (spurs->m.xD64.read_relaxed() == 0)
{ {
if (s32 res = sys_lwcond_wait(spurs->get_lwcond(), 0)) if (s32 res = sys_lwcond_wait(CPU, spurs->get_lwcond(), 0))
{ {
assert(!"sys_lwcond_wait() failed"); assert(!"sys_lwcond_wait() failed");
} }
@ -628,7 +630,7 @@ s64 spursInit(
spurs->m.xD65.exchange(0); spurs->m.xD65.exchange(0);
if (spurs->m.xD66.read_relaxed()) if (spurs->m.xD66.read_relaxed())
{ {
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@ -638,7 +640,7 @@ s64 spursInit(
if (Emu.IsStopped()) continue; if (Emu.IsStopped()) continue;
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@ -705,7 +707,7 @@ s64 spursInit(
} }
else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup
{ {
return spursWakeUp(spurs); return spursWakeUp(GetCurrentPPUThread(), spurs);
} }
return CELL_OK; return CELL_OK;
@ -1265,7 +1267,7 @@ s64 cellSpursGetInfo(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursInfo> info)
#endif #endif
} }
s64 spursWakeUp(vm::ptr<CellSpurs> spurs) s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{ {
#ifdef PRX_DEBUG_XXX #ifdef PRX_DEBUG_XXX
return cb_call<s32, vm::ptr<CellSpurs>>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs); return cb_call<s32, vm::ptr<CellSpurs>>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs);
@ -1287,7 +1289,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
spurs->m.xD64.exchange(1); spurs->m.xD64.exchange(1);
if (spurs->m.xD65.read_sync()) if (spurs->m.xD65.read_sync())
{ {
if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0))
{ {
assert(!"sys_lwmutex_lock() failed"); assert(!"sys_lwmutex_lock() failed");
} }
@ -1295,7 +1297,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
{ {
assert(!"sys_lwcond_signal() failed"); assert(!"sys_lwcond_signal() failed");
} }
if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex()))
{ {
assert(!"sys_lwmutex_unlock() failed"); assert(!"sys_lwmutex_unlock() failed");
} }
@ -1303,11 +1305,11 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
return CELL_OK; return CELL_OK;
} }
s64 cellSpursWakeUp(vm::ptr<CellSpurs> spurs) s64 cellSpursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{ {
cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr()); cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr());
return spursWakeUp(spurs); return spursWakeUp(CPU, spurs);
} }
s32 spursAddWorkload( s32 spursAddWorkload(

View File

@ -604,5 +604,7 @@ struct CellSpursTaskBinInfo
CellSpursTaskLsPattern lsPattern; CellSpursTaskLsPattern lsPattern;
}; };
class PPUThread;
s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated); s64 spursAttachLv2EventQueue(vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool wasCreated);
s64 spursWakeUp(vm::ptr<CellSpurs> spurs); s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs);

View File

@ -3,8 +3,9 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_lwcond.h" #include "Emu/SysCalls/lv2/sys_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_spu.h"

View File

@ -4,9 +4,8 @@
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/SysCalls/lv2/sys_process.h"
#include "Emu/Event.h" #include "Emu/Event.h"

View File

@ -234,12 +234,6 @@ u32 vdecOpen(VideoDecoder* data)
break; break;
} }
//if (!vdec.job.GetCountUnsafe() && vdec.is_running)
//{
// std::this_thread::sleep_for(std::chrono::milliseconds(1));
// continue;
//}
if (!vdec.job.Pop(task, &vdec.is_closed)) if (!vdec.job.Pop(task, &vdec.is_closed))
{ {
break; break;
@ -612,7 +606,7 @@ int cellVdecClose(u32 handle)
cellVdec->Warning("cellVdecClose(%d) aborted", handle); cellVdec->Warning("cellVdecClose(%d) aborted", handle);
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId()); if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId());

View File

@ -347,7 +347,7 @@ int cellSurMixerCreate(vm::ptr<const CellSurMixerConfig> config)
if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }

View File

@ -4,9 +4,10 @@
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsFile.h"
#include "Emu/SysCalls/lv2/sleep_queue_type.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_spinlock.h" #include "Emu/SysCalls/lv2/sys_spinlock.h"

View File

@ -155,7 +155,7 @@ void fsAioRead(u32 fd, vm::ptr<CellFsAio> aio, int xid, vm::ptr<void (*)(vm::ptr
{ {
while (g_FsAioReadCur != xid) while (g_FsAioReadCur != xid)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
sys_fs->Warning("fsAioRead() aborted"); sys_fs->Warning("fsAioRead() aborted");

View File

@ -6,9 +6,10 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "ModuleManager.h" #include "ModuleManager.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "lv2/lv2Fs.h" #include "lv2/lv2Fs.h"
#include "lv2/sleep_queue_type.h"
#include "lv2/sys_lwmutex.h" #include "lv2/sys_lwmutex.h"
#include "lv2/sys_mutex.h" #include "lv2/sys_mutex.h"
#include "lv2/sys_cond.h" #include "lv2/sys_cond.h"
@ -139,11 +140,11 @@ static func_caller* sc_table[kSyscallTableLength] =
bind_func(sys_semaphore_wait), //92 (0x05C) bind_func(sys_semaphore_wait), //92 (0x05C)
bind_func(sys_semaphore_trywait), //93 (0x05D) bind_func(sys_semaphore_trywait), //93 (0x05D)
bind_func(sys_semaphore_post), //94 (0x05E) bind_func(sys_semaphore_post), //94 (0x05E)
null_func,//bind_func(sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create
null_func,//bind_func(sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy
null_func,//bind_func(sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock
null_func,//bind_func(sys_lwmutex_trylock), //98 (0x062) // internal, used by sys_lwmutex_unlock null_func,//bind_func(_sys_lwmutex_trylock), //98 (0x062) // internal, used by sys_lwmutex_unlock
null_func,//bind_func(sys_lwmutex_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock null_func,//bind_func(_sys_lwmutex_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock
bind_func(sys_mutex_create), //100 (0x064) bind_func(sys_mutex_create), //100 (0x064)
bind_func(sys_mutex_destroy), //101 (0x065) bind_func(sys_mutex_destroy), //101 (0x065)
bind_func(sys_mutex_lock), //102 (0x066) bind_func(sys_mutex_lock), //102 (0x066)
@ -155,9 +156,9 @@ static func_caller* sc_table[kSyscallTableLength] =
bind_func(sys_cond_signal), //108 (0x06C) bind_func(sys_cond_signal), //108 (0x06C)
bind_func(sys_cond_signal_all), //109 (0x06D) bind_func(sys_cond_signal_all), //109 (0x06D)
bind_func(sys_cond_signal_to), //110 (0x06E) bind_func(sys_cond_signal_to), //110 (0x06E)
null_func,//bind_func(sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create null_func,//bind_func(_sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create
null_func,//bind_func(sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy null_func,//bind_func(_sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy
null_func,//bind_func(sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait null_func,//bind_func(_sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait
bind_func(sys_semaphore_get_value), //114 (0x072) bind_func(sys_semaphore_get_value), //114 (0x072)
null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to
null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all

View File

@ -0,0 +1,149 @@
#include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Memory/atomic_type.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h"
#include "sleep_queue_type.h"
void sleep_queue_t::push(u32 tid, u32 protocol)
{
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
list.push_back(tid);
return;
}
case SYS_SYNC_RETRY:
{
return;
}
}
LOG_ERROR(HLE, "sleep_queue_t::push(): unsupported protocol (0x%x)", protocol);
Emu.Pause();
}
u32 sleep_queue_t::pop(u32 protocol)
{
switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK)
{
case SYS_SYNC_FIFO:
{
std::lock_guard<std::mutex> lock(m_mutex);
while (true)
{
if (list.size())
{
u32 res = list[0];
list.erase(list.begin());
if (res && Emu.GetIdManager().CheckID(res))
// check thread
{
return res;
}
}
return 0;
}
}
case SYS_SYNC_PRIORITY:
{
std::lock_guard<std::mutex> lock(m_mutex);
while (true)
{
if (list.size())
{
u64 highest_prio = ~0ull;
u32 sel = 0;
for (u32 i = 0; i < list.size(); i++)
{
CPUThread* t = Emu.GetCPU().GetThread(list[i]);
if (!t)
{
list[i] = 0;
sel = i;
break;
}
u64 prio = t->GetPrio();
if (prio < highest_prio)
{
highest_prio = prio;
sel = i;
}
}
u32 res = list[sel];
list.erase(list.begin() + sel);
/* if (Emu.GetIdManager().CheckID(res)) */
if (res)
// check thread
{
return res;
}
}
return 0;
}
}
case SYS_SYNC_RETRY:
{
return 0;
}
}
LOG_ERROR(HLE, "sleep_queue_t::pop(): unsupported protocol (0x%x)", protocol);
Emu.Pause();
return 0;
}
bool sleep_queue_t::invalidate(u32 tid)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (tid) for (u32 i = 0; i < list.size(); i++)
{
if (list[i] == tid)
{
list.erase(list.begin() + i);
return true;
}
}
return false;
}
u32 sleep_queue_t::count()
{
std::lock_guard<std::mutex> lock(m_mutex);
u32 result = 0;
for (u32 i = 0; i < list.size(); i++)
{
if (list[i]) result++;
}
return result;
}
bool sleep_queue_t::finalize()
{
if (!m_mutex.try_lock()) return false;
for (u32 i = 0; i < list.size(); i++)
{
if (list[i])
{
m_mutex.unlock();
return false;
}
}
m_mutex.unlock();
return true;
}

View File

@ -0,0 +1,45 @@
#pragma once
// attr_protocol (waiting scheduling policy)
enum
{
// First In, First Out
SYS_SYNC_FIFO = 1,
// Priority Order
SYS_SYNC_PRIORITY = 2,
// Basic Priority Inheritance Protocol (probably not implemented)
SYS_SYNC_PRIORITY_INHERIT = 3,
// Not selected while unlocking
SYS_SYNC_RETRY = 4,
//
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
};
// attr_recursive (recursive locks policy)
enum
{
// Recursive locks are allowed
SYS_SYNC_RECURSIVE = 0x10,
// Recursive locks are NOT allowed
SYS_SYNC_NOT_RECURSIVE = 0x20,
//
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
};
struct sleep_queue_t
{
std::vector<u32> list;
std::mutex m_mutex;
u64 m_name;
sleep_queue_t(u64 name = 0)
: m_name(name)
{
}
void push(u32 tid, u32 protocol);
u32 pop(u32 protocol);
bool invalidate(u32 tid);
u32 count();
bool finalize();
};

View File

@ -3,11 +3,12 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_mutex.h" #include "sys_mutex.h"
#include "sys_cond.h" #include "sys_cond.h"
@ -33,7 +34,7 @@ s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribu
} }
Cond* cond = new Cond(mutex, attr->name_u64); Cond* cond = new Cond(mutex, attr->name_u64);
u32 id = sys_cond.GetNewId(cond, TYPE_COND); const u32 id = sys_cond.GetNewId(cond, TYPE_COND);
*cond_id = id; *cond_id = id;
mutex->cond_count++; mutex->cond_count++;
sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id); sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id);
@ -54,7 +55,7 @@ s32 sys_cond_destroy(u32 cond_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!cond->m_queue.finalize()) if (!cond->queue.finalize())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -77,9 +78,9 @@ s32 sys_cond_signal(u32 cond_id)
Mutex* mutex = cond->mutex; Mutex* mutex = cond->mutex;
if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) if (u32 target = cond->queue.pop(mutex->protocol))
{ {
cond->signal.lock(target); cond->signal.Push(target, nullptr);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -102,10 +103,9 @@ s32 sys_cond_signal_all(u32 cond_id)
Mutex* mutex = cond->mutex; Mutex* mutex = cond->mutex;
while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) while (u32 target = cond->queue.pop(mutex->protocol))
{ {
cond->signaler = GetCurrentPPUThread().GetId(); cond->signal.Push(target, nullptr);
cond->signal.lock(target);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -114,7 +114,6 @@ s32 sys_cond_signal_all(u32 cond_id)
} }
} }
cond->signaler = 0;
return CELL_OK; return CELL_OK;
} }
@ -133,7 +132,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!cond->m_queue.invalidate(thread_id)) if (!cond->queue.invalidate(thread_id))
{ {
return CELL_EPERM; return CELL_EPERM;
} }
@ -142,7 +141,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
u32 target = thread_id; u32 target = thread_id;
{ {
cond->signal.lock(target); cond->signal.Push(target, nullptr);
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
@ -153,7 +152,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
return CELL_OK; return CELL_OK;
} }
s32 sys_cond_wait(u32 cond_id, u64 timeout) s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
{ {
sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout); sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout);
@ -164,65 +163,69 @@ s32 sys_cond_wait(u32 cond_id, u64 timeout)
} }
Mutex* mutex = cond->mutex; Mutex* mutex = cond->mutex;
u32 tid = GetCurrentPPUThread().GetId();
if (mutex->m_mutex.GetOwner() != tid) const u32 tid = CPU.GetId();
if (mutex->owner.read_sync() != tid)
{ {
sys_cond.Warning("sys_cond_wait(cond_id=%d) failed (EPERM)", cond_id);
return CELL_EPERM; return CELL_EPERM;
} }
cond->m_queue.push(tid); cond->queue.push(tid, mutex->protocol);
auto old_recursive = mutex->recursive; auto old_recursive = mutex->recursive;
mutex->recursive = 0; mutex->recursive = 0;
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol)))
{
u64 counter = 0; assert(!"sys_cond_wait() failed");
const u64 max_counter = timeout ? (timeout / 1000) : ~0ull; }
bool pushed_in_sleep_queue = false;
const u64 time_start = get_system_time();
while (true) while (true)
{ {
if (cond->signal.unlock(tid, tid) == SMR_OK) u32 signaled;
if (cond->signal.Peek(signaled, &sq_no_wait) && signaled == tid) // check signaled threads
{ {
if (SMutexResult res = mutex->m_mutex.trylock(tid)) if (mutex->owner.compare_and_swap_test(0, tid)) // try to lock
{ {
if (res != SMR_FAILED)
{
goto abort;
}
mutex->m_queue.push(tid);
switch (mutex->m_mutex.lock(tid))
{
case SMR_OK:
mutex->m_queue.invalidate(tid);
case SMR_SIGNAL:
break; break;
default:
goto abort;
}
}
mutex->recursive = old_recursive;
cond->signal.unlock(tid);
return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (!pushed_in_sleep_queue)
if (counter++ > max_counter)
{ {
cond->m_queue.invalidate(tid); mutex->queue.push(tid, mutex->protocol);
GetCurrentPPUThread().owned_mutexes--; // ??? pushed_in_sleep_queue = true;
return CELL_ETIMEDOUT;
} }
auto old_owner = mutex->owner.compare_and_swap(0, tid);
if (!old_owner)
{
mutex->queue.invalidate(tid);
break;
}
if (old_owner == tid)
{
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (timeout && get_system_time() - time_start > timeout)
{
cond->queue.invalidate(tid);
CPU.owned_mutexes--; // ???
return CELL_ETIMEDOUT; // mutex not locked
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
goto abort;
}
}
abort:
sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id); sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id);
return CELL_OK; return CELL_OK;
} }
}
mutex->recursive = old_recursive;
cond->signal.Pop(cond_id /* unused result */, nullptr);
return CELL_OK;
}

View File

@ -15,25 +15,22 @@ struct sys_cond_attribute
struct Cond struct Cond
{ {
Mutex* mutex; // associated with mutex Mutex* mutex; // associated with mutex
SMutex signal; SQueue<u32, 32> signal;
u32 signaler; // signaler thread id (for signal_all) sleep_queue_t queue;
SleepQueue m_queue;
u64 signal_stamp;
Cond(Mutex* mutex, u64 name) Cond(Mutex* mutex, u64 name)
: mutex(mutex) : mutex(mutex)
, m_queue(name) , queue(name)
, signaler(0)
{ {
signal.initialize();
} }
}; };
class PPUThread;
// SysCalls // SysCalls
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute> attr); s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute> attr);
s32 sys_cond_destroy(u32 cond_id); s32 sys_cond_destroy(u32 cond_id);
s32 sys_cond_wait(u32 cond_id, u64 timeout); s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout);
s32 sys_cond_signal(u32 cond_id); s32 sys_cond_signal(u32 cond_id);
s32 sys_cond_signal_all(u32 cond_id); s32 sys_cond_signal_all(u32 cond_id);
s32 sys_cond_signal_to(u32 cond_id, u32 thread_id); s32 sys_cond_signal_to(u32 cond_id, u32 thread_id);

View File

@ -3,11 +3,10 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_process.h" #include "sys_process.h"
#include "sys_event.h" #include "sys_event.h"
@ -88,19 +87,19 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode)
u32 tid = GetCurrentPPUThread().GetId(); u32 tid = GetCurrentPPUThread().GetId();
eq->sq.m_mutex.lock(); eq->sq.m_mutex.lock();
eq->owner.lock(tid); //eq->owner.lock(tid);
// check if some threads are waiting for an event // check if some threads are waiting for an event
if (!mode && eq->sq.list.size()) if (!mode && eq->sq.list.size())
{ {
eq->owner.unlock(tid); //eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(); eq->sq.m_mutex.unlock();
return CELL_EBUSY; return CELL_EBUSY;
} }
eq->owner.unlock(tid, ~0); //eq->owner.unlock(tid, ~0);
eq->sq.m_mutex.unlock(); eq->sq.m_mutex.unlock();
while (eq->sq.list.size()) while (eq->sq.list.size())
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id); sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id);
@ -140,16 +139,16 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_data> event_arra
u32 tid = GetCurrentPPUThread().GetId(); u32 tid = GetCurrentPPUThread().GetId();
eq->sq.m_mutex.lock(); eq->sq.m_mutex.lock();
eq->owner.lock(tid); //eq->owner.lock(tid);
if (eq->sq.list.size()) if (eq->sq.list.size())
{ {
*number = 0; *number = 0;
eq->owner.unlock(tid); //eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(); eq->sq.m_mutex.unlock();
return CELL_OK; return CELL_OK;
} }
*number = eq->events.pop_all(event_array.get_ptr(), size); *number = eq->events.pop_all(event_array.get_ptr(), size);
eq->owner.unlock(tid); //eq->owner.unlock(tid);
eq->sq.m_mutex.unlock(); eq->sq.m_mutex.unlock();
return CELL_OK; return CELL_OK;
} }
@ -173,34 +172,38 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr<sys_event_data> dummy_event,
u32 tid = GetCurrentPPUThread().GetId(); u32 tid = GetCurrentPPUThread().GetId();
eq->sq.push(tid); // add thread to sleep queue eq->sq.push(tid, eq->protocol); // add thread to sleep queue
timeout = timeout ? (timeout / 1000) : ~0; timeout = timeout ? (timeout / 1000) : ~0;
u64 counter = 0; u64 counter = 0;
while (true) while (true)
{ {
switch (eq->owner.trylock(tid)) u32 old_owner = eq->owner.compare_and_swap(0, tid);
const s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0;
switch (res)
{ {
case SMR_OK: case 0:
if (!eq->events.count())
{ {
eq->owner.unlock(tid); const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0;
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid) if (next != tid)
{ {
eq->owner.unlock(tid, next); if (!eq->owner.compare_and_swap_test(tid, next))
{
assert(!"sys_event_queue_receive() failed (I)");
}
break; break;
} }
// fallthrough
} }
case SMR_SIGNAL: case 1:
{ {
sys_event_data event; sys_event_data event;
eq->events.pop(event); eq->events.pop(event);
eq->owner.unlock(tid); if (!eq->owner.compare_and_swap_test(tid, 0))
{
assert(!"sys_event_queue_receive() failed (II)");
}
sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx",
(u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3); (u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3);
/* passing event data in registers */ /* passing event data in registers */
@ -211,11 +214,15 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr<sys_event_data> dummy_event,
t.GPR[7] = event.data3; t.GPR[7] = event.data3;
return CELL_OK; return CELL_OK;
} }
case SMR_FAILED: break;
default: eq->sq.invalidate(tid); return CELL_ECANCELED;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (!~old_owner)
{
eq->sq.invalidate(tid);
return CELL_ECANCELED;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (counter++ > timeout || Emu.IsStopped()) if (counter++ > timeout || Emu.IsStopped())
{ {
if (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); if (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id);

View File

@ -1,8 +1,5 @@
#pragma once #pragma once
//#include "sys_lwmutex.h"
//#include "Utilities/SMutex.h"
#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL) #define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL)
// arbitrary code to prevent "special" zero value in key argument // arbitrary code to prevent "special" zero value in key argument
@ -192,10 +189,10 @@ public:
struct EventQueue struct EventQueue
{ {
SleepQueue sq; sleep_queue_t sq;
EventPortList ports; EventPortList ports;
EventRingBuffer events; EventRingBuffer events;
SMutex owner; atomic_le_t<u32> owner;
const union const union
{ {
@ -213,7 +210,7 @@ struct EventQueue
, key(key) , key(key)
, events(size) // size: max event count this queue can hold , events(size) // size: max event count this queue can hold
{ {
owner.initialize(); owner.write_relaxed(0);
} }
}; };

View File

@ -3,26 +3,27 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_event_flag.h" #include "sys_event_flag.h"
SysCallBase sys_event_flag("sys_event_flag"); SysCallBase sys_event_flag("sys_event_flag");
u32 EventFlag::check() u32 EventFlag::check()
{ {
SleepQueue sq; // TODO: implement without SleepQueue sleep_queue_t sq; // TODO: implement without sleep queue
u32 target = 0; u32 target = 0;
const u64 flag_set = flags.read_sync();
for (u32 i = 0; i < waiters.size(); i++) for (u32 i = 0; i < waiters.size(); i++)
{ {
if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) || if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & waiters[i].bitptn) == waiters[i].bitptn) ||
((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn))) ((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & waiters[i].bitptn)))
{ {
if (m_protocol == SYS_SYNC_FIFO) if (protocol == SYS_SYNC_FIFO)
{ {
target = waiters[i].tid; target = waiters[i].tid;
break; break;
@ -31,8 +32,8 @@ u32 EventFlag::check()
} }
} }
if (m_protocol == SYS_SYNC_PRIORITY) if (protocol == SYS_SYNC_PRIORITY)
target = sq.pop_prio(); target = sq.pop(SYS_SYNC_PRIORITY);
return target; return target;
} }
@ -126,12 +127,13 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
const u32 tid = GetCurrentPPUThread().GetId(); const u32 tid = GetCurrentPPUThread().GetId();
{ {
ef->m_mutex.lock(tid); std::lock_guard<std::mutex> lock(ef->mutex);
if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
if (ef->type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
{ {
ef->m_mutex.unlock(tid);
return CELL_EPERM; return CELL_EPERM;
} }
EventFlagWaiter rec; EventFlagWaiter rec;
rec.bitptn = bitptn; rec.bitptn = bitptn;
rec.mode = mode; rec.mode = mode;
@ -140,7 +142,7 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
if (ef->check() == tid) if (ef->check() == tid)
{ {
u64 flags = ef->flags; const u64 flag_set = ef->flags.read_sync();
ef->waiters.erase(ef->waiters.end() - 1); ef->waiters.erase(ef->waiters.end() - 1);
@ -150,15 +152,15 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
} }
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{ {
ef->flags = 0; ef->flags &= 0;
} }
if (result) *result = flags; if (result)
{
ef->m_mutex.unlock(tid); *result = flag_set;
}
return CELL_OK; return CELL_OK;
} }
ef->m_mutex.unlock(tid);
} }
u64 counter = 0; u64 counter = 0;
@ -166,10 +168,14 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
while (true) while (true)
{ {
if (ef->signal.unlock(tid, tid) == SMR_OK) u32 signaled;
if (ef->signal.Peek(signaled, &sq_no_wait) && signaled == tid)
{ {
ef->m_mutex.lock(tid); std::lock_guard<std::mutex> lock(ef->mutex);
u64 flags = ef->flags;
const u64 flag_set = ef->flags.read_sync();
ef->signal.Pop(signaled, nullptr);
for (u32 i = 0; i < ef->waiters.size(); i++) for (u32 i = 0; i < ef->waiters.size(); i++)
{ {
@ -183,37 +189,30 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
} }
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{ {
ef->flags = 0; ef->flags &= 0;
} }
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.Push(target, nullptr);
ef->signal.unlock(tid, target);
ef->m_mutex.unlock(tid, target);
} }
else
if (result)
{ {
ef->signal.unlock(tid); *result = flag_set;
} }
if (result) *result = flags;
ef->m_mutex.unlock(tid);
return CELL_OK; return CELL_OK;
} }
} }
ef->signal.unlock(tid);
ef->m_mutex.unlock(tid);
return CELL_ECANCELED; return CELL_ECANCELED;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (counter++ > max_counter) if (counter++ > max_counter)
{ {
ef->m_mutex.lock(tid); std::lock_guard<std::mutex> lock(ef->mutex);
for (u32 i = 0; i < ef->waiters.size(); i++) for (u32 i = 0; i < ef->waiters.size(); i++)
{ {
@ -223,10 +222,9 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> result,
break; break;
} }
} }
ef->m_mutex.unlock(tid);
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id); sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id);
@ -260,13 +258,12 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> resu
EventFlag* ef; EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
u64 flags = ef->flags; const u64 flag_set = ef->flags.read_sync();
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) || if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & bitptn) == bitptn) ||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn))) ((mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & bitptn)))
{ {
if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) if (mode & SYS_EVENT_FLAG_WAIT_CLEAR)
{ {
@ -274,16 +271,17 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr<u64> resu
} }
else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL)
{ {
ef->flags = 0; ef->flags &= 0;
} }
if (result) *result = flags; if (result)
{
*result = flag_set;
}
ef->m_mutex.unlock(tid);
return CELL_OK; return CELL_OK;
} }
ef->m_mutex.unlock(tid);
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -294,21 +292,13 @@ s32 sys_event_flag_set(u32 eflag_id, u64 bitptn)
EventFlag* ef; EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
u32 tid = GetCurrentPPUThread().GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= bitptn; ef->flags |= bitptn;
if (u32 target = ef->check()) if (u32 target = ef->check())
{ {
// if signal, leave both mutexes locked... ef->signal.Push(target, nullptr);
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
} }
else
{
ef->m_mutex.unlock(tid);
}
return CELL_OK; return CELL_OK;
} }
@ -319,10 +309,8 @@ s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn)
EventFlag* ef; EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId(); std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags &= bitptn; ef->flags &= bitptn;
ef->m_mutex.unlock(tid);
return CELL_OK; return CELL_OK;
} }
@ -334,23 +322,20 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr<u32> num)
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
std::vector<u32> tids; std::vector<u32> tids;
const u32 tid = GetCurrentPPUThread().GetId();
{ {
ef->m_mutex.lock(tid); std::lock_guard<std::mutex> lock(ef->mutex);
tids.resize(ef->waiters.size()); tids.resize(ef->waiters.size());
for (u32 i = 0; i < ef->waiters.size(); i++) for (u32 i = 0; i < ef->waiters.size(); i++)
{ {
tids[i] = ef->waiters[i].tid; tids[i] = ef->waiters[i].tid;
} }
ef->waiters.clear(); ef->waiters.clear();
ef->m_mutex.unlock(tid);
} }
for (u32 i = 0; i < tids.size(); i++) for (u32 i = 0; i < tids.size(); i++)
{ {
ef->signal.lock(tids[i]); ef->signal.Push(tids[i], nullptr);
} }
if (Emu.IsStopped()) if (Emu.IsStopped())
@ -359,7 +344,10 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr<u32> num)
return CELL_OK; return CELL_OK;
} }
if (num) *num = (u32)tids.size(); if (num)
{
*num = (u32)tids.size();
}
return CELL_OK; return CELL_OK;
} }
@ -377,9 +365,6 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr<u64> flags)
EventFlag* ef; EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId(); *flags = ef->flags.read_sync();
ef->m_mutex.lock(tid);
*flags = ef->flags;
ef->m_mutex.unlock(tid);
return CELL_OK; return CELL_OK;
} }

View File

@ -31,20 +31,18 @@ struct EventFlagWaiter
struct EventFlag struct EventFlag
{ {
SMutex m_mutex; atomic_le_t<u64> flags;
u64 flags; SQueue<u32, 32> signal;
std::mutex mutex; // protects waiters
std::vector<EventFlagWaiter> waiters; std::vector<EventFlagWaiter> waiters;
SMutex signal; const u32 protocol;
const u32 m_protocol; const int type;
const int m_type;
EventFlag(u64 pattern, u32 protocol, int type) EventFlag(u64 pattern, u32 protocol, int type)
: flags(pattern) : protocol(protocol)
, m_protocol(protocol) , type(type)
, m_type(type)
{ {
m_mutex.initialize(); flags.write_relaxed(pattern);
signal.initialize();
} }
u32 check(); u32 check();

View File

@ -3,9 +3,11 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h" #include "Utilities/SQueue.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_lwmutex.h" #include "sys_lwmutex.h"
#include "sys_lwcond.h" #include "sys_lwcond.h"
@ -52,7 +54,7 @@ s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!lw->m_queue.finalize()) if (!lw->queue.finalize())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -74,9 +76,9 @@ s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond)
auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr());
if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) if (u32 target = lw->queue.pop(mutex->attribute))
{ {
lw->signal.lock(target); lw->signal.Push(target, nullptr);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -100,9 +102,9 @@ s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond)
auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr());
while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) while (u32 target = lw->queue.pop(mutex->attribute))
{ {
lw->signal.lock(target); lw->signal.Push(target, nullptr);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -129,14 +131,14 @@ s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!lw->m_queue.invalidate(ppu_thread_id)) if (!lw->queue.invalidate(ppu_thread_id))
{ {
return CELL_EPERM; return CELL_EPERM;
} }
u32 target = ppu_thread_id; u32 target = ppu_thread_id;
{ {
lw->signal.lock(target); lw->signal.Push(target, nullptr);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -148,7 +150,7 @@ s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_OK; return CELL_OK;
} }
s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout) s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
{ {
sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout);
@ -159,10 +161,10 @@ s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
} }
auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr()); auto mutex = vm::ptr<sys_lwmutex_t>::make(lwcond->lwmutex.addr());
u32 tid_le = GetCurrentPPUThread().GetId(); u32 tid_le = CPU.GetId();
be_t<u32> tid = be_t<u32>::make(tid_le); be_t<u32> tid = be_t<u32>::make(tid_le);
SleepQueue* sq = nullptr; sleep_queue_t* sq = nullptr;
if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq) && mutex->attribute.ToBE() != se32(SYS_SYNC_RETRY)) if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq) && mutex->attribute.ToBE() != se32(SYS_SYNC_RETRY))
{ {
sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)", sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)",
@ -170,60 +172,89 @@ s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
return CELL_ESRCH; return CELL_ESRCH;
} }
auto old_owner = mutex->mutex.read_sync(); if (mutex->owner.read_sync() != tid)
if (old_owner != tid)
{ {
sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue); return CELL_EPERM;
return CELL_EPERM; // caller must own this lwmutex
} }
lw->m_queue.push(tid_le); lw->queue.push(tid_le, mutex->attribute);
auto old_recursive = mutex->recursive_count; auto old_recursive = mutex->recursive_count;
mutex->recursive_count = 0; mutex->recursive_count = 0;
be_t<u32> target = sq ? (be_t<u32>::make(mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())) : be_t<u32>::make(0); be_t<u32> target = be_t<u32>::make(sq->pop(mutex->attribute));
if (!mutex->mutex.compare_and_swap_test(tid, target)) if (!mutex->owner.compare_and_swap_test(tid, target))
{ {
assert(!"sys_lwcond_wait(): mutex unlocking failed"); assert(!"sys_lwcond_wait(): mutex unlocking failed");
} }
u64 counter = 0; const u64 time_start = get_system_time();
const u64 max_counter = timeout ? (timeout / 1000) : ~0;
while (true) while (true)
{ {
if (lw->signal.unlock(tid, tid) == SMR_OK) u32 signaled;
if (lw->signal.Peek(signaled, &sq_no_wait) && signaled == tid_le) // check signaled threads
{ {
switch (mutex->lock(tid, 0)) s32 res = mutex->lock(tid, timeout ? get_system_time() - time_start : 0); // this is bad
if (res == CELL_OK)
{ {
case CELL_OK: break; break;
case static_cast<int>(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked",
(u32)lwcond->lwcond_queue); return CELL_OK;
case static_cast<int>(CELL_ESRCH): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)",
(u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH;
case static_cast<int>(CELL_EINVAL): goto abort;
} }
mutex->recursive_count = old_recursive; switch (res)
lw->signal.unlock(tid);
return CELL_OK;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (counter++ > max_counter)
{ {
lw->m_queue.invalidate(tid_le); case static_cast<int>(CELL_EDEADLK):
return CELL_ETIMEDOUT; {
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue);
lw->queue.invalidate(tid_le);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_OK; // mutex not locked (but already locked in the incorrect way)
} }
case static_cast<int>(CELL_ESRCH):
{
sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
lw->queue.invalidate(tid_le);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_ESRCH; // mutex not locked
}
case static_cast<int>(CELL_ETIMEDOUT):
{
lw->queue.invalidate(tid_le);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_ETIMEDOUT; // mutex not locked
}
case static_cast<int>(CELL_EINVAL):
{
sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue);
lw->queue.invalidate(tid_le);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_EINVAL; // mutex not locked
}
default:
{
sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res);
lw->queue.invalidate(tid_le);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_EINVAL; // mutex not locked
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (timeout && get_system_time() - time_start > timeout)
{
lw->queue.invalidate(tid_le);
return CELL_ETIMEDOUT; // mutex not locked
}
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
goto abort;
}
}
abort:
sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK; return CELL_OK;
} }
}
mutex->recursive_count = old_recursive;
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_OK;
}

View File

@ -19,23 +19,24 @@ struct sys_lwcond_t
struct Lwcond struct Lwcond
{ {
SMutex signal; SQueue<u32, 32> signal;
SleepQueue m_queue; sleep_queue_t queue;
Lwcond(u64 name) Lwcond(u64 name)
: m_queue(name) : queue(name)
{ {
signal.initialize();
} }
}; };
// Aux // Aux
s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64); s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64);
class PPUThread;
// SysCalls // SysCalls
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr); s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond); s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond); s32 sys_lwcond_signal(vm::ptr<sys_lwcond_t> lwcond);
s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond); s32 sys_lwcond_signal_all(vm::ptr<sys_lwcond_t> lwcond);
s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id); s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
s32 sys_lwcond_wait(vm::ptr<sys_lwcond_t> lwcond, u64 timeout); s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);

View File

@ -6,33 +6,32 @@
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sleep_queue_type.h"
#include "sys_time.h" #include "sys_time.h"
#include "sys_lwmutex.h" #include "sys_lwmutex.h"
SysCallBase sys_lwmutex("sys_lwmutex"); SysCallBase sys_lwmutex("sys_lwmutex");
// TODO: move SleepQueue somewhere
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64)
{ {
LV2_LOCK(0); LV2_LOCK(0);
lwmutex.mutex.write_relaxed(be_t<u32>::make(0)); lwmutex.owner.write_relaxed(be_t<u32>::make(0));
lwmutex.waiter.write_relaxed(be_t<u32>::make(~0)); lwmutex.waiter.write_relaxed(be_t<u32>::make(~0));
lwmutex.attribute = protocol | recursive; lwmutex.attribute = protocol | recursive;
lwmutex.recursive_count = 0; lwmutex.recursive_count = 0;
u32 sq_id = sys_lwmutex.GetNewId(new SleepQueue(name_u64), TYPE_LWMUTEX); u32 sq_id = sys_lwmutex.GetNewId(new sleep_queue_t(name_u64), TYPE_LWMUTEX);
lwmutex.sleep_queue = sq_id; lwmutex.sleep_queue = sq_id;
std::string name((const char*)&name_u64, 8); std::string name((const char*)&name_u64, 8);
sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", name.c_str(), protocol | recursive, sq_id); sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", name.c_str(), protocol | recursive, sq_id);
Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, GetCurrentPPUThread().GetId()); Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, 0);
return CELL_OK; return CELL_OK;
} }
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr) s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
{ {
sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr());
@ -55,7 +54,7 @@ s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attri
return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64); return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64);
} }
s32 sys_lwmutex_destroy(vm::ptr<sys_lwmutex_t> lwmutex) s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
{ {
sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr());
@ -77,156 +76,42 @@ s32 sys_lwmutex_destroy(vm::ptr<sys_lwmutex_t> lwmutex)
} }
} }
s32 sys_lwmutex_lock(vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout) s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
{ {
sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout); sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout);
return lwmutex->lock(be_t<u32>::make(GetCurrentPPUThread().GetId()), timeout); return lwmutex->lock(be_t<u32>::make(CPU.GetId()), timeout);
} }
s32 sys_lwmutex_trylock(vm::ptr<sys_lwmutex_t> lwmutex) s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
{ {
sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr()); sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr());
return lwmutex->trylock(be_t<u32>::make(GetCurrentPPUThread().GetId())); return lwmutex->trylock(be_t<u32>::make(CPU.GetId()));
} }
s32 sys_lwmutex_unlock(vm::ptr<sys_lwmutex_t> lwmutex) s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex)
{ {
sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr()); sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr());
return lwmutex->unlock(be_t<u32>::make(GetCurrentPPUThread().GetId())); return lwmutex->unlock(be_t<u32>::make(CPU.GetId()));
}
void SleepQueue::push(u32 tid)
{
std::lock_guard<std::mutex> lock(m_mutex);
list.push_back(tid);
}
u32 SleepQueue::pop() // SYS_SYNC_FIFO
{
std::lock_guard<std::mutex> lock(m_mutex);
while (true)
{
if (list.size())
{
u32 res = list[0];
list.erase(list.begin());
if (res && Emu.GetIdManager().CheckID(res))
// check thread
{
return res;
}
}
return 0;
};
}
u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY
{
std::lock_guard<std::mutex> lock(m_mutex);
while (true)
{
if (list.size())
{
u64 highest_prio = ~0ull;
u32 sel = 0;
for (u32 i = 0; i < list.size(); i++)
{
CPUThread* t = Emu.GetCPU().GetThread(list[i]);
if (!t)
{
list[i] = 0;
sel = i;
break;
}
u64 prio = t->GetPrio();
if (prio < highest_prio)
{
highest_prio = prio;
sel = i;
}
}
u32 res = list[sel];
list.erase(list.begin() + sel);
/* if (Emu.GetIdManager().CheckID(res)) */
if (res)
// check thread
{
return res;
}
}
return 0;
}
}
u32 SleepQueue::pop_prio_inherit() // (TODO)
{
sys_lwmutex.Error("TODO: SleepQueue::pop_prio_inherit()");
Emu.Pause();
return 0;
}
bool SleepQueue::invalidate(u32 tid)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (tid) for (u32 i = 0; i < list.size(); i++)
{
if (list[i] == tid)
{
list.erase(list.begin() + i);
return true;
}
}
return false;
}
u32 SleepQueue::count()
{
std::lock_guard<std::mutex> lock(m_mutex);
u32 result = 0;
for (u32 i = 0; i < list.size(); i++)
{
if (list[i]) result++;
}
return result;
}
bool SleepQueue::finalize()
{
if (!m_mutex.try_lock()) return false;
for (u32 i = 0; i < list.size(); i++)
{
if (list[i])
{
m_mutex.unlock();
return false;
}
}
m_mutex.unlock();
return true;
} }
s32 sys_lwmutex_t::trylock(be_t<u32> tid) s32 sys_lwmutex_t::trylock(be_t<u32> tid)
{ {
if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL;
be_t<u32> owner_tid = mutex.read_sync(); const be_t<u32> old_owner = owner.read_sync();
if (tid == owner_tid) if (old_owner == tid)
{ {
if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE))
{ {
recursive_count += 1; recursive_count += 1;
if (!recursive_count.ToBE()) return CELL_EKRESOURCE; if (!recursive_count.ToBE())
{
return CELL_EKRESOURCE;
}
return CELL_OK; return CELL_OK;
} }
else else
@ -235,7 +120,7 @@ s32 sys_lwmutex_t::trylock(be_t<u32> tid)
} }
} }
if (!mutex.compare_and_swap_test(be_t<u32>::make(0), tid)) if (!owner.compare_and_swap_test(be_t<u32>::make(0), tid))
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -246,12 +131,11 @@ s32 sys_lwmutex_t::trylock(be_t<u32> tid)
s32 sys_lwmutex_t::unlock(be_t<u32> tid) s32 sys_lwmutex_t::unlock(be_t<u32> tid)
{ {
if (mutex.read_sync() != tid) if (owner.read_sync() != tid)
{ {
return CELL_EPERM; return CELL_EPERM;
} }
else
{
if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE))))
{ {
sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)recursive_count); sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)recursive_count);
@ -261,23 +145,13 @@ s32 sys_lwmutex_t::unlock(be_t<u32> tid)
recursive_count -= 1; recursive_count -= 1;
if (!recursive_count.ToBE()) if (!recursive_count.ToBE())
{ {
be_t<u32> target = be_t<u32>::make(0); sleep_queue_t* sq;
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
{
case se32(SYS_SYNC_FIFO):
case se32(SYS_SYNC_PRIORITY):
{
SleepQueue* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
target = attribute & SYS_SYNC_FIFO ? sq->pop() : sq->pop_prio(); if (!owner.compare_and_swap_test(tid, be_t<u32>::make(sq->pop(attribute))))
}
}
if (!mutex.compare_and_swap_test(tid, target))
{ {
assert(!"sys_lwmutex_t::unlock() failed"); assert(!"sys_lwmutex_t::unlock() failed");
} }
@ -285,7 +159,6 @@ s32 sys_lwmutex_t::unlock(be_t<u32> tid)
return CELL_OK; return CELL_OK;
} }
}
s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout) s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
{ {
@ -295,25 +168,18 @@ s32 sys_lwmutex_t::lock(be_t<u32> tid, u64 timeout)
default: return res; default: return res;
} }
SleepQueue* sq; sleep_queue_t* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) sq->push(tid, attribute);
{
case se32(SYS_SYNC_PRIORITY):
case se32(SYS_SYNC_FIFO):
{
sq->push(tid);
}
}
const u64 time_start = get_system_time(); const u64 time_start = get_system_time();
while (true) while (true)
{ {
auto old_owner = mutex.compare_and_swap(be_t<u32>::make(0), tid); auto old_owner = owner.compare_and_swap(be_t<u32>::make(0), tid);
if (!old_owner.ToBE()) if (!old_owner.ToBE())
{ {
sq->invalidate(tid); sq->invalidate(tid);

View File

@ -1,31 +1,5 @@
#pragma once #pragma once
// attr_protocol (waiting scheduling policy)
enum
{
// First In, First Out
SYS_SYNC_FIFO = 1,
// Priority Order
SYS_SYNC_PRIORITY = 2,
// Basic Priority Inheritance Protocol (probably not implemented)
SYS_SYNC_PRIORITY_INHERIT = 3,
// Not selected while unlocking
SYS_SYNC_RETRY = 4,
//
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
};
// attr_recursive (recursive locks policy)
enum
{
// Recursive locks are allowed
SYS_SYNC_RECURSIVE = 0x10,
// Recursive locks are NOT allowed
SYS_SYNC_NOT_RECURSIVE = 0x20,
//
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
};
struct sys_lwmutex_attribute_t struct sys_lwmutex_attribute_t
{ {
be_t<u32> protocol; be_t<u32> protocol;
@ -37,35 +11,9 @@ struct sys_lwmutex_attribute_t
}; };
}; };
struct SleepQueue
{
/* struct q_rec
{
u32 tid;
u64 prio;
q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {}
}; */
std::vector<u32> list;
std::mutex m_mutex;
u64 m_name;
SleepQueue(u64 name = 0)
: m_name(name)
{
}
void push(u32 tid);
u32 pop(); // SYS_SYNC_FIFO
u32 pop_prio(); // SYS_SYNC_PRIORITY
u32 pop_prio_inherit(); // (TODO)
bool invalidate(u32 tid);
u32 count();
bool finalize();
};
struct sys_lwmutex_t struct sys_lwmutex_t
{ {
atomic_t<u32> mutex; atomic_t<u32> owner;
atomic_t<u32> waiter; // currently not used atomic_t<u32> waiter; // currently not used
be_t<u32> attribute; be_t<u32> attribute;
be_t<u32> recursive_count; be_t<u32> recursive_count;
@ -85,9 +33,11 @@ struct sys_lwmutex_t
// Aux // Aux
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64);
class PPUThread;
// SysCalls // SysCalls
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr); s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
s32 sys_lwmutex_destroy(vm::ptr<sys_lwmutex_t> lwmutex); s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_lock(vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout); s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
s32 sys_lwmutex_trylock(vm::ptr<sys_lwmutex_t> lwmutex); s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_unlock(vm::ptr<sys_lwmutex_t> lwmutex); s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);

View File

@ -3,33 +3,36 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_mutex.h" #include "sys_mutex.h"
SysCallBase sys_mutex("sys_mutex"); SysCallBase sys_mutex("sys_mutex");
Mutex::~Mutex() Mutex::~Mutex()
{ {
if (u32 owner = m_mutex.GetOwner()) if (u32 tid = owner.read_sync())
{ {
sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, owner, recursive); sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, tid, recursive);
} }
if (!m_queue.m_mutex.try_lock()) return; if (!queue.m_mutex.try_lock()) return;
for (u32 i = 0; i < m_queue.list.size(); i++) for (u32 i = 0; i < queue.list.size(); i++)
{ {
if (u32 owner = m_queue.list[i]) sys_mutex.Notice("Mutex(%d) was waited by thread %d", id, owner); if (u32 owner = queue.list[i])
{
sys_mutex.Notice("Mutex(%d) was waited by thread %d", id, owner);
}
} }
m_queue.m_mutex.unlock(); queue.m_mutex.unlock();
} }
s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr) s32 sys_mutex_create(PPUThread& CPU, vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr)
{ {
sys_mutex.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.addr(), attr.addr()); sys_mutex.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.addr(), attr.addr());
@ -58,13 +61,10 @@ s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr)
return CELL_EINVAL; return CELL_EINVAL;
} }
u32 tid = GetCurrentPPUThread().GetId();
Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64); Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64);
u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); const u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX);
mutex->m_mutex.lock(tid); mutex->id.exchange(id);
mutex->id = id;
*mutex_id = id; *mutex_id = id;
mutex->m_mutex.unlock(tid);
sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d",
std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), id); std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), id);
@ -74,7 +74,7 @@ s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr)
return CELL_OK; return CELL_OK;
} }
s32 sys_mutex_destroy(u32 mutex_id) s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id)
{ {
sys_mutex.Warning("sys_mutex_destroy(mutex_id=%d)", mutex_id); sys_mutex.Warning("sys_mutex_destroy(mutex_id=%d)", mutex_id);
@ -91,26 +91,32 @@ s32 sys_mutex_destroy(u32 mutex_id)
return CELL_EPERM; return CELL_EPERM;
} }
u32 tid = GetCurrentPPUThread().GetId(); const u32 tid = CPU.GetId();
if (mutex->m_mutex.trylock(tid)) // check if locked if (mutex->owner.compare_and_swap_test(0, tid)) // check if locked
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
if (!mutex->m_queue.finalize()) if (!mutex->queue.finalize())
{ {
mutex->m_mutex.unlock(tid); if (!mutex->owner.compare_and_swap_test(tid, 0))
{
assert(!"sys_mutex_destroy() failed (busy)");
}
return CELL_EBUSY; return CELL_EBUSY;
} }
mutex->m_mutex.unlock(tid, ~0); if (!mutex->owner.compare_and_swap_test(tid, ~0))
{
assert(!"sys_mutex_destroy() failed");
}
Emu.GetIdManager().RemoveID(mutex_id); Emu.GetIdManager().RemoveID(mutex_id);
Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_MUTEX, mutex_id); Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_MUTEX, mutex_id);
return CELL_OK; return CELL_OK;
} }
s32 sys_mutex_lock(u32 mutex_id, u64 timeout) s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
{ {
sys_mutex.Log("sys_mutex_lock(mutex_id=%d, timeout=%lld)", mutex_id, timeout); sys_mutex.Log("sys_mutex_lock(mutex_id=%d, timeout=%lld)", mutex_id, timeout);
@ -120,14 +126,13 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_ESRCH; return CELL_ESRCH;
} }
PPUThread& t = GetCurrentPPUThread(); const u32 tid = CPU.GetId();
u32 tid = t.GetId();
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) if (mutex->owner.read_sync() == tid)
{ {
if (mutex->is_recursive) if (mutex->is_recursive)
{ {
if (++mutex->recursive == 0) if (!++mutex->recursive)
{ {
return CELL_EKRESOURCE; return CELL_EKRESOURCE;
} }
@ -138,48 +143,51 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_EDEADLK; return CELL_EDEADLK;
} }
} }
else if (u32 owner = mutex->m_mutex.GetOwner())
if (mutex->owner.compare_and_swap_test(0, tid))
{ {
if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) mutex->recursive = 1;
{ CPU.owned_mutexes++;
} return CELL_OK;
else
{
sys_mutex.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
}
} }
switch (mutex->m_mutex.trylock(tid)) mutex->queue.push(tid, mutex->protocol);
const u64 time_start = get_system_time();
while (true)
{ {
case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; auto old_owner = mutex->owner.compare_and_swap(0, tid);
case SMR_FAILED: break; if (!old_owner)
default: goto abort; {
mutex->queue.invalidate(tid);
break;
}
if (old_owner == tid)
{
break;
} }
mutex->m_queue.push(tid); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
switch (mutex->m_mutex.lock(tid, timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0)) if (timeout && get_system_time() - time_start > timeout)
{ {
case SMR_OK: mutex->queue.invalidate(tid);
mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT;
case SMR_SIGNAL:
mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
case SMR_TIMEOUT:
mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT;
default:
mutex->m_queue.invalidate(tid); goto abort;
} }
abort:
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id); sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id);
return CELL_OK; return CELL_OK;
} }
return CELL_ESRCH;
} }
s32 sys_mutex_trylock(u32 mutex_id) mutex->recursive = 1;
CPU.owned_mutexes++;
return CELL_OK;
}
s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id)
{ {
sys_mutex.Log("sys_mutex_trylock(mutex_id=%d)", mutex_id); sys_mutex.Log("sys_mutex_trylock(mutex_id=%d)", mutex_id);
@ -189,14 +197,13 @@ s32 sys_mutex_trylock(u32 mutex_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
PPUThread& t = GetCurrentPPUThread(); const u32 tid = CPU.GetId();
u32 tid = t.GetId();
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) if (mutex->owner.read_sync() == tid)
{ {
if (mutex->is_recursive) if (mutex->is_recursive)
{ {
if (++mutex->recursive == 0) if (!++mutex->recursive)
{ {
return CELL_EKRESOURCE; return CELL_EKRESOURCE;
} }
@ -207,25 +214,18 @@ s32 sys_mutex_trylock(u32 mutex_id)
return CELL_EDEADLK; return CELL_EDEADLK;
} }
} }
else if (u32 owner = mutex->m_mutex.GetOwner())
if (!mutex->owner.compare_and_swap_test(0, tid))
{ {
if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) return CELL_EBUSY;
{
}
else
{
sys_mutex.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
}
} }
switch (mutex->m_mutex.trylock(tid)) mutex->recursive = 1;
{ CPU.owned_mutexes++;
case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; return CELL_OK;
default: return CELL_EBUSY;
}
} }
s32 sys_mutex_unlock(u32 mutex_id) s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id)
{ {
sys_mutex.Log("sys_mutex_unlock(mutex_id=%d)", mutex_id); sys_mutex.Log("sys_mutex_unlock(mutex_id=%d)", mutex_id);
@ -235,24 +235,26 @@ s32 sys_mutex_unlock(u32 mutex_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
PPUThread& t = GetCurrentPPUThread(); const u32 tid = CPU.GetId();
u32 tid = t.GetId();
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) if (mutex->owner.read_sync() != tid)
{ {
return CELL_EPERM;
}
if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive)) if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive))
{ {
sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive); sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive);
mutex->recursive = 1; mutex->recursive = 1;
} }
mutex->recursive--;
if (!mutex->recursive) if (!--mutex->recursive)
{ {
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol)))
t.owned_mutexes--; {
assert(!"sys_mutex_unlock() failed");
}
CPU.owned_mutexes--;
} }
return CELL_OK; return CELL_OK;
} }
return CELL_EPERM;
}

View File

@ -18,9 +18,9 @@ struct sys_mutex_attribute
struct Mutex struct Mutex
{ {
u32 id; atomic_le_t<u32> id;
SMutex m_mutex; atomic_le_t<u32> owner;
SleepQueue m_queue; sleep_queue_t queue;
u32 recursive; // recursive locks count u32 recursive; // recursive locks count
std::atomic<u32> cond_count; // count of condition variables associated std::atomic<u32> cond_count; // count of condition variables associated
@ -30,18 +30,20 @@ struct Mutex
Mutex(u32 protocol, bool is_recursive, u64 name) Mutex(u32 protocol, bool is_recursive, u64 name)
: protocol(protocol) : protocol(protocol)
, is_recursive(is_recursive) , is_recursive(is_recursive)
, m_queue(name) , queue(name)
, cond_count(0) , cond_count(0)
{ {
m_mutex.initialize(); owner.write_relaxed(0);
} }
~Mutex(); ~Mutex();
}; };
class PPUThread;
// SysCalls // SysCalls
s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr); s32 sys_mutex_create(PPUThread& CPU, vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr);
s32 sys_mutex_destroy(u32 mutex_id); s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id);
s32 sys_mutex_lock(u32 mutex_id, u64 timeout); s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout);
s32 sys_mutex_trylock(u32 mutex_id); s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id);
s32 sys_mutex_unlock(u32 mutex_id); s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id);

View File

@ -43,7 +43,7 @@ s32 sys_ppu_thread_yield()
{ {
sys_ppu_thread.Log("sys_ppu_thread_yield()"); sys_ppu_thread.Log("sys_ppu_thread_yield()");
// Note: Or do we actually want to yield? // Note: Or do we actually want to yield?
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
return CELL_OK; return CELL_OK;
} }
@ -61,7 +61,7 @@ s32 sys_ppu_thread_join(u64 thread_id, vm::ptr<u64> vptr)
sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id); sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id);
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
*vptr = thr->GetExitStatus(); *vptr = thr->GetExitStatus();

View File

@ -5,7 +5,7 @@
#include "Emu/Memory/atomic_type.h" #include "Emu/Memory/atomic_type.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_rwlock.h" #include "sys_rwlock.h"
SysCallBase sys_rwlock("sys_rwlock"); SysCallBase sys_rwlock("sys_rwlock");
@ -76,7 +76,7 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, ...) aborted", rw_lock_id); sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, ...) aborted", rw_lock_id);
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (rw->rlock_trylock(tid)) return CELL_OK; if (rw->rlock_trylock(tid)) return CELL_OK;
@ -139,7 +139,7 @@ s32 sys_rwlock_wlock(u32 rw_lock_id, u64 timeout)
sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, ...) aborted", rw_lock_id); sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, ...) aborted", rw_lock_id);
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (rw->wlock_trylock(tid, true)) return CELL_OK; if (rw->wlock_trylock(tid, true)) return CELL_OK;

View File

@ -6,7 +6,7 @@
#include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h" #include "sleep_queue_type.h"
#include "sys_time.h" #include "sys_time.h"
#include "sys_semaphore.h" #include "sys_semaphore.h"
@ -75,7 +75,7 @@ s32 sys_semaphore_destroy(u32 sem_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!sem->m_queue.finalize()) if (!sem->queue.finalize())
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -99,13 +99,13 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
const u64 start_time = get_system_time(); const u64 start_time = get_system_time();
{ {
std::lock_guard<std::mutex> lock(sem->m_mutex); std::lock_guard<std::mutex> lock(sem->mutex);
if (sem->m_value > 0) if (sem->value > 0)
{ {
sem->m_value--; sem->value--;
return CELL_OK; return CELL_OK;
} }
sem->m_queue.push(tid); sem->queue.push(tid, sem->protocol);
} }
while (true) while (true)
@ -118,13 +118,13 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
if (timeout && get_system_time() - start_time > timeout) if (timeout && get_system_time() - start_time > timeout)
{ {
sem->m_queue.invalidate(tid); sem->queue.invalidate(tid);
return CELL_ETIMEDOUT; return CELL_ETIMEDOUT;
} }
if (tid == sem->signal) if (tid == sem->signal)
{ {
std::lock_guard<std::mutex> lock(sem->m_mutex); std::lock_guard<std::mutex> lock(sem->mutex);
if (tid != sem->signal) if (tid != sem->signal)
{ {
@ -134,7 +134,7 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout)
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
} }
@ -148,11 +148,11 @@ s32 sys_semaphore_trywait(u32 sem_id)
return CELL_ESRCH; return CELL_ESRCH;
} }
std::lock_guard<std::mutex> lock(sem->m_mutex); std::lock_guard<std::mutex> lock(sem->mutex);
if (sem->m_value > 0) if (sem->value > 0)
{ {
sem->m_value--; sem->value--;
return CELL_OK; return CELL_OK;
} }
else else
@ -176,7 +176,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
return CELL_EINVAL; return CELL_EINVAL;
} }
if (count + sem->m_value - (s32)sem->m_queue.count() > sem->max) if (count + sem->value - (s32)sem->queue.count() > sem->max)
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -189,22 +189,22 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
return CELL_OK; return CELL_OK;
} }
std::lock_guard<std::mutex> lock(sem->m_mutex); std::lock_guard<std::mutex> lock(sem->mutex);
if (sem->signal && sem->m_queue.count()) if (sem->signal && sem->queue.count())
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue; continue;
} }
if (u32 target = (sem->protocol == SYS_SYNC_FIFO) ? sem->m_queue.pop() : sem->m_queue.pop_prio()) if (u32 target = sem->queue.pop(sem->protocol))
{ {
count--; count--;
sem->signal = target; sem->signal = target;
} }
else else
{ {
sem->m_value += count; sem->value += count;
count = 0; count = 0;
} }
} }
@ -227,9 +227,9 @@ s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count)
return CELL_ESRCH; return CELL_ESRCH;
} }
std::lock_guard<std::mutex> lock(sem->m_mutex); std::lock_guard<std::mutex> lock(sem->mutex);
*count = sem->m_value; *count = sem->value;
return CELL_OK; return CELL_OK;
} }

View File

@ -16,9 +16,9 @@ struct sys_semaphore_attribute
struct Semaphore struct Semaphore
{ {
std::mutex m_mutex; std::mutex mutex;
SleepQueue m_queue; sleep_queue_t queue;
s32 m_value; s32 value;
u32 signal; u32 signal;
const s32 max; const s32 max;
@ -26,7 +26,7 @@ struct Semaphore
const u64 name; const u64 name;
Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name) Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name)
: m_value(initial_count) : value(initial_count)
, signal(0) , signal(0)
, max(max_count) , max(max_count)
, protocol(protocol) , protocol(protocol)

View File

@ -504,7 +504,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id); sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id);
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
} }
} }

View File

@ -362,7 +362,6 @@ void Emulator::Stop()
m_status = Stopped; m_status = Stopped;
u32 uncounted = 0; u32 uncounted = 0;
u32 counter = 0;
while (true) while (true)
{ {
if (g_thread_count <= uncounted) if (g_thread_count <= uncounted)

View File

@ -50,7 +50,6 @@
<ClCompile Include="..\Utilities\rPlatform.cpp" /> <ClCompile Include="..\Utilities\rPlatform.cpp" />
<ClCompile Include="..\Utilities\rTime.cpp" /> <ClCompile Include="..\Utilities\rTime.cpp" />
<ClCompile Include="..\Utilities\rXml.cpp" /> <ClCompile Include="..\Utilities\rXml.cpp" />
<ClCompile Include="..\Utilities\SMutex.cpp" />
<ClCompile Include="..\Utilities\SSemaphore.cpp" /> <ClCompile Include="..\Utilities\SSemaphore.cpp" />
<ClCompile Include="..\Utilities\StrFmt.cpp" /> <ClCompile Include="..\Utilities\StrFmt.cpp" />
<ClCompile Include="..\Utilities\Thread.cpp" /> <ClCompile Include="..\Utilities\Thread.cpp" />
@ -134,6 +133,7 @@
<ClCompile Include="Emu\SysCalls\FuncList.cpp" /> <ClCompile Include="Emu\SysCalls\FuncList.cpp" />
<ClCompile Include="Emu\SysCalls\LogBase.cpp" /> <ClCompile Include="Emu\SysCalls\LogBase.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\lv2Fs.cpp" /> <ClCompile Include="Emu\SysCalls\lv2\lv2Fs.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue_type.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\sys_cond.cpp" /> <ClCompile Include="Emu\SysCalls\lv2\sys_cond.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\sys_event.cpp" /> <ClCompile Include="Emu\SysCalls\lv2\sys_event.cpp" />
<ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp" /> <ClCompile Include="Emu\SysCalls\lv2\sys_event_flag.cpp" />
@ -277,7 +277,6 @@
<ClInclude Include="..\Utilities\rXml.h" /> <ClInclude Include="..\Utilities\rXml.h" />
<ClInclude Include="..\Utilities\simpleini\ConvertUTF.h" /> <ClInclude Include="..\Utilities\simpleini\ConvertUTF.h" />
<ClInclude Include="..\Utilities\simpleini\SimpleIni.h" /> <ClInclude Include="..\Utilities\simpleini\SimpleIni.h" />
<ClInclude Include="..\Utilities\SMutex.h" />
<ClInclude Include="..\Utilities\SQueue.h" /> <ClInclude Include="..\Utilities\SQueue.h" />
<ClInclude Include="..\Utilities\SSemaphore.h" /> <ClInclude Include="..\Utilities\SSemaphore.h" />
<ClInclude Include="..\Utilities\StrFmt.h" /> <ClInclude Include="..\Utilities\StrFmt.h" />
@ -383,6 +382,7 @@
<ClInclude Include="Emu\SysCalls\ErrorCodes.h" /> <ClInclude Include="Emu\SysCalls\ErrorCodes.h" />
<ClInclude Include="Emu\SysCalls\LogBase.h" /> <ClInclude Include="Emu\SysCalls\LogBase.h" />
<ClInclude Include="Emu\SysCalls\lv2\lv2Fs.h" /> <ClInclude Include="Emu\SysCalls\lv2\lv2Fs.h" />
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue_type.h" />
<ClInclude Include="Emu\SysCalls\lv2\sys_cond.h" /> <ClInclude Include="Emu\SysCalls\lv2\sys_cond.h" />
<ClInclude Include="Emu\SysCalls\lv2\sys_event.h" /> <ClInclude Include="Emu\SysCalls\lv2\sys_event.h" />
<ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h" /> <ClInclude Include="Emu\SysCalls\lv2\sys_event_flag.h" />

View File

@ -383,9 +383,6 @@
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\Utilities\SMutex.cpp">
<Filter>Utilities</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\StrFmt.cpp"> <ClCompile Include="..\Utilities\StrFmt.cpp">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClCompile> </ClCompile>
@ -653,6 +650,9 @@
<ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp"> <ClCompile Include="Emu\ARMv7\Modules\sceLibm.cpp">
<Filter>Emu\CPU\ARMv7\Modules</Filter> <Filter>Emu\CPU\ARMv7\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\SysCalls\lv2\sleep_queue_type.cpp">
<Filter>Emu\SysCalls\lv2</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Crypto\aes.h"> <ClInclude Include="Crypto\aes.h">
@ -1009,9 +1009,6 @@
<ClInclude Include="..\Utilities\BEType.h"> <ClInclude Include="..\Utilities\BEType.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Utilities\SMutex.h">
<Filter>Utilities</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\SQueue.h"> <ClInclude Include="..\Utilities\SQueue.h">
<Filter>Utilities</Filter> <Filter>Utilities</Filter>
</ClInclude> </ClInclude>
@ -1261,5 +1258,8 @@
<ClInclude Include="Emu\ARMv7\PSVFuncList.h"> <ClInclude Include="Emu\ARMv7\PSVFuncList.h">
<Filter>Emu\CPU\ARMv7</Filter> <Filter>Emu\CPU\ARMv7</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Emu\SysCalls\lv2\sleep_queue_type.h">
<Filter>Emu\SysCalls\lv2</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>