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
//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;
mGet = moveGet();
@ -45,7 +45,7 @@ public:
{
//if this is reached a lot it's time to increase the buffer size
//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);
mPut = movePut();
@ -94,7 +94,7 @@ public:
{
//if this is reached a lot it's time to increase the buffer size
//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())
{

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;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
@ -65,7 +65,7 @@ public:
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
@ -100,7 +100,7 @@ public:
return false;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}

View File

@ -160,10 +160,10 @@ public:
// register waiter
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))
{
// initialize waiter (only first time)
// initialize waiter (only once)
waiter.init();
// wait for 1 ms or until signal arrived
waiter.thread->WaitForAnySignal(1);

View File

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

View File

@ -136,23 +136,6 @@ protected:
public:
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();
void NextPc(u8 instr_size);
@ -280,7 +263,7 @@ public:
thread->SetJoinable(false);
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();
}

View File

@ -72,12 +72,6 @@ void CPUThreadManager::RemoveThread(const u32 id)
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;
thr = m_threads[i];

View File

@ -3,12 +3,13 @@
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SQueue.h"
#include "Emu/IdManager.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/ErrorCodes.h"
#include "Utilities/SMutex.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.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);
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())
{
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;
}
const u32 tid = GetId();
std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
ef->signal.Push(target, nullptr);
}
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
@ -769,21 +762,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
return;
}
const u32 tid = GetId();
std::lock_guard<std::mutex> lock(ef->mutex);
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
ef->signal.Push(target, nullptr);
}
else
{
ef->m_mutex.unlock(tid);
}
return;
}
else
@ -806,7 +791,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r)
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;
}
@ -917,13 +905,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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;
}
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;
}
@ -937,11 +931,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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
{
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;
}
@ -950,24 +950,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
{
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
{
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;
}
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;
}
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;
}
@ -985,7 +997,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch)
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;
break;
}
@ -1067,43 +1082,51 @@ void SPUThread::StopAndSignal(u32 code)
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)
{
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:
if (!eq->events.count())
case 0:
{
eq->owner.unlock(tid);
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0;
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;
}
// fallthrough
}
case SMR_SIGNAL:
case 1:
{
sys_event_data 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((u32)event.data1);
SPU.In_MBox.PushUncond((u32)event.data2);
SPU.In_MBox.PushUncond((u32)event.data3);
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())
{
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);

View File

@ -1,8 +1,7 @@
#pragma once
#include "Utilities/SMutex.h"
#include "Emu/Memory/atomic_type.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/Event.h"
#include "MFC.h"

View File

@ -1,9 +1,8 @@
#include "stdafx.h"
#include "Emu/Memory/Memory.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 "Event.h"

View File

@ -2215,7 +2215,7 @@ void RSXThread::Task()
continue;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
is_vblank_stopped = true;
@ -2246,7 +2246,7 @@ void RSXThread::Task()
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;
}
@ -2332,7 +2332,7 @@ void RSXThread::Task()
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");

View File

@ -244,12 +244,6 @@ u32 adecOpen(AudioDecoder* data)
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))
{
break;
@ -576,7 +570,7 @@ int cellAdecClose(u32 handle)
cellAdec->Warning("cellAdecClose(%d) aborted", handle);
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());

View File

@ -6,9 +6,8 @@
#include "rpcs3/Ini.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_lwmutex.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/Event.h"
#include "Emu/Audio/AudioManager.h"
@ -461,7 +460,7 @@ abort:
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;
@ -475,7 +474,7 @@ abort:
cellAudio->Warning("cellAudioInit() aborted");
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;
@ -494,7 +493,7 @@ int cellAudioQuit()
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())
{
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)
{
if (esFilterId->filterIdMajor >= 0xe0)
attr->memSize = 0x500000; // 0x45fa49 from ps3
attr->memSize = 0x400000; // 0x45fa49 from ps3
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,
(u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2);
@ -454,7 +454,7 @@ u32 dmuxOpen(Demuxer* data)
if (es.raw_data.size() > 1024 * 1024)
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
@ -550,7 +550,7 @@ u32 dmuxOpen(Demuxer* data)
if (es.isfull(old_size))
{
stream = backup;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}
@ -714,7 +714,7 @@ u32 dmuxOpen(Demuxer* data)
{
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);
@ -868,7 +868,7 @@ int cellDmuxClose(u32 demuxerHandle)
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());
@ -936,7 +936,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle);
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;
}

View File

@ -156,7 +156,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
cellSysutil->Warning("MsgDialog thread aborted");
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)
@ -166,7 +166,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogAbort;
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))

View File

@ -4,8 +4,10 @@
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SQueue.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_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
@ -558,13 +560,13 @@ s64 spursInit(
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");
}
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");
}
@ -620,7 +622,7 @@ s64 spursInit(
spurs->m.xD65.exchange(1);
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");
}
@ -628,7 +630,7 @@ s64 spursInit(
spurs->m.xD65.exchange(0);
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");
}
@ -638,7 +640,7 @@ s64 spursInit(
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");
}
@ -705,7 +707,7 @@ s64 spursInit(
}
else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup
{
return spursWakeUp(spurs);
return spursWakeUp(GetCurrentPPUThread(), spurs);
}
return CELL_OK;
@ -1265,7 +1267,7 @@ s64 cellSpursGetInfo(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursInfo> info)
#endif
}
s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
s64 spursWakeUp(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
{
#ifdef PRX_DEBUG_XXX
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);
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");
}
@ -1295,7 +1297,7 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
{
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");
}
@ -1303,11 +1305,11 @@ s64 spursWakeUp(vm::ptr<CellSpurs> spurs)
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());
return spursWakeUp(spurs);
return spursWakeUp(CPU, spurs);
}
s32 spursAddWorkload(

View File

@ -604,5 +604,7 @@ struct CellSpursTaskBinInfo
CellSpursTaskLsPattern lsPattern;
};
class PPUThread;
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/SysCalls/Modules.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_lwcond.h"
#include "Emu/SysCalls/lv2/sys_spu.h"

View File

@ -4,9 +4,8 @@
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.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_process.h"
#include "Emu/Event.h"

View File

@ -234,12 +234,6 @@ u32 vdecOpen(VideoDecoder* data)
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))
{
break;
@ -612,7 +606,7 @@ int cellVdecClose(u32 handle)
cellVdec->Warning("cellVdecClose(%d) aborted", handle);
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());

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)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
continue;
}

View File

@ -4,9 +4,10 @@
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Utilities/SQueue.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_lwmutex.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)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped())
{
sys_fs->Warning("fsAioRead() aborted");

View File

@ -6,9 +6,10 @@
#include "Emu/System.h"
#include "ModuleManager.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Utilities/SQueue.h"
#include "lv2/lv2Fs.h"
#include "lv2/sleep_queue_type.h"
#include "lv2/sys_lwmutex.h"
#include "lv2/sys_mutex.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_trywait), //93 (0x05D)
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_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_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_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_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_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock
bind_func(sys_mutex_create), //100 (0x064)
bind_func(sys_mutex_destroy), //101 (0x065)
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_all), //109 (0x06D)
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_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_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_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait
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_...) //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/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Utilities/SQueue.h"
#include "Emu/CPU/CPUThreadManager.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_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);
u32 id = sys_cond.GetNewId(cond, TYPE_COND);
const u32 id = sys_cond.GetNewId(cond, TYPE_COND);
*cond_id = id;
mutex->cond_count++;
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;
}
if (!cond->m_queue.finalize())
if (!cond->queue.finalize())
{
return CELL_EBUSY;
}
@ -77,9 +78,9 @@ s32 sys_cond_signal(u32 cond_id)
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())
{
@ -102,10 +103,9 @@ s32 sys_cond_signal_all(u32 cond_id)
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.lock(target);
cond->signal.Push(target, nullptr);
if (Emu.IsStopped())
{
@ -114,7 +114,6 @@ s32 sys_cond_signal_all(u32 cond_id)
}
}
cond->signaler = 0;
return CELL_OK;
}
@ -133,7 +132,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
return CELL_ESRCH;
}
if (!cond->m_queue.invalidate(thread_id))
if (!cond->queue.invalidate(thread_id))
{
return CELL_EPERM;
}
@ -142,7 +141,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
u32 target = thread_id;
{
cond->signal.lock(target);
cond->signal.Push(target, nullptr);
}
if (Emu.IsStopped())
@ -153,7 +152,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
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);
@ -164,65 +163,69 @@ s32 sys_cond_wait(u32 cond_id, u64 timeout)
}
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;
}
cond->m_queue.push(tid);
cond->queue.push(tid, mutex->protocol);
auto old_recursive = mutex->recursive;
mutex->recursive = 0;
mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop());
u64 counter = 0;
const u64 max_counter = timeout ? (timeout / 1000) : ~0ull;
if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol)))
{
assert(!"sys_cond_wait() failed");
}
bool pushed_in_sleep_queue = false;
const u64 time_start = get_system_time();
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;
default:
goto abort;
}
}
mutex->recursive = old_recursive;
cond->signal.unlock(tid);
return CELL_OK;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (counter++ > max_counter)
if (!pushed_in_sleep_queue)
{
cond->m_queue.invalidate(tid);
GetCurrentPPUThread().owned_mutexes--; // ???
return CELL_ETIMEDOUT;
mutex->queue.push(tid, mutex->protocol);
pushed_in_sleep_queue = true;
}
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())
{
goto abort;
sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id);
return CELL_OK;
}
}
abort:
sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id);
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
{
Mutex* mutex; // associated with mutex
SMutex signal;
u32 signaler; // signaler thread id (for signal_all)
SleepQueue m_queue;
u64 signal_stamp;
SQueue<u32, 32> signal;
sleep_queue_t queue;
Cond(Mutex* mutex, u64 name)
: mutex(mutex)
, m_queue(name)
, signaler(0)
, queue(name)
{
signal.initialize();
}
};
class PPUThread;
// SysCalls
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_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_all(u32 cond_id);
s32 sys_cond_signal_to(u32 cond_id, u32 thread_id);

View File

@ -3,11 +3,10 @@
#include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Event.h"
#include "sys_lwmutex.h"
#include "sleep_queue_type.h"
#include "sys_process.h"
#include "sys_event.h"
@ -88,19 +87,19 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode)
u32 tid = GetCurrentPPUThread().GetId();
eq->sq.m_mutex.lock();
eq->owner.lock(tid);
//eq->owner.lock(tid);
// check if some threads are waiting for an event
if (!mode && eq->sq.list.size())
{
eq->owner.unlock(tid);
//eq->owner.unlock(tid);
eq->sq.m_mutex.unlock();
return CELL_EBUSY;
}
eq->owner.unlock(tid, ~0);
//eq->owner.unlock(tid, ~0);
eq->sq.m_mutex.unlock();
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())
{
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();
eq->sq.m_mutex.lock();
eq->owner.lock(tid);
//eq->owner.lock(tid);
if (eq->sq.list.size())
{
*number = 0;
eq->owner.unlock(tid);
//eq->owner.unlock(tid);
eq->sq.m_mutex.unlock();
return CELL_OK;
}
*number = eq->events.pop_all(event_array.get_ptr(), size);
eq->owner.unlock(tid);
//eq->owner.unlock(tid);
eq->sq.m_mutex.unlock();
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();
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;
u64 counter = 0;
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:
if (!eq->events.count())
case 0:
{
eq->owner.unlock(tid);
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
const u32 next = eq->events.count() ? eq->sq.pop(eq->protocol) : 0;
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;
}
// fallthrough
}
case SMR_SIGNAL:
case 1:
{
sys_event_data 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",
(u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3);
/* 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;
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 (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id);

View File

@ -1,8 +1,5 @@
#pragma once
//#include "sys_lwmutex.h"
//#include "Utilities/SMutex.h"
#define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL)
// arbitrary code to prevent "special" zero value in key argument
@ -192,10 +189,10 @@ public:
struct EventQueue
{
SleepQueue sq;
sleep_queue_t sq;
EventPortList ports;
EventRingBuffer events;
SMutex owner;
atomic_le_t<u32> owner;
const union
{
@ -213,7 +210,7 @@ struct EventQueue
, key(key)
, 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/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Utilities/SQueue.h"
#include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h"
#include "sleep_queue_type.h"
#include "sys_event_flag.h"
SysCallBase sys_event_flag("sys_event_flag");
u32 EventFlag::check()
{
SleepQueue sq; // TODO: implement without SleepQueue
sleep_queue_t sq; // TODO: implement without sleep queue
u32 target = 0;
const u64 flag_set = flags.read_sync();
for (u32 i = 0; i < waiters.size(); i++)
{
if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) ||
((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & 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) && (flag_set & waiters[i].bitptn)))
{
if (m_protocol == SYS_SYNC_FIFO)
if (protocol == SYS_SYNC_FIFO)
{
target = waiters[i].tid;
break;
@ -31,8 +32,8 @@ u32 EventFlag::check()
}
}
if (m_protocol == SYS_SYNC_PRIORITY)
target = sq.pop_prio();
if (protocol == SYS_SYNC_PRIORITY)
target = sq.pop(SYS_SYNC_PRIORITY);
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();
{
ef->m_mutex.lock(tid);
if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
std::lock_guard<std::mutex> lock(ef->mutex);
if (ef->type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0)
{
ef->m_mutex.unlock(tid);
return CELL_EPERM;
}
EventFlagWaiter rec;
rec.bitptn = bitptn;
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)
{
u64 flags = ef->flags;
const u64 flag_set = ef->flags.read_sync();
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)
{
ef->flags = 0;
ef->flags &= 0;
}
if (result) *result = flags;
ef->m_mutex.unlock(tid);
if (result)
{
*result = flag_set;
}
return CELL_OK;
}
ef->m_mutex.unlock(tid);
}
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)
{
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);
u64 flags = ef->flags;
std::lock_guard<std::mutex> lock(ef->mutex);
const u64 flag_set = ef->flags.read_sync();
ef->signal.Pop(signaled, nullptr);
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)
{
ef->flags = 0;
ef->flags &= 0;
}
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.unlock(tid, target);
ef->m_mutex.unlock(tid, target);
ef->signal.Push(target, nullptr);
}
else
if (result)
{
ef->signal.unlock(tid);
*result = flag_set;
}
if (result) *result = flags;
ef->m_mutex.unlock(tid);
return CELL_OK;
}
}
ef->signal.unlock(tid);
ef->m_mutex.unlock(tid);
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)
{
ef->m_mutex.lock(tid);
std::lock_guard<std::mutex> lock(ef->mutex);
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;
}
}
ef->m_mutex.unlock(tid);
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
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;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId();
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();
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) ||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn)))
if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & bitptn) == bitptn) ||
((mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & bitptn)))
{
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)
{
ef->flags = 0;
ef->flags &= 0;
}
if (result) *result = flags;
if (result)
{
*result = flag_set;
}
ef->m_mutex.unlock(tid);
return CELL_OK;
}
ef->m_mutex.unlock(tid);
return CELL_EBUSY;
}
@ -294,21 +292,13 @@ s32 sys_event_flag_set(u32 eflag_id, u64 bitptn)
EventFlag* ef;
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;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
ef->signal.Push(target, nullptr);
}
else
{
ef->m_mutex.unlock(tid);
}
return CELL_OK;
}
@ -319,10 +309,8 @@ s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn)
EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId();
ef->m_mutex.lock(tid);
std::lock_guard<std::mutex> lock(ef->mutex);
ef->flags &= bitptn;
ef->m_mutex.unlock(tid);
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;
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());
for (u32 i = 0; i < ef->waiters.size(); i++)
{
tids[i] = ef->waiters[i].tid;
}
ef->waiters.clear();
ef->m_mutex.unlock(tid);
}
for (u32 i = 0; i < tids.size(); i++)
{
ef->signal.lock(tids[i]);
ef->signal.Push(tids[i], nullptr);
}
if (Emu.IsStopped())
@ -359,7 +344,10 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr<u32> num)
return CELL_OK;
}
if (num) *num = (u32)tids.size();
if (num)
{
*num = (u32)tids.size();
}
return CELL_OK;
}
@ -377,9 +365,6 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr<u64> flags)
EventFlag* ef;
if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH;
const u32 tid = GetCurrentPPUThread().GetId();
ef->m_mutex.lock(tid);
*flags = ef->flags;
ef->m_mutex.unlock(tid);
*flags = ef->flags.read_sync();
return CELL_OK;
}

View File

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

View File

@ -3,9 +3,11 @@
#include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Utilities/SQueue.h"
#include "Emu/Cell/PPUThread.h"
#include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_lwmutex.h"
#include "sys_lwcond.h"
@ -52,7 +54,7 @@ s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
return CELL_ESRCH;
}
if (!lw->m_queue.finalize())
if (!lw->queue.finalize())
{
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());
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())
{
@ -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());
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())
{
@ -129,14 +131,14 @@ s32 sys_lwcond_signal_to(vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
return CELL_ESRCH;
}
if (!lw->m_queue.invalidate(ppu_thread_id))
if (!lw->queue.invalidate(ppu_thread_id))
{
return CELL_EPERM;
}
u32 target = ppu_thread_id;
{
lw->signal.lock(target);
lw->signal.Push(target, nullptr);
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;
}
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);
@ -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());
u32 tid_le = GetCurrentPPUThread().GetId();
u32 tid_le = CPU.GetId();
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))
{
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;
}
auto old_owner = mutex->mutex.read_sync();
if (old_owner != tid)
if (mutex->owner.read_sync() != tid)
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue);
return CELL_EPERM; // caller must own this lwmutex
return CELL_EPERM;
}
lw->m_queue.push(tid_le);
lw->queue.push(tid_le, mutex->attribute);
auto old_recursive = mutex->recursive_count;
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);
if (!mutex->mutex.compare_and_swap_test(tid, target))
be_t<u32> target = be_t<u32>::make(sq->pop(mutex->attribute));
if (!mutex->owner.compare_and_swap_test(tid, target))
{
assert(!"sys_lwcond_wait(): mutex unlocking failed");
}
u64 counter = 0;
const u64 max_counter = timeout ? (timeout / 1000) : ~0;
const u64 time_start = get_system_time();
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;
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;
break;
}
switch (res)
{
case static_cast<int>(CELL_EDEADLK):
{
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())
{
sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
return CELL_OK;
}
}
mutex->recursive_count = old_recursive;
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);
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
goto abort;
}
}
abort:
sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue);
lw->signal.Pop(tid_le /* unused result */, nullptr);
return CELL_OK;
}

View File

@ -19,23 +19,24 @@ struct sys_lwcond_t
struct Lwcond
{
SMutex signal;
SleepQueue m_queue;
SQueue<u32, 32> signal;
sleep_queue_t queue;
Lwcond(u64 name)
: m_queue(name)
: queue(name)
{
signal.initialize();
}
};
// Aux
s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64);
class PPUThread;
// 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_destroy(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_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/Cell/PPUThread.h"
#include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_lwmutex.h"
SysCallBase sys_lwmutex("sys_lwmutex");
// TODO: move SleepQueue somewhere
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64)
{
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.attribute = protocol | recursive;
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;
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);
Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, GetCurrentPPUThread().GetId());
Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, 0);
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());
@ -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);
}
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());
@ -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);
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());
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());
return lwmutex->unlock(be_t<u32>::make(GetCurrentPPUThread().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;
return lwmutex->unlock(be_t<u32>::make(CPU.GetId()));
}
s32 sys_lwmutex_t::trylock(be_t<u32> tid)
{
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))
{
recursive_count += 1;
if (!recursive_count.ToBE()) return CELL_EKRESOURCE;
if (!recursive_count.ToBE())
{
return CELL_EKRESOURCE;
}
return CELL_OK;
}
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;
}
@ -246,12 +131,11 @@ s32 sys_lwmutex_t::trylock(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;
}
else
{
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);
@ -261,30 +145,19 @@ s32 sys_lwmutex_t::unlock(be_t<u32> tid)
recursive_count -= 1;
if (!recursive_count.ToBE())
{
be_t<u32> target = be_t<u32>::make(0);
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
{
case se32(SYS_SYNC_FIFO):
case se32(SYS_SYNC_PRIORITY):
{
SleepQueue* sq;
sleep_queue_t* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
{
return CELL_ESRCH;
}
target = attribute & SYS_SYNC_FIFO ? sq->pop() : sq->pop_prio();
}
}
if (!mutex.compare_and_swap_test(tid, target))
if (!owner.compare_and_swap_test(tid, be_t<u32>::make(sq->pop(attribute))))
{
assert(!"sys_lwmutex_t::unlock() failed");
}
}
return CELL_OK;
}
}
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;
}
SleepQueue* sq;
sleep_queue_t* sq;
if (!Emu.GetIdManager().GetIDData(sleep_queue, sq))
{
return CELL_ESRCH;
}
switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK))
{
case se32(SYS_SYNC_PRIORITY):
case se32(SYS_SYNC_FIFO):
{
sq->push(tid);
}
}
sq->push(tid, attribute);
const u64 time_start = get_system_time();
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())
{
sq->invalidate(tid);

View File

@ -1,31 +1,5 @@
#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
{
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
{
atomic_t<u32> mutex;
atomic_t<u32> owner;
atomic_t<u32> waiter; // currently not used
be_t<u32> attribute;
be_t<u32> recursive_count;
@ -85,9 +33,11 @@ struct sys_lwmutex_t
// Aux
s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64);
class PPUThread;
// SysCalls
s32 sys_lwmutex_create(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_lock(vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
s32 sys_lwmutex_trylock(vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_unlock(vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
s32 sys_lwmutex_trylock(PPUThread& CPU, 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/SysCalls/SysCalls.h"
#include "Emu/Memory/atomic_type.h"
#include "Utilities/SMutex.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h"
#include "sleep_queue_type.h"
#include "sys_time.h"
#include "sys_mutex.h"
SysCallBase sys_mutex("sys_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());
@ -58,13 +61,10 @@ s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr)
return CELL_EINVAL;
}
u32 tid = GetCurrentPPUThread().GetId();
Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64);
u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX);
mutex->m_mutex.lock(tid);
mutex->id = id;
const u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX);
mutex->id.exchange(id);
*mutex_id = id;
mutex->m_mutex.unlock(tid);
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);
@ -74,7 +74,7 @@ s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute> attr)
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);
@ -91,26 +91,32 @@ s32 sys_mutex_destroy(u32 mutex_id)
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;
}
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;
}
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.GetSyncPrimManager().EraseSyncPrimData(TYPE_MUTEX, mutex_id);
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);
@ -120,14 +126,13 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout)
return CELL_ESRCH;
}
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
const u32 tid = CPU.GetId();
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
if (mutex->owner.read_sync() == tid)
{
if (mutex->is_recursive)
{
if (++mutex->recursive == 0)
if (!++mutex->recursive)
{
return CELL_EKRESOURCE;
}
@ -138,48 +143,51 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout)
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))
{
}
else
{
sys_mutex.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
}
mutex->recursive = 1;
CPU.owned_mutexes++;
return CELL_OK;
}
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;
case SMR_FAILED: break;
default: goto abort;
auto old_owner = mutex->owner.compare_and_swap(0, tid);
if (!old_owner)
{
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->m_queue.invalidate(tid);
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;
mutex->queue.invalidate(tid);
return CELL_ETIMEDOUT;
}
abort:
if (Emu.IsStopped())
{
sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id);
return CELL_OK;
}
return CELL_ESRCH;
}
mutex->recursive = 1;
CPU.owned_mutexes++;
return CELL_OK;
}
s32 sys_mutex_trylock(u32 mutex_id)
s32 sys_mutex_trylock(PPUThread& CPU, u32 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;
}
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
const u32 tid = CPU.GetId();
if (mutex->m_mutex.unlock(tid, tid) == SMR_OK)
if (mutex->owner.read_sync() == tid)
{
if (mutex->is_recursive)
{
if (++mutex->recursive == 0)
if (!++mutex->recursive)
{
return CELL_EKRESOURCE;
}
@ -207,25 +214,18 @@ s32 sys_mutex_trylock(u32 mutex_id)
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))
{
}
else
{
sys_mutex.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner);
}
return CELL_EBUSY;
}
switch (mutex->m_mutex.trylock(tid))
{
case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK;
default: return CELL_EBUSY;
}
mutex->recursive = 1;
CPU.owned_mutexes++;
return CELL_OK;
}
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);
@ -235,24 +235,26 @@ s32 sys_mutex_unlock(u32 mutex_id)
return CELL_ESRCH;
}
PPUThread& t = GetCurrentPPUThread();
u32 tid = t.GetId();
const u32 tid = CPU.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))
{
sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive);
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());
t.owned_mutexes--;
if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.pop(mutex->protocol)))
{
assert(!"sys_mutex_unlock() failed");
}
CPU.owned_mutexes--;
}
return CELL_OK;
}
return CELL_EPERM;
}

View File

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

View File

@ -5,7 +5,7 @@
#include "Emu/Memory/atomic_type.h"
#include "Emu/Cell/PPUThread.h"
#include "sys_lwmutex.h"
#include "sleep_queue_type.h"
#include "sys_rwlock.h"
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);
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;
@ -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);
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;

View File

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

View File

@ -16,9 +16,9 @@ struct sys_semaphore_attribute
struct Semaphore
{
std::mutex m_mutex;
SleepQueue m_queue;
s32 m_value;
std::mutex mutex;
sleep_queue_t queue;
s32 value;
u32 signal;
const s32 max;
@ -26,7 +26,7 @@ struct Semaphore
const u64 name;
Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name)
: m_value(initial_count)
: value(initial_count)
, signal(0)
, max(max_count)
, 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);
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;
u32 uncounted = 0;
u32 counter = 0;
while (true)
{
if (g_thread_count <= uncounted)

View File

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

View File

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