cpu_thread::test_state added

lv2_obj::sleep adjustment
synchronization fixes
This commit is contained in:
Nekotekina 2017-02-22 13:10:55 +03:00
parent 4b6f8d2f62
commit 9000407a77
36 changed files with 421 additions and 302 deletions

View file

@ -2,6 +2,8 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "CPUThread.h" #include "CPUThread.h"
#include <thread>
DECLARE(cpu_thread::g_threads_created){0}; DECLARE(cpu_thread::g_threads_created){0};
DECLARE(cpu_thread::g_threads_deleted){0}; DECLARE(cpu_thread::g_threads_deleted){0};
@ -17,10 +19,11 @@ void fmt_class_string<cpu_flag>::format(std::string& out, u64 arg)
case cpu_flag::suspend: return "s"; case cpu_flag::suspend: return "s";
case cpu_flag::ret: return "ret"; case cpu_flag::ret: return "ret";
case cpu_flag::signal: return "sig"; case cpu_flag::signal: return "sig";
case cpu_flag::dbg_global_pause: return "G.PAUSE"; case cpu_flag::dbg_global_pause: return "G-PAUSE";
case cpu_flag::dbg_global_stop: return "G.EXIT"; case cpu_flag::dbg_global_stop: return "G-EXIT";
case cpu_flag::dbg_pause: return "PAUSE"; case cpu_flag::dbg_pause: return "PAUSE";
case cpu_flag::dbg_step: return "STEP"; case cpu_flag::dbg_step: return "STEP";
case cpu_flag::is_waiting: return "w";
case cpu_flag::__bitset_enum_max: break; case cpu_flag::__bitset_enum_max: break;
} }
@ -63,6 +66,7 @@ void cpu_thread::on_task()
} }
state -= cpu_flag::ret; state -= cpu_flag::ret;
state += cpu_flag::is_waiting;
continue; continue;
} }
@ -93,8 +97,9 @@ bool cpu_thread::check_state()
while (true) while (true)
{ {
if (test(state & cpu_flag::exit)) if (test(state, cpu_flag::exit + cpu_flag::dbg_global_stop))
{ {
state += cpu_flag::is_waiting;
return true; return true;
} }
@ -103,11 +108,21 @@ bool cpu_thread::check_state()
cpu_sleep_called = false; cpu_sleep_called = false;
} }
if (!test(state & (cpu_state_pause + cpu_flag::dbg_global_stop))) if (!test(state, cpu_state_pause))
{ {
if (test(state, cpu_flag::is_waiting))
{
state -= cpu_flag::is_waiting;
}
break; break;
} }
if (!state.test_and_set(cpu_flag::is_waiting))
{
continue;
}
if (test(state & cpu_flag::suspend) && !cpu_sleep_called) if (test(state & cpu_flag::suspend) && !cpu_sleep_called)
{ {
cpu_sleep(); cpu_sleep();
@ -122,6 +137,7 @@ bool cpu_thread::check_state()
if (test(state_, cpu_flag::ret + cpu_flag::stop)) if (test(state_, cpu_flag::ret + cpu_flag::stop))
{ {
state += cpu_flag::is_waiting;
return true; return true;
} }
@ -131,9 +147,21 @@ bool cpu_thread::check_state()
state -= cpu_flag::dbg_step; state -= cpu_flag::dbg_step;
} }
state -= cpu_flag::is_waiting;
return false; return false;
} }
void cpu_thread::test_state()
{
if (UNLIKELY(test(state)))
{
if (check_state())
{
throw cpu_flag::ret;
}
}
}
void cpu_thread::run() void cpu_thread::run()
{ {
state -= cpu_flag::stop; state -= cpu_flag::stop;

View file

@ -17,6 +17,8 @@ enum class cpu_flag : u32
dbg_pause, // Thread paused dbg_pause, // Thread paused
dbg_step, // Thread forced to pause after one step (one instruction, etc) dbg_step, // Thread forced to pause after one step (one instruction, etc)
is_waiting, // Informational, self-maintained
__bitset_enum_max __bitset_enum_max
}; };
@ -36,11 +38,14 @@ public:
cpu_thread(u32 id); cpu_thread(u32 id);
// Public thread state // Public thread state
atomic_t<bs_t<cpu_flag>> state{+cpu_flag::stop}; atomic_t<bs_t<cpu_flag>> state{cpu_flag::stop + cpu_flag::is_waiting};
// Process thread state, return true if the checker must return // Process thread state, return true if the checker must return
bool check_state(); bool check_state();
// Process thread state
void test_state();
// Run thread // Run thread
void run(); void run();

View file

@ -200,7 +200,7 @@ public:
// TODO: finalize // TODO: finalize
cellAdec.warning("adecEndSeq:"); cellAdec.warning("adecEndSeq:");
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg); cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
just_finished = true; just_finished = true;
break; break;
@ -377,13 +377,13 @@ public:
{ {
frame.data = nullptr; // to prevent destruction frame.data = nullptr; // to prevent destruction
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg); cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
} }
} }
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg); cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
break; break;
} }

View file

@ -243,7 +243,7 @@ public:
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata; dmuxMsg->supplementalInfo = stream.userdata;
cbFunc(*this, id, dmuxMsg, cbArg); cbFunc(*this, id, dmuxMsg, cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
is_working = false; is_working = false;
@ -397,7 +397,7 @@ public:
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
es.cbFunc(*this, id, es.id, esMsg, es.cbArg); es.cbFunc(*this, id, es.id, esMsg, es.cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
} }
else else
@ -463,7 +463,7 @@ public:
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
es.cbFunc(*this, id, es.id, esMsg, es.cbArg); es.cbFunc(*this, id, es.id, esMsg, es.cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
if (pes.has_ts) if (pes.has_ts)
@ -540,7 +540,7 @@ public:
dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE;
dmuxMsg->supplementalInfo = stream.userdata; dmuxMsg->supplementalInfo = stream.userdata;
cbFunc(*this, id, dmuxMsg, cbArg); cbFunc(*this, id, dmuxMsg, cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
stream = {}; stream = {};
@ -629,7 +629,7 @@ public:
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
es.cbFunc(*this, id, es.id, esMsg, es.cbArg); es.cbFunc(*this, id, es.id, esMsg, es.cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
if (es.raw_data.size()) if (es.raw_data.size())
@ -642,7 +642,7 @@ public:
esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE;
esMsg->supplementalInfo = stream.userdata; esMsg->supplementalInfo = stream.userdata;
es.cbFunc(*this, id, es.id, esMsg, es.cbArg); es.cbFunc(*this, id, es.id, esMsg, es.cbArg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
break; break;
} }

View file

@ -743,7 +743,7 @@ struct fs_aio_thread : ppu_thread
} }
func(*this, aio, error, xid, result); func(*this, aio, error, xid, result);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
} }
}; };

View file

@ -12,7 +12,7 @@
logs::channel cellGcmSys("cellGcmSys", logs::level::notice); logs::channel cellGcmSys("cellGcmSys", logs::level::notice);
extern s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count); extern s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 count);
extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr); extern void ppu_register_function_at(u32 addr, u32 size, ppu_function_t ptr);
const u32 tiled_pitches[] = { const u32 tiled_pitches[] = {
@ -1298,12 +1298,12 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd)
return true; return true;
} }
s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count) s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 count)
{ {
cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count); cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count);
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr); auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
const std::chrono::time_point<steady_clock> enterWait = steady_clock::now();
// Flush command buffer (ie allow RSX to read up to context->current) // Flush command buffer (ie allow RSX to read up to context->current)
ctrl.put.exchange(getOffsetFromAddress(context->current.addr())); ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
@ -1317,18 +1317,18 @@ s32 cellGcmCallback(vm::ptr<CellGcmContextData> context, u32 count)
context->end.set(newCommandBuffer.second); context->end.set(newCommandBuffer.second);
// Wait for rsx to "release" the new command buffer // Wait for rsx to "release" the new command buffer
while (!Emu.IsStopped()) while (true)
{ {
u32 getPos = ctrl.get.load(); u32 getPos = ctrl.get.load();
if (isInCommandBufferExcept(getPos, newCommandBuffer.first, newCommandBuffer.second)) if (isInCommandBufferExcept(getPos, newCommandBuffer.first, newCommandBuffer.second))
break; break;
std::chrono::time_point<steady_clock> waitPoint = steady_clock::now();
long long elapsedTime = std::chrono::duration_cast<std::chrono::seconds>(waitPoint - enterWait).count(); ppu.state += cpu_flag::is_waiting;
if (elapsedTime > 0) ppu.test_state();
cellGcmSys.error("Has wait for more than a second for command buffer to be released by RSX"); busy_wait();
std::this_thread::yield();
} }
ppu.test_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -572,7 +572,7 @@ void _spurs::handler_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
_spurs::handler_wait_ready(ppu, spurs); _spurs::handler_wait_ready(ppu, spurs);
} }
CHECK_SUCCESS(sys_spu_thread_group_start(spurs->spuTG)); CHECK_SUCCESS(sys_spu_thread_group_start(ppu, spurs->spuTG));
if (s32 rc = sys_spu_thread_group_join(ppu, spurs->spuTG, vm::null, vm::null)) if (s32 rc = sys_spu_thread_group_join(ppu, spurs->spuTG, vm::null, vm::null))
{ {
@ -1118,9 +1118,10 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision,
} }
// entry point cannot be initialized immediately because SPU LS will be rewritten by sys_spu_thread_group_start() // entry point cannot be initialized immediately because SPU LS will be rewritten by sys_spu_thread_group_start()
idm::get<SPUThread>(spurs->spus[num])->custom_task = [entry = spurs->spuImg.entry_point](SPUThread& spu) //idm::get<SPUThread>(spurs->spus[num])->custom_task = [entry = spurs->spuImg.entry_point](SPUThread& spu)
{ {
spu.RegisterHleFunction(entry, spursKernelEntry); // Disabled
//spu.RegisterHleFunction(entry, spursKernelEntry);
}; };
} }

View file

@ -266,10 +266,10 @@ bool spursKernel1SelectWorkload(SPUThread& spu)
u32 wklSelectedId; u32 wklSelectedId;
u32 pollStatus; u32 pollStatus;
vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() //vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]()
{ {
// lock the first 0x80 bytes of spurs // lock the first 0x80 bytes of spurs
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
// Calculate the contention (number of SPUs used) for each workload // Calculate the contention (number of SPUs used) for each workload
u8 contention[CELL_SPURS_MAX_WORKLOAD]; u8 contention[CELL_SPURS_MAX_WORKLOAD];
@ -429,7 +429,7 @@ bool spursKernel1SelectWorkload(SPUThread& spu)
} }
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
}); }//);
u64 result = (u64)wklSelectedId << 32; u64 result = (u64)wklSelectedId << 32;
result |= pollStatus; result |= pollStatus;
@ -450,10 +450,10 @@ bool spursKernel2SelectWorkload(SPUThread& spu)
u32 wklSelectedId; u32 wklSelectedId;
u32 pollStatus; u32 pollStatus;
vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() //vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]()
{ {
// lock the first 0x80 bytes of spurs // lock the first 0x80 bytes of spurs
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
// Calculate the contention (number of SPUs used) for each workload // Calculate the contention (number of SPUs used) for each workload
u8 contention[CELL_SPURS_MAX_WORKLOAD2]; u8 contention[CELL_SPURS_MAX_WORKLOAD2];
@ -602,7 +602,7 @@ bool spursKernel2SelectWorkload(SPUThread& spu)
} }
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
}); }//);
u64 result = (u64)wklSelectedId << 32; u64 result = (u64)wklSelectedId << 32;
result |= pollStatus; result |= pollStatus;
@ -633,10 +633,10 @@ void spursKernelDispatchWorkload(SPUThread& spu, u64 widAndPollStatus)
switch (wklInfo->addr.addr()) switch (wklInfo->addr.addr())
{ {
case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD: case SPURS_IMG_ADDR_SYS_SRV_WORKLOAD:
spu.RegisterHleFunction(0xA00, spursSysServiceEntry); //spu.RegisterHleFunction(0xA00, spursSysServiceEntry);
break; break;
case SPURS_IMG_ADDR_TASKSET_PM: case SPURS_IMG_ADDR_TASKSET_PM:
spu.RegisterHleFunction(0xA00, spursTasksetEntry); //spu.RegisterHleFunction(0xA00, spursTasksetEntry);
break; break;
default: default:
std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size); std::memcpy(vm::base(spu.offset + 0xA00), wklInfo->addr.get_ptr(), wklInfo->size);
@ -721,10 +721,10 @@ bool spursKernelEntry(SPUThread& spu)
} }
// Register SPURS kernel HLE functions // Register SPURS kernel HLE functions
spu.UnregisterHleFunctions(0, 0x40000/*LS_BOTTOM*/); //spu.UnregisterHleFunctions(0, 0x40000/*LS_BOTTOM*/);
spu.RegisterHleFunction(isKernel2 ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR, spursKernelEntry); //spu.RegisterHleFunction(isKernel2 ? CELL_SPURS_KERNEL2_ENTRY_ADDR : CELL_SPURS_KERNEL1_ENTRY_ADDR, spursKernelEntry);
spu.RegisterHleFunction(ctxt->exitToKernelAddr, spursKernelWorkloadExit); //spu.RegisterHleFunction(ctxt->exitToKernelAddr, spursKernelWorkloadExit);
spu.RegisterHleFunction(ctxt->selectWorkloadAddr, isKernel2 ? spursKernel2SelectWorkload : spursKernel1SelectWorkload); //spu.RegisterHleFunction(ctxt->selectWorkloadAddr, isKernel2 ? spursKernel2SelectWorkload : spursKernel1SelectWorkload);
// Start the system service // Start the system service
spursKernelDispatchWorkload(spu, ((u64)CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) << 32); spursKernelDispatchWorkload(spu, ((u64)CELL_SPURS_SYS_SERVICE_WORKLOAD_ID) << 32);
@ -771,7 +771,7 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
while (true) while (true)
{ {
vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); //vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128);
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x100); auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x100);
// Find the number of SPUs that are idling in this SPURS instance // Find the number of SPUs that are idling in this SPURS instance
@ -860,7 +860,7 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
continue; continue;
} }
if (vm::reservation_update(vm::cast(ctxt->spurs.addr(), HERE), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload)) //if (vm::reservation_update(vm::cast(ctxt->spurs.addr(), HERE), vm::base(spu.offset + 0x100), 128) && (shouldExit || foundReadyWorkload))
{ {
break; break;
} }
@ -888,11 +888,11 @@ void spursSysServiceMain(SPUThread& spu, u32 pollStatus)
{ {
ctxt->sysSrvInitialised = 1; ctxt->sysSrvInitialised = 1;
vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128); //vm::reservation_acquire(vm::base(spu.offset + 0x100), vm::cast(ctxt->spurs.addr(), HERE), 128);
vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() //vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
// Halt if already initialised // Halt if already initialised
if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum)) if (spurs->sysSrvOnSpu & (1 << ctxt->spuNum))
@ -904,7 +904,7 @@ void spursSysServiceMain(SPUThread& spu, u32 pollStatus)
spurs->sysSrvOnSpu |= 1 << ctxt->spuNum; spurs->sysSrvOnSpu |= 1 << ctxt->spuNum;
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
ctxt->traceBuffer = 0; ctxt->traceBuffer = 0;
ctxt->traceMsgCount = -1; ctxt->traceMsgCount = -1;
@ -984,9 +984,9 @@ void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt)
bool updateWorkload = false; bool updateWorkload = false;
bool terminate = false; bool terminate = false;
vm::reservation_op(vm::cast(ctxt->spurs.addr() + OFFSET_32(CellSpurs, wklState1), HERE), 128, [&]() //vm::reservation_op(vm::cast(ctxt->spurs.addr() + OFFSET_32(CellSpurs, wklState1), HERE), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
// Terminate request // Terminate request
if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum)) if (spurs->sysSrvMsgTerminate & (1 << ctxt->spuNum))
@ -1009,7 +1009,7 @@ void spursSysServiceProcessRequests(SPUThread& spu, SpursKernelContext* ctxt)
} }
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
// Process update workload message // Process update workload message
if (updateWorkload) if (updateWorkload)
@ -1063,9 +1063,9 @@ void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt)
} }
} }
vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() //vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++) for (u32 i = 0; i < CELL_SPURS_MAX_WORKLOAD; i++)
{ {
@ -1120,7 +1120,7 @@ void spursSysServiceActivateWorkload(SPUThread& spu, SpursKernelContext* ctxt)
} }
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
if (wklShutdownBitSet) if (wklShutdownBitSet)
{ {
@ -1135,9 +1135,9 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelCo
// workloads that have a shutdown completion hook registered // workloads that have a shutdown completion hook registered
u32 wklNotifyBitSet; u32 wklNotifyBitSet;
u8 spuPort; u8 spuPort;
vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() //vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
wklNotifyBitSet = 0; wklNotifyBitSet = 0;
spuPort = spurs->spuPort;; spuPort = spurs->spuPort;;
@ -1163,7 +1163,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(SPUThread& spu, SpursKernelCo
} }
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
if (wklNotifyBitSet) if (wklNotifyBitSet)
{ {
@ -1187,9 +1187,9 @@ void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 ar
bool notify; bool notify;
u8 sysSrvMsgUpdateTrace; u8 sysSrvMsgUpdateTrace;
vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() //vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
auto& trace = spurs->sysSrvTrace.raw(); auto& trace = spurs->sysSrvTrace.raw();
sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace; sysSrvMsgUpdateTrace = trace.sysSrvMsgUpdateTrace;
@ -1211,12 +1211,12 @@ void spursSysServiceTraceUpdate(SPUThread& spu, SpursKernelContext* ctxt, u32 ar
} }
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
// Get trace parameters from CellSpurs and store them in the LS // Get trace parameters from CellSpurs and store them in the LS
if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0)) if (((sysSrvMsgUpdateTrace & (1 << ctxt->spuNum)) != 0) || (arg3 != 0))
{ {
vm::reservation_acquire(vm::base(spu.offset + 0x80), ctxt->spurs.ptr(&CellSpurs::traceBuffer).addr(), 128); //vm::reservation_acquire(vm::base(spu.offset + 0x80), ctxt->spurs.ptr(&CellSpurs::traceBuffer).addr(), 128);
auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x80 - OFFSET_32(CellSpurs, traceBuffer)); auto spurs = vm::_ptr<CellSpurs>(spu.offset + 0x80 - OFFSET_32(CellSpurs, traceBuffer));
if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0) if (ctxt->traceMsgCount != 0xFF || spurs->traceBuffer.addr() == 0)
@ -1252,9 +1252,9 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContex
bool do_return = false; bool do_return = false;
vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]() //vm::reservation_op(ctxt->spurs.ptr(&CellSpurs::wklState1).addr(), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF) if (spurs->sysSrvPreemptWklId[ctxt->spuNum] == 0xFF)
{ {
@ -1266,15 +1266,15 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContex
spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF; spurs->sysSrvPreemptWklId[ctxt->spuNum] = 0xFF;
std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128); std::memcpy(vm::base(spu.offset + 0x2D80), spurs->wklState1, 128);
}); }//);
if (do_return) return; if (do_return) return;
spursSysServiceActivateWorkload(spu, ctxt); spursSysServiceActivateWorkload(spu, ctxt);
vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]() //vm::reservation_op(vm::cast(ctxt->spurs.addr(), HERE), 128, [&]()
{ {
auto spurs = ctxt->spurs.get_ptr_priv(); auto spurs = ctxt->spurs.get_ptr();
if (wklId >= CELL_SPURS_MAX_WORKLOAD) if (wklId >= CELL_SPURS_MAX_WORKLOAD)
{ {
@ -1288,7 +1288,7 @@ void spursSysServiceCleanupAfterSystemWorkload(SPUThread& spu, SpursKernelContex
} }
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
}); }//);
// Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace // Set the current workload id to the id of the pre-empted workload since cellSpursModulePutTrace
// uses the current worload id to determine the workload to which the trace belongs // uses the current worload id to determine the workload to which the trace belongs
@ -1341,9 +1341,9 @@ bool spursTasksetEntry(SPUThread& spu)
ctxt->taskId = 0xFFFFFFFF; ctxt->taskId = 0xFFFFFFFF;
// Register SPURS takset policy module HLE functions // Register SPURS takset policy module HLE functions
spu.UnregisterHleFunctions(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, 0x40000/*LS_BOTTOM*/); //spu.UnregisterHleFunctions(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, 0x40000/*LS_BOTTOM*/);
spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry); //spu.RegisterHleFunction(CELL_SPURS_TASKSET_PM_ENTRY_ADDR, spursTasksetEntry);
spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry); //spu.RegisterHleFunction(ctxt->syscallAddr, spursTasksetSyscallEntry);
try try
{ {
@ -1433,9 +1433,9 @@ s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* is
s32 rc = CELL_OK; s32 rc = CELL_OK;
s32 numNewlyReadyTasks; s32 numNewlyReadyTasks;
vm::reservation_op(vm::cast(ctxt->taskset.addr(), HERE), 128, [&]() //vm::reservation_op(vm::cast(ctxt->taskset.addr(), HERE), 128, [&]()
{ {
auto taskset = ctxt->taskset.get_ptr_priv(); auto taskset = ctxt->taskset.get_ptr();
// Verify taskset state is valid // Verify taskset state is valid
be_t<v128> _0(v128::from32(0)); be_t<v128> _0(v128::from32(0));
@ -1592,12 +1592,12 @@ s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* is
taskset->ready = ready; taskset->ready = ready;
std::memcpy(vm::base(spu.offset + 0x2700), taskset, 128); std::memcpy(vm::base(spu.offset + 0x2700), taskset, 128);
}); }//);
// Increment the ready count of the workload by the number of tasks that have become ready // Increment the ready count of the workload by the number of tasks that have become ready
vm::reservation_op(vm::cast(kernelCtxt->spurs.addr(), HERE), 128, [&]() //vm::reservation_op(vm::cast(kernelCtxt->spurs.addr(), HERE), 128, [&]()
{ {
auto spurs = kernelCtxt->spurs.get_ptr_priv(); auto spurs = kernelCtxt->spurs.get_ptr();
s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[kernelCtxt->wklCurrentId].load() : spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].load(); s32 readyCount = kernelCtxt->wklCurrentId < CELL_SPURS_MAX_WORKLOAD ? spurs->wklReadyCount1[kernelCtxt->wklCurrentId].load() : spurs->wklIdleSpuCountOrReadyCount2[kernelCtxt->wklCurrentId & 0x0F].load();
readyCount += numNewlyReadyTasks; readyCount += numNewlyReadyTasks;
@ -1613,7 +1613,7 @@ s32 spursTasksetProcessRequest(SPUThread& spu, s32 request, u32* taskId, u32* is
} }
std::memcpy(vm::base(spu.offset + 0x100), spurs, 128); std::memcpy(vm::base(spu.offset + 0x100), spurs, 128);
}); }//);
return rc; return rc;
} }

View file

@ -6,10 +6,6 @@
#include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/lv2/sys_process.h"
#include "cellSync.h" #include "cellSync.h"
#include "Emu/Memory/wait_engine.h"
#include <thread>
logs::channel cellSync("cellSync", logs::level::notice); logs::channel cellSync("cellSync", logs::level::notice);
template<> template<>
@ -63,7 +59,7 @@ error_code cellSyncMutexInitialize(vm::ptr<CellSyncMutex> mutex)
return CELL_OK; return CELL_OK;
} }
error_code cellSyncMutexLock(vm::ptr<CellSyncMutex> mutex) error_code cellSyncMutexLock(ppu_thread& ppu, vm::ptr<CellSyncMutex> mutex)
{ {
cellSync.trace("cellSyncMutexLock(mutex=*0x%x)", mutex); cellSync.trace("cellSyncMutexLock(mutex=*0x%x)", mutex);
@ -81,10 +77,10 @@ error_code cellSyncMutexLock(vm::ptr<CellSyncMutex> mutex)
const auto order = mutex->ctrl.atomic_op(&CellSyncMutex::lock_begin); const auto order = mutex->ctrl.atomic_op(&CellSyncMutex::lock_begin);
// Wait until rel value is equal to old acq value // Wait until rel value is equal to old acq value
vm::wait_op(mutex.addr(), 4, [&] while (mutex->ctrl.load().rel != order)
{ {
return mutex->ctrl.load().rel == order; ppu.test_state();
}); }
_mm_mfence(); _mm_mfence();
@ -129,8 +125,6 @@ error_code cellSyncMutexUnlock(vm::ptr<CellSyncMutex> mutex)
mutex->ctrl.atomic_op(&CellSyncMutex::unlock); mutex->ctrl.atomic_op(&CellSyncMutex::unlock);
vm::notify_at(mutex.addr(), 4);
return CELL_OK; return CELL_OK;
} }
@ -159,7 +153,7 @@ error_code cellSyncBarrierInitialize(vm::ptr<CellSyncBarrier> barrier, u16 total
return CELL_OK; return CELL_OK;
} }
error_code cellSyncBarrierNotify(vm::ptr<CellSyncBarrier> barrier) error_code cellSyncBarrierNotify(ppu_thread& ppu, vm::ptr<CellSyncBarrier> barrier)
{ {
cellSync.trace("cellSyncBarrierNotify(barrier=*0x%x)", barrier); cellSync.trace("cellSyncBarrierNotify(barrier=*0x%x)", barrier);
@ -173,9 +167,10 @@ error_code cellSyncBarrierNotify(vm::ptr<CellSyncBarrier> barrier)
return CELL_SYNC_ERROR_ALIGN; return CELL_SYNC_ERROR_ALIGN;
} }
vm::wait_op(barrier.addr(), 4, [&] { return barrier->ctrl.atomic_op(&CellSyncBarrier::try_notify); }); while (!barrier->ctrl.atomic_op(&CellSyncBarrier::try_notify))
{
vm::notify_at(barrier.addr(), 4); ppu.test_state();
}
return CELL_OK; return CELL_OK;
} }
@ -201,12 +196,10 @@ error_code cellSyncBarrierTryNotify(vm::ptr<CellSyncBarrier> barrier)
return not_an_error(CELL_SYNC_ERROR_BUSY); return not_an_error(CELL_SYNC_ERROR_BUSY);
} }
vm::notify_at(barrier.addr(), 4);
return CELL_OK; return CELL_OK;
} }
error_code cellSyncBarrierWait(vm::ptr<CellSyncBarrier> barrier) error_code cellSyncBarrierWait(ppu_thread& ppu, vm::ptr<CellSyncBarrier> barrier)
{ {
cellSync.trace("cellSyncBarrierWait(barrier=*0x%x)", barrier); cellSync.trace("cellSyncBarrierWait(barrier=*0x%x)", barrier);
@ -222,9 +215,10 @@ error_code cellSyncBarrierWait(vm::ptr<CellSyncBarrier> barrier)
_mm_mfence(); _mm_mfence();
vm::wait_op(barrier.addr(), 4, [&] { return barrier->ctrl.atomic_op(&CellSyncBarrier::try_wait); }); while (!barrier->ctrl.atomic_op(&CellSyncBarrier::try_wait))
{
vm::notify_at(barrier.addr(), 4); ppu.test_state();
}
return CELL_OK; return CELL_OK;
} }
@ -250,8 +244,6 @@ error_code cellSyncBarrierTryWait(vm::ptr<CellSyncBarrier> barrier)
return not_an_error(CELL_SYNC_ERROR_BUSY); return not_an_error(CELL_SYNC_ERROR_BUSY);
} }
vm::notify_at(barrier.addr(), 4);
return CELL_OK; return CELL_OK;
} }
@ -284,7 +276,7 @@ error_code cellSyncRwmInitialize(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer,
return CELL_OK; return CELL_OK;
} }
error_code cellSyncRwmRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer) error_code cellSyncRwmRead(ppu_thread& ppu, vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
{ {
cellSync.trace("cellSyncRwmRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); cellSync.trace("cellSyncRwmRead(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
@ -299,7 +291,10 @@ error_code cellSyncRwmRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
} }
// wait until `writers` is zero, increase `readers` // wait until `writers` is zero, increase `readers`
vm::wait_op(rwm.addr(), 8, [&] { return rwm->ctrl.atomic_op(&CellSyncRwm::try_read_begin); }); while (!rwm->ctrl.atomic_op(&CellSyncRwm::try_read_begin))
{
ppu.test_state();
}
// copy data to buffer // copy data to buffer
std::memcpy(buffer.get_ptr(), rwm->buffer.get_ptr(), rwm->size); std::memcpy(buffer.get_ptr(), rwm->buffer.get_ptr(), rwm->size);
@ -310,8 +305,6 @@ error_code cellSyncRwmRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
return CELL_SYNC_ERROR_ABORT; return CELL_SYNC_ERROR_ABORT;
} }
vm::notify_at(rwm.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -344,12 +337,10 @@ error_code cellSyncRwmTryRead(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> buffer)
return CELL_SYNC_ERROR_ABORT; return CELL_SYNC_ERROR_ABORT;
} }
vm::notify_at(rwm.addr(), 8);
return CELL_OK; return CELL_OK;
} }
error_code cellSyncRwmWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer) error_code cellSyncRwmWrite(ppu_thread& ppu, vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
{ {
cellSync.trace("cellSyncRwmWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer); cellSync.trace("cellSyncRwmWrite(rwm=*0x%x, buffer=*0x%x)", rwm, buffer);
@ -364,10 +355,16 @@ error_code cellSyncRwmWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
} }
// wait until `writers` is zero, set to 1 // wait until `writers` is zero, set to 1
vm::wait_op(rwm.addr(), 8, [&] { return rwm->ctrl.atomic_op(&CellSyncRwm::try_write_begin); }); while (!rwm->ctrl.atomic_op(&CellSyncRwm::try_write_begin))
{
ppu.test_state();
}
// wait until `readers` is zero // wait until `readers` is zero
vm::wait_op(rwm.addr(), 8, [&] { return rwm->ctrl.load().readers == 0; }); while (rwm->ctrl.load().readers != 0)
{
ppu.test_state();
}
// copy data from buffer // copy data from buffer
std::memcpy(rwm->buffer.get_ptr(), buffer.get_ptr(), rwm->size); std::memcpy(rwm->buffer.get_ptr(), buffer.get_ptr(), rwm->size);
@ -375,8 +372,6 @@ error_code cellSyncRwmWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
// sync and clear `readers` and `writers` // sync and clear `readers` and `writers`
rwm->ctrl.exchange({ 0, 0 }); rwm->ctrl.exchange({ 0, 0 });
vm::notify_at(rwm.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -406,8 +401,6 @@ error_code cellSyncRwmTryWrite(vm::ptr<CellSyncRwm> rwm, vm::cptr<void> buffer)
// sync and clear `readers` and `writers` // sync and clear `readers` and `writers`
rwm->ctrl.exchange({ 0, 0 }); rwm->ctrl.exchange({ 0, 0 });
vm::notify_at(rwm.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -446,7 +439,7 @@ error_code cellSyncQueueInitialize(vm::ptr<CellSyncQueue> queue, vm::ptr<u8> buf
return CELL_OK; return CELL_OK;
} }
error_code cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> buffer) error_code cellSyncQueuePush(ppu_thread& ppu, vm::ptr<CellSyncQueue> queue, vm::cptr<void> buffer)
{ {
cellSync.trace("cellSyncQueuePush(queue=*0x%x, buffer=*0x%x)", queue, buffer); cellSync.trace("cellSyncQueuePush(queue=*0x%x, buffer=*0x%x)", queue, buffer);
@ -464,15 +457,16 @@ error_code cellSyncQueuePush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> buffer
u32 position; u32 position;
vm::wait_op(queue.addr(), 8, [&] { return queue->ctrl.atomic_op(&CellSyncQueue::try_push_begin, depth, &position); }); while (!queue->ctrl.atomic_op(&CellSyncQueue::try_push_begin, depth, &position))
{
ppu.test_state();
}
// copy data from the buffer at the position // copy data from the buffer at the position
std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size); std::memcpy(&queue->buffer[position * queue->size], buffer.get_ptr(), queue->size);
queue->ctrl.atomic_op(&CellSyncQueue::push_end); queue->ctrl.atomic_op(&CellSyncQueue::push_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -504,12 +498,10 @@ error_code cellSyncQueueTryPush(vm::ptr<CellSyncQueue> queue, vm::cptr<void> buf
queue->ctrl.atomic_op(&CellSyncQueue::push_end); queue->ctrl.atomic_op(&CellSyncQueue::push_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
error_code cellSyncQueuePop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer) error_code cellSyncQueuePop(ppu_thread& ppu, vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
{ {
cellSync.trace("cellSyncQueuePop(queue=*0x%x, buffer=*0x%x)", queue, buffer); cellSync.trace("cellSyncQueuePop(queue=*0x%x, buffer=*0x%x)", queue, buffer);
@ -527,15 +519,16 @@ error_code cellSyncQueuePop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
u32 position; u32 position;
vm::wait_op(queue.addr(), 8, [&] { return queue->ctrl.atomic_op(&CellSyncQueue::try_pop_begin, depth, &position); }); while (!queue->ctrl.atomic_op(&CellSyncQueue::try_pop_begin, depth, &position))
{
ppu.test_state();
}
// copy data at the position to the buffer // copy data at the position to the buffer
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
queue->ctrl.atomic_op(&CellSyncQueue::pop_end); queue->ctrl.atomic_op(&CellSyncQueue::pop_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -567,12 +560,10 @@ error_code cellSyncQueueTryPop(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffe
queue->ctrl.atomic_op(&CellSyncQueue::pop_end); queue->ctrl.atomic_op(&CellSyncQueue::pop_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
error_code cellSyncQueuePeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer) error_code cellSyncQueuePeek(ppu_thread& ppu, vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
{ {
cellSync.trace("cellSyncQueuePeek(queue=*0x%x, buffer=*0x%x)", queue, buffer); cellSync.trace("cellSyncQueuePeek(queue=*0x%x, buffer=*0x%x)", queue, buffer);
@ -590,15 +581,16 @@ error_code cellSyncQueuePeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buffer)
u32 position; u32 position;
vm::wait_op(queue.addr(), 8, [&] { return queue->ctrl.atomic_op(&CellSyncQueue::try_peek_begin, depth, &position); }); while (!queue->ctrl.atomic_op(&CellSyncQueue::try_peek_begin, depth, &position))
{
ppu.test_state();
}
// copy data at the position to the buffer // copy data at the position to the buffer
std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size); std::memcpy(buffer.get_ptr(), &queue->buffer[position % depth * queue->size], queue->size);
queue->ctrl.atomic_op(&CellSyncQueue::pop_end); queue->ctrl.atomic_op(&CellSyncQueue::pop_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -630,8 +622,6 @@ error_code cellSyncQueueTryPeek(vm::ptr<CellSyncQueue> queue, vm::ptr<void> buff
queue->ctrl.atomic_op(&CellSyncQueue::pop_end); queue->ctrl.atomic_op(&CellSyncQueue::pop_end);
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -654,7 +644,7 @@ error_code cellSyncQueueSize(vm::ptr<CellSyncQueue> queue)
return not_an_error(queue->ctrl.load().count & 0xffffff); return not_an_error(queue->ctrl.load().count & 0xffffff);
} }
error_code cellSyncQueueClear(vm::ptr<CellSyncQueue> queue) error_code cellSyncQueueClear(ppu_thread& ppu, vm::ptr<CellSyncQueue> queue)
{ {
cellSync.trace("cellSyncQueueClear(queue=*0x%x)", queue); cellSync.trace("cellSyncQueueClear(queue=*0x%x)", queue);
@ -670,13 +660,18 @@ error_code cellSyncQueueClear(vm::ptr<CellSyncQueue> queue)
const u32 depth = queue->check_depth(); const u32 depth = queue->check_depth();
vm::wait_op(queue.addr(), 8, [&] { return queue->ctrl.atomic_op(&CellSyncQueue::try_clear_begin_1); }); while (!queue->ctrl.atomic_op(&CellSyncQueue::try_clear_begin_1))
vm::wait_op(queue.addr(), 8, [&] { return queue->ctrl.atomic_op(&CellSyncQueue::try_clear_begin_2); }); {
ppu.test_state();
}
while (!queue->ctrl.atomic_op(&CellSyncQueue::try_clear_begin_2))
{
ppu.test_state();
}
queue->ctrl.exchange({ 0, 0 }); queue->ctrl.exchange({ 0, 0 });
vm::notify_at(queue.addr(), 8);
return CELL_OK; return CELL_OK;
} }
@ -1107,7 +1102,7 @@ error_code _cellSyncLFQueuePushBody(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> qu
break; break;
} }
thread_ctrl::wait_for(1000); // hack ppu.test_state();
} }
const s32 depth = queue->m_depth; const s32 depth = queue->m_depth;
@ -1402,7 +1397,7 @@ error_code _cellSyncLFQueuePopBody(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> que
break; break;
} }
thread_ctrl::wait_for(1000); // hack ppu.test_state();
} }
const s32 depth = queue->m_depth; const s32 depth = queue->m_depth;

View file

@ -77,6 +77,7 @@ struct vdec_thread : ppu_thread
std::mutex mutex; std::mutex mutex;
std::queue<vdec_frame> out; std::queue<vdec_frame> out;
u32 max_frames = 20;
vdec_thread(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg, u32 prio, u32 stack) vdec_thread(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg, u32 prio, u32 stack)
: ppu_thread("HLE Video Decoder", prio, stack) : ppu_thread("HLE Video Decoder", prio, stack)
@ -328,7 +329,7 @@ struct vdec_thread : ppu_thread
std::lock_guard<std::mutex>{mutex}, out.push(std::move(frame)); std::lock_guard<std::mutex>{mutex}, out.push(std::move(frame));
cb_func(*this, id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg); cb_func(*this, id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
if (vcmd == vdec_cmd::decode) if (vcmd == vdec_cmd::decode)
@ -338,9 +339,9 @@ struct vdec_thread : ppu_thread
} }
cb_func(*this, id, vcmd == vdec_cmd::decode ? CELL_VDEC_MSG_TYPE_AUDONE : CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg); cb_func(*this, id, vcmd == vdec_cmd::decode ? CELL_VDEC_MSG_TYPE_AUDONE : CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
while (std::lock_guard<std::mutex>{mutex}, out.size() > 60) while (std::lock_guard<std::mutex>{mutex}, out.size() > max_frames)
{ {
thread_ctrl::wait(); thread_ctrl::wait();
} }
@ -444,8 +445,14 @@ s32 cellVdecClose(ppu_thread& ppu, u32 handle)
return CELL_VDEC_ERROR_ARG; return CELL_VDEC_ERROR_ARG;
} }
lv2_obj::sleep(ppu, -1); lv2_obj::sleep(ppu);
{
std::lock_guard<std::mutex> lock(vdec->mutex);
vdec->cmd_push({vdec_cmd::close, 0}); vdec->cmd_push({vdec_cmd::close, 0});
vdec->out = decltype(vdec->out){};
}
vdec->notify(); vdec->notify();
vdec->join(); vdec->join();
idm::remove<ppu_thread>(handle); idm::remove<ppu_thread>(handle);
@ -534,7 +541,7 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
vdec->out.pop(); vdec->out.pop();
if (vdec->out.size() <= 60) if (vdec->out.size() <= vdec->max_frames)
{ {
vdec->notify(); vdec->notify();
} }

View file

@ -348,7 +348,7 @@ struct surmixer_thread : ppu_thread
if (g_surmx.cb) if (g_surmx.cb)
{ {
g_surmx.cb(*this, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256); g_surmx.cb(*this, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256);
lv2_obj::sleep(*this, -1); lv2_obj::sleep(*this);
} }
//u64 stamp1 = get_system_time(); //u64 stamp1 = get_system_time();

View file

@ -120,8 +120,10 @@ s32 sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeou
return CELL_EINVAL; return CELL_EINVAL;
} }
for (u32 i = 0; i < 300; i++) for (u32 i = 0; i < 10; i++)
{ {
busy_wait();
if (lwmutex->vars.owner.load() == lwmutex_free) if (lwmutex->vars.owner.load() == lwmutex_free)
{ {
if (lwmutex->vars.owner.compare_and_swap_test(lwmutex_free, tid)) if (lwmutex->vars.owner.compare_and_swap_test(lwmutex_free, tid))

View file

@ -45,7 +45,7 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u6
// Dirty hack for sound: confirm the creation of _mxr000 event queue // Dirty hack for sound: confirm the creation of _mxr000 event queue
if (threadname && std::memcmp(threadname.get_ptr(), "_cellsurMixerMain", 18) == 0) if (threadname && std::memcmp(threadname.get_ptr(), "_cellsurMixerMain", 18) == 0)
{ {
lv2_obj::sleep(ppu, -1); lv2_obj::sleep(ppu);
while (!idm::select<lv2_obj, lv2_event_queue>([](u32, lv2_event_queue& eq) while (!idm::select<lv2_obj, lv2_event_queue>([](u32, lv2_event_queue& eq)
{ {
@ -54,6 +54,8 @@ s32 sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u6
{ {
thread_ctrl::wait_for(50000); thread_ctrl::wait_for(50000);
} }
ppu.test_state();
} }
return CELL_OK; return CELL_OK;

View file

@ -4,30 +4,34 @@
#include "sysPrxForUser.h" #include "sysPrxForUser.h"
#include "Emu/Memory/wait_engine.h"
extern logs::channel sysPrxForUser; extern logs::channel sysPrxForUser;
void sys_spinlock_initialize(vm::ptr<atomic_be_t<u32>> lock) void sys_spinlock_initialize(vm::ptr<atomic_be_t<u32>> lock)
{ {
sysPrxForUser.trace("sys_spinlock_initialize(lock=*0x%x)", lock); sysPrxForUser.trace("sys_spinlock_initialize(lock=*0x%x)", lock);
lock->exchange(0); if (*lock)
{
*lock = 0;
}
} }
void sys_spinlock_lock(vm::ptr<atomic_be_t<u32>> lock) void sys_spinlock_lock(ppu_thread& ppu, vm::ptr<atomic_be_t<u32>> lock)
{ {
sysPrxForUser.trace("sys_spinlock_lock(lock=*0x%x)", lock); sysPrxForUser.trace("sys_spinlock_lock(lock=*0x%x)", lock);
// Try exchange with 0xabadcafe, repeat until exchanged with 0 // Try to exchange with 0xabadcafe, repeat until exchanged with 0
vm::wait_op(lock.addr(), 4, [&] { return lock->exchange(0xabadcafe) == 0; }); while (*lock || lock->exchange(0xabadcafe))
{
ppu.test_state();
}
} }
s32 sys_spinlock_trylock(vm::ptr<atomic_be_t<u32>> lock) s32 sys_spinlock_trylock(vm::ptr<atomic_be_t<u32>> lock)
{ {
sysPrxForUser.trace("sys_spinlock_trylock(lock=*0x%x)", lock); sysPrxForUser.trace("sys_spinlock_trylock(lock=*0x%x)", lock);
if (lock->exchange(0xabadcafe)) if (*lock || lock->exchange(0xabadcafe))
{ {
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -39,9 +43,7 @@ void sys_spinlock_unlock(vm::ptr<atomic_be_t<u32>> lock)
{ {
sysPrxForUser.trace("sys_spinlock_unlock(lock=*0x%x)", lock); sysPrxForUser.trace("sys_spinlock_unlock(lock=*0x%x)", lock);
lock->exchange(0); *lock = 0;
vm::notify_at(lock.addr(), 4);
} }
void sysPrxForUser_sys_spinlock_init() void sysPrxForUser_sys_spinlock_init()

View file

@ -145,8 +145,8 @@ extern void ppu_execute_function(ppu_thread& ppu, u32 index)
{ {
if (index < g_ppu_function_cache.size()) if (index < g_ppu_function_cache.size())
{ {
// If autopause occures, check_status() will hold the thread until unpaused. // If autopause occures, check_status() will hold the thread until unpaused
if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_state()) throw cpu_flag::ret; if (debug::autopause::pause_function(g_ppu_fnid_cache[index])) ppu.test_state();
if (const auto func = g_ppu_function_cache[index]) if (const auto func = g_ppu_function_cache[index])
{ {

View file

@ -51,6 +51,31 @@ extern u64 get_system_time();
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }
enum class join_status : u32
{
joinable = 0,
detached = 0u-1,
exited = 0u-2,
zombie = 0u-3,
};
template <>
void fmt_class_string<join_status>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](join_status js)
{
switch (js)
{
case join_status::joinable: return "";
case join_status::detached: return "detached";
case join_status::zombie: return "zombie";
case join_status::exited: return "exited";
}
return unknown;
});
}
enum class ppu_decoder_type enum class ppu_decoder_type
{ {
precise, precise,
@ -197,7 +222,32 @@ std::string ppu_thread::dump() const
{ {
std::string ret = cpu_thread::dump(); std::string ret = cpu_thread::dump();
ret += fmt::format("Priority: %d\n", +prio); ret += fmt::format("Priority: %d\n", +prio);
ret += fmt::format("Last function: %s\n", last_function ? last_function : ""); ret += fmt::format("Stack: 0x%x..0x%x\n", stack_addr, stack_addr + stack_size - 1);
ret += fmt::format("Joiner: %s\n", join_status(joiner.load()));
ret += fmt::format("Commands: %u\n", cmd_queue.size());
const auto _func = last_function;
if (_func)
{
ret += "Last function: ";
ret += _func;
ret += '\n';
}
if (const auto _time = start_time)
{
ret += fmt::format("Waiting: %fs\n", (get_system_time() - _time) / 1000000.);
}
else
{
ret += '\n';
}
if (!_func)
{
ret += '\n';
}
ret += "\nRegisters:\n=========\n"; ret += "\nRegisters:\n=========\n";
for (uint i = 0; i < 32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, gpr[i]); for (uint i = 0; i < 32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, gpr[i]);
@ -289,7 +339,7 @@ void ppu_thread::cpu_task()
} }
case ppu_cmd::sleep: case ppu_cmd::sleep:
{ {
cmd_pop(), lv2_obj::sleep(*this, -1); cmd_pop(), lv2_obj::sleep(*this);
break; break;
} }
default: default:
@ -400,6 +450,7 @@ ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
, prio(prio) , prio(prio)
, stack_size(std::max<u32>(stack, 0x4000)) , stack_size(std::max<u32>(stack, 0x4000))
, stack_addr(vm::alloc(stack_size, vm::stack)) , stack_addr(vm::alloc(stack_size, vm::stack))
, start_time(get_system_time())
, m_name(name) , m_name(name)
{ {
if (!stack_addr) if (!stack_addr)
@ -505,7 +556,14 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc)
{ {
if (last_function) if (last_function)
{ {
LOG_WARNING(PPU, "'%s' aborted (%fs)", last_function, (get_system_time() - gpr[10]) / 1000000.); if (start_time)
{
LOG_WARNING(PPU, "'%s' aborted (%fs)", last_function, (get_system_time() - start_time) / 1000000.);
}
else
{
LOG_WARNING(PPU, "'%s' aborted", last_function);
}
} }
last_function = old_func; last_function = old_func;
@ -612,7 +670,7 @@ extern void sse_cellbe_stvrx(u64 addr, __m128i a);
static void ppu_check(ppu_thread& ppu, u64 addr) static void ppu_check(ppu_thread& ppu, u64 addr)
{ {
ppu.cia = addr; ppu.cia = addr;
ppu.check_state(); ppu.test_state();
} }
static void ppu_trace(u64 addr) static void ppu_trace(u64 addr)

View file

@ -133,6 +133,7 @@ public:
cmd64 cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status(). cmd64 cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
cmd64 cmd_get(u32 index) { return cmd_queue[cmd_queue.peek() + index].load(); } cmd64 cmd_get(u32 index) { return cmd_queue[cmd_queue.peek() + index].load(); }
u64 start_time{0}; // Sleep start timepoint
const char* last_function{}; // Last function name for diagnosis, optimized for speed. const char* last_function{}; // Last function name for diagnosis, optimized for speed.
const std::string m_name; // Thread name const std::string m_name; // Thread name

View file

@ -50,7 +50,7 @@ void spu_interpreter::set_interrupt_status(SPUThread& spu, spu_opcode_t op)
spu.set_interrupt_status(false); spu.set_interrupt_status(false);
} }
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST) > SPU_EVENT_INTR_ENABLED) if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST & spu.ch_event_mask) > SPU_EVENT_INTR_ENABLED)
{ {
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED; spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED;
spu.srr0 = std::exchange(spu.pc, -4) + 4; spu.srr0 = std::exchange(spu.pc, -4) + 4;
@ -89,10 +89,16 @@ void spu_interpreter::MFSPR(SPUThread& spu, spu_opcode_t op)
void spu_interpreter::RDCH(SPUThread& spu, spu_opcode_t op) void spu_interpreter::RDCH(SPUThread& spu, spu_opcode_t op)
{ {
if (!spu.get_ch_value(op.ra, spu.gpr[op.rt]._u32[3])) u32 result;
if (!spu.get_ch_value(op.ra, result))
{ {
spu.pc -= 4; spu.pc -= 4;
} }
else
{
spu.gpr[op.rt] = v128::from32r(result);
}
} }
void spu_interpreter::RCHCNT(SPUThread& spu, spu_opcode_t op) void spu_interpreter::RCHCNT(SPUThread& spu, spu_opcode_t op)

View file

@ -26,7 +26,7 @@ void spu_recompiler_base::enter(SPUThread& spu)
const auto func = spu.spu_db->analyse(_ls, spu.pc); const auto func = spu.spu_db->analyse(_ls, spu.pc);
// Reset callstack if necessary // Reset callstack if necessary
if (func->does_reset_stack && spu.recursion_level) if ((func->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
{ {
spu.state += cpu_flag::ret; spu.state += cpu_flag::ret;
return; return;
@ -77,7 +77,7 @@ void spu_recompiler_base::enter(SPUThread& spu)
spu.pc = res & 0x3fffc; spu.pc = res & 0x3fffc;
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST) > SPU_EVENT_INTR_ENABLED) if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST & spu.ch_event_mask) > SPU_EVENT_INTR_ENABLED)
{ {
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED; spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED;
spu.srr0 = std::exchange(spu.pc, 0); spu.srr0 = std::exchange(spu.pc, 0);

View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "Utilities/lockless.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -1060,18 +1061,8 @@ bool SPUThread::stop_and_signal(u32 code)
{ {
case 0x000: case 0x000:
{ {
// Hack: wait for an instruction become available // Hack: execute as NOP
while (vm::ps3::read32(offset + pc) == 0) return true;
{
if (test(state) && check_state())
{
return false;
}
thread_ctrl::wait_for(1000);
}
return false;
} }
case 0x001: case 0x001:
@ -1086,23 +1077,6 @@ bool SPUThread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x003:
{
const auto found = m_addr_to_hle_function_map.find(pc);
if (found == m_addr_to_hle_function_map.end())
{
fmt::throw_exception("HLE function not registered (PC=0x%05x)" HERE, pc);
}
if (const auto return_to_caller = found->second(*this))
{
pc = (gpr[0]._u32[3] & 0x3fffc) - 4;
}
return true;
}
case 0x110: case 0x110:
{ {
/* ===== sys_spu_thread_receive_event ===== */ /* ===== sys_spu_thread_receive_event ===== */

View file

@ -986,8 +986,11 @@ extern void ppu_execute_syscall(ppu_thread& ppu, u64 code)
{ {
if (code < g_ppu_syscall_table.size()) if (code < g_ppu_syscall_table.size())
{ {
// If autopause occures, check_status() will hold the thread till unpaused. // If autopause occures, check_status() will hold the thread till unpaused
if (debug::autopause::pause_syscall(code) && ppu.check_state()) throw cpu_flag::ret; if (debug::autopause::pause_syscall(code))
{
ppu.test_state();
}
if (auto func = g_ppu_syscall_table[code]) if (auto func = g_ppu_syscall_table[code])
{ {
@ -1026,10 +1029,12 @@ DECLARE(lv2_obj::g_waiting);
// Amount of PPU threads running simultaneously (must be 2) // Amount of PPU threads running simultaneously (must be 2)
cfg::int_entry<1, 16> g_cfg_ppu_threads(cfg::root.core, "PPU Threads", 2); cfg::int_entry<1, 16> g_cfg_ppu_threads(cfg::root.core, "PPU Threads", 2);
void lv2_obj::sleep(named_thread& thread, u64 wait_until) void lv2_obj::sleep_timeout(named_thread& thread, u64 timeout)
{ {
semaphore_lock lock(g_mutex); semaphore_lock lock(g_mutex);
const u64 start_time = get_system_time();
if (auto ppu = dynamic_cast<ppu_thread*>(&thread)) if (auto ppu = dynamic_cast<ppu_thread*>(&thread))
{ {
sys_ppu_thread.trace("sleep() - waiting (%zu)", g_pending.size()); sys_ppu_thread.trace("sleep() - waiting (%zu)", g_pending.size());
@ -1039,21 +1044,27 @@ void lv2_obj::sleep(named_thread& thread, u64 wait_until)
if (!test(val, cpu_flag::signal)) if (!test(val, cpu_flag::signal))
{ {
val += cpu_flag::suspend; val += cpu_flag::suspend;
val += cpu_flag::is_waiting;
} }
}); });
if (test(state, cpu_flag::signal)) if (test(state, cpu_flag::signal))
{ {
sys_ppu_thread.error("sleep() failed (signaled)"); sys_ppu_thread.trace("sleep() failed (signaled)");
return;
} }
// Find and remove the thread // Find and remove the thread
unqueue(g_ppu, ppu); unqueue(g_ppu, ppu);
unqueue(g_pending, ppu); unqueue(g_pending, ppu);
ppu->start_time = start_time;
} }
if (wait_until < -2) if (timeout)
{ {
const u64 wait_until = start_time + timeout;
// Register timeout if necessary // Register timeout if necessary
for (auto it = g_waiting.begin(), end = g_waiting.end(); it != end; it++) for (auto it = g_waiting.begin(), end = g_waiting.end(); it != end; it++)
{ {
@ -1160,6 +1171,7 @@ void lv2_obj::schedule_all()
{ {
sys_ppu_thread.trace("schedule(): %s", target->id); sys_ppu_thread.trace("schedule(): %s", target->id);
target->state ^= (cpu_flag::signal + cpu_flag::suspend); target->state ^= (cpu_flag::signal + cpu_flag::suspend);
target->start_time = 0;
if (target->get() != thread_ctrl::get_current()) if (target->get() != thread_ctrl::get_current())
{ {

View file

@ -99,8 +99,9 @@ error_code sys_cond_signal(ppu_thread& ppu, u32 cond_id)
if (cond.ret) if (cond.ret)
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cond.ret); cond->awake(*cond.ret);
ppu.check_state(); ppu.test_state();
} }
return CELL_OK; return CELL_OK;
@ -139,8 +140,9 @@ error_code sys_cond_signal_all(ppu_thread& ppu, u32 cond_id)
if (cond.ret) if (cond.ret)
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cond.ret); cond->awake(*cond.ret);
ppu.check_state(); ppu.test_state();
} }
return CELL_OK; return CELL_OK;
@ -182,8 +184,9 @@ error_code sys_cond_signal_to(ppu_thread& ppu, u32 cond_id, u32 thread_id)
if (cond.ret && cond.ret != (cpu_thread*)(1)) if (cond.ret && cond.ret != (cpu_thread*)(1))
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cond.ret); cond->awake(*cond.ret);
ppu.check_state(); ppu.test_state();
} }
else if (!cond.ret) else if (!cond.ret)
{ {
@ -197,8 +200,6 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
{ {
sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout); sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto cond = idm::get<lv2_obj, lv2_cond>(cond_id, [&](lv2_cond& cond) const auto cond = idm::get<lv2_obj, lv2_cond>(cond_id, [&](lv2_cond& cond)
{ {
// Add a "promise" to add a waiter // Add a "promise" to add a waiter
@ -226,11 +227,15 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
// Register waiter // Register waiter
cond->sq.emplace_back(&ppu); cond->sq.emplace_back(&ppu);
cond->sleep(ppu, start_time, timeout); cond->sleep(ppu, timeout);
// Unlock the mutex // Unlock the mutex
cond->mutex->lock_count = 0; cond->mutex->lock_count = 0;
cond->mutex->reown<ppu_thread>();
if (auto cpu = cond->mutex->reown<ppu_thread>())
{
cond->mutex->awake(*cpu);
}
// Further function result // Further function result
ppu.gpr[3] = CELL_OK; ppu.gpr[3] = CELL_OK;
@ -240,7 +245,7 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -278,12 +283,6 @@ error_code sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
// Restore the recursive value // Restore the recursive value
cond->mutex->lock_count = cond.ret; cond->mutex->lock_count = cond.ret;
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]);
if (ppu.gpr[3] == CELL_ETIMEDOUT)
{
return not_an_error(CELL_ETIMEDOUT);
}
return CELL_OK;
} }

View file

@ -172,6 +172,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
if (queue->type == SYS_PPU_QUEUE) if (queue->type == SYS_PPU_QUEUE)
{ {
static_cast<ppu_thread&>(*cpu).gpr[3] = CELL_ECANCELED; static_cast<ppu_thread&>(*cpu).gpr[3] = CELL_ECANCELED;
ppu.state += cpu_flag::is_waiting;
queue->awake(*cpu); queue->awake(*cpu);
} }
else else
@ -183,8 +184,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
} }
} }
ppu.check_state(); ppu.test_state();
return CELL_OK; return CELL_OK;
} }
@ -226,8 +226,6 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
{ {
sys_event.trace("sys_event_queue_receive(equeue_id=0x%x, *0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout); sys_event.trace("sys_event_queue_receive(equeue_id=0x%x, *0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto queue = idm::get<lv2_obj, lv2_event_queue>(equeue_id, [&](lv2_event_queue& queue) -> CellError const auto queue = idm::get<lv2_obj, lv2_event_queue>(equeue_id, [&](lv2_event_queue& queue) -> CellError
{ {
if (queue.type != SYS_PPU_QUEUE) if (queue.type != SYS_PPU_QUEUE)
@ -240,7 +238,7 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
if (queue.events.empty()) if (queue.events.empty())
{ {
queue.sq.emplace_back(&ppu); queue.sq.emplace_back(&ppu);
queue.sleep(ppu, start_time, timeout); queue.sleep(ppu, timeout);
return CELL_EBUSY; return CELL_EBUSY;
} }
@ -273,7 +271,7 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -297,7 +295,7 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -423,6 +421,8 @@ error_code sys_event_port_send(ppu_thread& ppu, u32 eport_id, u64 data1, u64 dat
{ {
sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
ppu.state += cpu_flag::is_waiting;
const auto port = idm::get<lv2_obj, lv2_event_port>(eport_id, [&](lv2_event_port& port) -> CellError const auto port = idm::get<lv2_obj, lv2_event_port>(eport_id, [&](lv2_event_port& port) -> CellError
{ {
if (const auto queue = port.queue.lock()) if (const auto queue = port.queue.lock())
@ -455,6 +455,6 @@ error_code sys_event_port_send(ppu_thread& ppu, u32 eport_id, u64 data1, u64 dat
return port.ret; return port.ret;
} }
ppu.check_state(); ppu.test_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -91,8 +91,6 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
{ {
sys_event_flag.trace("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout); sys_event_flag.trace("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
// Fix function arguments for external access // Fix function arguments for external access
ppu.gpr[3] = -1; ppu.gpr[3] = -1;
ppu.gpr[4] = bitptn; ppu.gpr[4] = bitptn;
@ -130,7 +128,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
flag.waiters++; flag.waiters++;
flag.sq.emplace_back(&ppu); flag.sq.emplace_back(&ppu);
flag.sleep(ppu, start_time, timeout); flag.sleep(ppu, timeout);
return CELL_EBUSY; return CELL_EBUSY;
}); });
@ -156,7 +154,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -182,7 +180,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
} }
} }
ppu.check_state(); ppu.test_state();
if (result) *result = ppu.gpr[6]; if (result) *result = ppu.gpr[6];
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -223,6 +221,12 @@ error_code sys_event_flag_trywait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> res
error_code sys_event_flag_set(u32 id, u64 bitptn) error_code sys_event_flag_set(u32 id, u64 bitptn)
{ {
// Warning: may be called from SPU thread. // Warning: may be called from SPU thread.
auto cpu = get_current_cpu_thread();
if (cpu && cpu->id_type() != 1)
{
cpu = nullptr;
}
sys_event_flag.trace("sys_event_flag_set(id=0x%x, bitptn=0x%llx)", id, bitptn); sys_event_flag.trace("sys_event_flag_set(id=0x%x, bitptn=0x%llx)", id, bitptn);
@ -252,9 +256,10 @@ error_code sys_event_flag_set(u32 id, u64 bitptn)
} }
// Process all waiters in single atomic op // Process all waiters in single atomic op
flag->pattern.atomic_op([&](u64& value) const u32 count = flag->pattern.atomic_op([&](u64& value)
{ {
value |= bitptn; value |= bitptn;
u32 count = 0;
for (auto cpu : flag->sq) for (auto cpu : flag->sq)
{ {
@ -266,10 +271,22 @@ error_code sys_event_flag_set(u32 id, u64 bitptn)
if (lv2_event_flag::check_pattern(value, pattern, mode, &ppu.gpr[6])) if (lv2_event_flag::check_pattern(value, pattern, mode, &ppu.gpr[6]))
{ {
ppu.gpr[3] = CELL_OK; ppu.gpr[3] = CELL_OK;
count++;
} }
} }
return count;
}); });
if (!count)
{
return CELL_OK;
}
else if (cpu)
{
cpu->state += cpu_flag::is_waiting;
}
// Remove waiters // Remove waiters
const auto tail = std::remove_if(flag->sq.begin(), flag->sq.end(), [&](cpu_thread* cpu) const auto tail = std::remove_if(flag->sq.begin(), flag->sq.end(), [&](cpu_thread* cpu)
{ {
@ -288,14 +305,7 @@ error_code sys_event_flag_set(u32 id, u64 bitptn)
flag->sq.erase(tail, flag->sq.end()); flag->sq.erase(tail, flag->sq.end());
} }
if (auto cpu = get_current_cpu_thread()) if (cpu) cpu->test_state();
{
if (cpu->id_type() == 1)
{
static_cast<ppu_thread&>(*cpu).check_state();
}
}
return CELL_OK; return CELL_OK;
} }
@ -342,6 +352,8 @@ error_code sys_event_flag_cancel(ppu_thread& ppu, u32 id, vm::ptr<u32> num)
// Signal all threads to return CELL_ECANCELED // Signal all threads to return CELL_ECANCELED
while (auto thread = flag->schedule<ppu_thread>(flag->sq, flag->protocol)) while (auto thread = flag->schedule<ppu_thread>(flag->sq, flag->protocol))
{ {
ppu.state += cpu_flag::is_waiting;
auto& ppu = static_cast<ppu_thread&>(*thread); auto& ppu = static_cast<ppu_thread&>(*thread);
ppu.gpr[3] = CELL_ECANCELED; ppu.gpr[3] = CELL_ECANCELED;
@ -352,10 +364,8 @@ error_code sys_event_flag_cancel(ppu_thread& ppu, u32 id, vm::ptr<u32> num)
} }
} }
ppu.test_state();
if (num) *num = value; if (num) *num = value;
ppu.check_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -132,8 +132,9 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u3
if (cond.ret) if (cond.ret)
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cond.ret); cond->awake(*cond.ret);
ppu.check_state(); ppu.test_state();
} }
else if (mode == 2) else if (mode == 2)
{ {
@ -211,12 +212,13 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
for (auto cpu : threads) for (auto cpu : threads)
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cpu); cond->awake(*cpu);
} }
if (threads.size()) if (threads.size())
{ {
ppu.check_state(); ppu.test_state();
} }
if (mode == 1) if (mode == 1)
@ -232,8 +234,6 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
{ {
sys_lwcond.trace("_sys_lwcond_queue_wait(lwcond_id=0x%x, lwmutex_id=0x%x, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout); sys_lwcond.trace("_sys_lwcond_queue_wait(lwcond_id=0x%x, lwmutex_id=0x%x, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
std::shared_ptr<lv2_lwmutex> mutex; std::shared_ptr<lv2_lwmutex> mutex;
const auto cond = idm::get<lv2_obj, lv2_lwcond>(lwcond_id, [&](lv2_lwcond& cond) -> cpu_thread* const auto cond = idm::get<lv2_obj, lv2_lwcond>(lwcond_id, [&](lv2_lwcond& cond) -> cpu_thread*
@ -250,7 +250,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
// Add a waiter // Add a waiter
cond.waiters++; cond.waiters++;
cond.sq.emplace_back(&ppu); cond.sq.emplace_back(&ppu);
cond.sleep(ppu, start_time, timeout); cond.sleep(ppu, timeout);
// Process lwmutex sleep queue // Process lwmutex sleep queue
if (const auto cpu = mutex->schedule<ppu_thread>(mutex->sq, mutex->protocol)) if (const auto cpu = mutex->schedule<ppu_thread>(mutex->sq, mutex->protocol))
@ -269,6 +269,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
if (cond.ret) if (cond.ret)
{ {
ppu.state += cpu_flag::is_waiting;
cond->awake(*cond.ret); cond->awake(*cond.ret);
} }
@ -278,7 +279,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -311,6 +312,6 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
} }
// Return cause // Return cause
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }

View file

@ -73,8 +73,6 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
{ {
sys_lwmutex.trace("_sys_lwmutex_lock(lwmutex_id=0x%x, timeout=0x%llx)", lwmutex_id, timeout); sys_lwmutex.trace("_sys_lwmutex_lock(lwmutex_id=0x%x, timeout=0x%llx)", lwmutex_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto mutex = idm::get<lv2_obj, lv2_lwmutex>(lwmutex_id, [&](lv2_lwmutex& mutex) const auto mutex = idm::get<lv2_obj, lv2_lwmutex>(lwmutex_id, [&](lv2_lwmutex& mutex)
{ {
if (u32 value = mutex.signaled) if (u32 value = mutex.signaled)
@ -96,7 +94,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
} }
mutex.sq.emplace_back(&ppu); mutex.sq.emplace_back(&ppu);
mutex.sleep(ppu, start_time, timeout); mutex.sleep(ppu, timeout);
return false; return false;
}); });
@ -116,7 +114,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -140,7 +138,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -198,8 +196,9 @@ error_code _sys_lwmutex_unlock(ppu_thread& ppu, u32 lwmutex_id)
if (mutex.ret) if (mutex.ret)
{ {
ppu.state += cpu_flag::is_waiting;
mutex->awake(*mutex.ret); mutex->awake(*mutex.ret);
ppu.check_state(); ppu.test_state();
} }
return CELL_OK; return CELL_OK;

View file

@ -102,8 +102,6 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
{ {
sys_mutex.trace("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout); sys_mutex.trace("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto mutex = idm::get<lv2_obj, lv2_mutex>(mutex_id, [&](lv2_mutex& mutex) const auto mutex = idm::get<lv2_obj, lv2_mutex>(mutex_id, [&](lv2_mutex& mutex)
{ {
CellError result = mutex.try_lock(ppu.id); CellError result = mutex.try_lock(ppu.id);
@ -118,7 +116,7 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
} }
else else
{ {
mutex.sleep(ppu, start_time, timeout); mutex.sleep(ppu, timeout);
} }
} }
@ -148,7 +146,7 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -172,7 +170,7 @@ error_code sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -221,12 +219,17 @@ error_code sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id)
{ {
semaphore_lock lock(mutex->mutex); semaphore_lock lock(mutex->mutex);
mutex->reown<ppu_thread>(); if (auto cpu = mutex->reown<ppu_thread>())
{
ppu.state += cpu_flag::is_waiting;
mutex->awake(*cpu);
}
} }
else if (mutex.ret) else if (mutex.ret)
{ {
return mutex.ret; return mutex.ret;
} }
ppu.test_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -128,17 +128,17 @@ struct lv2_mutex final : lv2_obj
} }
template <typename T> template <typename T>
void reown() T* reown()
{ {
if (auto cpu = schedule<T>(sq, protocol)) if (auto cpu = schedule<T>(sq, protocol))
{ {
owner = cpu->id << 1 | !sq.empty(); owner = cpu->id << 1 | !sq.empty();
return static_cast<T*>(cpu);
awake(*cpu);
} }
else else
{ {
owner = 0; owner = 0;
return nullptr;
} }
} }
}; };

View file

@ -16,6 +16,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
sys_ppu_thread.trace("_sys_ppu_thread_exit(errorcode=0x%llx)", errorcode); sys_ppu_thread.trace("_sys_ppu_thread_exit(errorcode=0x%llx)", errorcode);
ppu.state += cpu_flag::exit; ppu.state += cpu_flag::exit;
ppu.state += cpu_flag::is_waiting;
// Get joiner ID // Get joiner ID
const u32 jid = ppu.joiner.fetch_op([](u32& value) const u32 jid = ppu.joiner.fetch_op([](u32& value)
@ -48,7 +49,7 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
} }
// Unqueue // Unqueue
lv2_obj::sleep(ppu, -1); lv2_obj::sleep(ppu);
// Remove suspend state (TODO) // Remove suspend state (TODO)
ppu.state -= cpu_flag::suspend; ppu.state -= cpu_flag::suspend;
@ -64,8 +65,9 @@ void sys_ppu_thread_yield(ppu_thread& ppu)
{ {
sys_ppu_thread.trace("sys_ppu_thread_yield()"); sys_ppu_thread.trace("sys_ppu_thread_yield()");
ppu.state += cpu_flag::is_waiting;
lv2_obj::awake(ppu, -4); lv2_obj::awake(ppu, -4);
ppu.check_state(); ppu.test_state();
} }
error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr) error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr)
@ -104,7 +106,7 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
if (!result) if (!result)
{ {
lv2_obj::sleep(ppu, -1); lv2_obj::sleep(ppu);
} }
return result; return result;
@ -126,12 +128,14 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
// Get the exit status from the register // Get the exit status from the register
if (vptr) if (vptr)
{ {
ppu.test_state();
*vptr = thread->gpr[3]; *vptr = thread->gpr[3];
} }
// Cleanup // Cleanup
idm::remove<ppu_thread>(thread->id); idm::remove<ppu_thread>(thread->id);
ppu.test_state();
return CELL_OK; return CELL_OK;
} }
@ -207,6 +211,7 @@ error_code sys_ppu_thread_set_priority(ppu_thread& ppu, u32 thread_id, s32 prio)
{ {
if (thread.prio != prio && thread.prio.exchange(prio) != prio) if (thread.prio != prio && thread.prio.exchange(prio) != prio)
{ {
ppu.state += cpu_flag::is_waiting;
lv2_obj::awake(thread, prio); lv2_obj::awake(thread, prio);
} }
}); });
@ -216,11 +221,7 @@ error_code sys_ppu_thread_set_priority(ppu_thread& ppu, u32 thread_id, s32 prio)
return CELL_ESRCH; return CELL_ESRCH;
} }
if (&ppu == thread) ppu.test_state();
{
ppu.check_state();
}
return CELL_OK; return CELL_OK;
} }
@ -338,6 +339,7 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id)
const auto thread = idm::get<ppu_thread>(thread_id, [&](ppu_thread& thread) const auto thread = idm::get<ppu_thread>(thread_id, [&](ppu_thread& thread)
{ {
ppu.state += cpu_flag::is_waiting;
lv2_obj::awake(thread, -2); lv2_obj::awake(thread, -2);
}); });
@ -356,7 +358,7 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id)
thread->notify(); thread->notify();
} }
ppu.check_state(); ppu.test_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -79,8 +79,6 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
{ {
sys_rwlock.trace("sys_rwlock_rlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout); sys_rwlock.trace("sys_rwlock_rlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock) const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock)
{ {
const s64 val = rwlock.owner; const s64 val = rwlock.owner;
@ -110,7 +108,7 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
if (_old > 0 || _old & 1) if (_old > 0 || _old & 1)
{ {
rwlock.rq.emplace_back(&ppu); rwlock.rq.emplace_back(&ppu);
rwlock.sleep(ppu, start_time, timeout); rwlock.sleep(ppu, timeout);
return false; return false;
} }
@ -133,7 +131,7 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -157,7 +155,7 @@ error_code sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -243,6 +241,8 @@ error_code sys_rwlock_runlock(ppu_thread& ppu, u32 rw_lock_id)
{ {
if (const auto cpu = rwlock->schedule<ppu_thread>(rwlock->wq, rwlock->protocol)) if (const auto cpu = rwlock->schedule<ppu_thread>(rwlock->wq, rwlock->protocol))
{ {
ppu.state += cpu_flag::is_waiting;
rwlock->owner = cpu->id << 1 | !rwlock->wq.empty(); rwlock->owner = cpu->id << 1 | !rwlock->wq.empty();
rwlock->awake(*cpu); rwlock->awake(*cpu);
@ -256,7 +256,7 @@ error_code sys_rwlock_runlock(ppu_thread& ppu, u32 rw_lock_id)
} }
} }
ppu.check_state(); ppu.test_state();
return CELL_OK; return CELL_OK;
} }
@ -264,8 +264,6 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
{ {
sys_rwlock.trace("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout); sys_rwlock.trace("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock) const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock)
{ {
const s64 val = rwlock.owner; const s64 val = rwlock.owner;
@ -299,7 +297,7 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
if (_old != 0) if (_old != 0)
{ {
rwlock.wq.emplace_back(&ppu); rwlock.wq.emplace_back(&ppu);
rwlock.sleep(ppu, start_time, timeout); rwlock.sleep(ppu, timeout);
return false; return false;
} }
@ -327,7 +325,7 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -346,6 +344,8 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
while (auto cpu = rwlock->schedule<ppu_thread>(rwlock->rq, SYS_SYNC_PRIORITY)) while (auto cpu = rwlock->schedule<ppu_thread>(rwlock->rq, SYS_SYNC_PRIORITY))
{ {
ppu.state += cpu_flag::is_waiting;
rwlock->awake(*cpu); rwlock->awake(*cpu);
} }
@ -364,7 +364,7 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -426,6 +426,8 @@ error_code sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id)
if (auto cpu = rwlock->schedule<ppu_thread>(rwlock->wq, rwlock->protocol)) if (auto cpu = rwlock->schedule<ppu_thread>(rwlock->wq, rwlock->protocol))
{ {
ppu.state += cpu_flag::is_waiting;
rwlock->owner = cpu->id << 1 | !rwlock->wq.empty(); rwlock->owner = cpu->id << 1 | !rwlock->wq.empty();
rwlock->awake(*cpu); rwlock->awake(*cpu);
@ -436,6 +438,7 @@ error_code sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id)
while (auto cpu = rwlock->schedule<ppu_thread>(rwlock->rq, SYS_SYNC_PRIORITY)) while (auto cpu = rwlock->schedule<ppu_thread>(rwlock->rq, SYS_SYNC_PRIORITY))
{ {
ppu.state += cpu_flag::is_waiting;
rwlock->awake(*cpu); rwlock->awake(*cpu);
} }
@ -449,7 +452,7 @@ error_code sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id)
if (rwlock.ret & 1) if (rwlock.ret & 1)
{ {
ppu.check_state(); ppu.test_state();
} }
return CELL_OK; return CELL_OK;

View file

@ -85,8 +85,6 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
{ {
sys_semaphore.trace("sys_semaphore_wait(sem_id=0x%x, timeout=0x%llx)", sem_id, timeout); sys_semaphore.trace("sys_semaphore_wait(sem_id=0x%x, timeout=0x%llx)", sem_id, timeout);
const u64 start_time = ppu.gpr[10] = get_system_time();
const auto sem = idm::get<lv2_obj, lv2_sema>(sem_id, [&](lv2_sema& sema) const auto sem = idm::get<lv2_obj, lv2_sema>(sem_id, [&](lv2_sema& sema)
{ {
const s32 val = sema.val; const s32 val = sema.val;
@ -104,7 +102,7 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
if (sema.val-- <= 0) if (sema.val-- <= 0)
{ {
sema.sq.emplace_back(&ppu); sema.sq.emplace_back(&ppu);
sema.sleep(ppu, start_time, timeout); sema.sleep(ppu, timeout);
return false; return false;
} }
@ -127,7 +125,7 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
{ {
if (timeout) if (timeout)
{ {
const u64 passed = get_system_time() - start_time; const u64 passed = get_system_time() - ppu.start_time;
if (passed >= timeout) if (passed >= timeout)
{ {
@ -160,7 +158,7 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
} }
} }
ppu.check_state(); ppu.test_state();
return not_an_error(ppu.gpr[3]); return not_an_error(ppu.gpr[3]);
} }
@ -251,11 +249,12 @@ error_code sys_semaphore_post(ppu_thread& ppu, u32 sem_id, s32 count)
{ {
const auto cpu = verify(HERE, sem->schedule<ppu_thread>(sem->sq, sem->protocol)); const auto cpu = verify(HERE, sem->schedule<ppu_thread>(sem->sq, sem->protocol));
ppu.state += cpu_flag::is_waiting;
sem->awake(*cpu); sem->awake(*cpu);
} }
} }
ppu.check_state(); ppu.test_state();
return CELL_OK; return CELL_OK;
} }

View file

@ -227,8 +227,10 @@ error_code sys_spu_thread_group_destroy(u32 id)
return CELL_OK; return CELL_OK;
} }
error_code sys_spu_thread_group_start(u32 id) error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
{ {
ppu.state += cpu_flag::is_waiting;
sys_spu.warning("sys_spu_thread_group_start(id=0x%x)", id); sys_spu.warning("sys_spu_thread_group_start(id=0x%x)", id);
const auto group = idm::get<lv2_spu_group>(id, [](lv2_spu_group& group) const auto group = idm::get<lv2_spu_group>(id, [](lv2_spu_group& group)
@ -285,6 +287,7 @@ error_code sys_spu_thread_group_start(u32 id)
} }
} }
ppu.test_state();
return CELL_OK; return CELL_OK;
} }
@ -495,7 +498,7 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return CELL_EBUSY; return CELL_EBUSY;
} }
lv2_obj::sleep(ppu, -1); lv2_obj::sleep(ppu);
while ((group->join_state & ~SPU_TGJSF_IS_JOINING) == 0) while ((group->join_state & ~SPU_TGJSF_IS_JOINING) == 0)
{ {

View file

@ -216,7 +216,7 @@ error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 sp
error_code sys_spu_thread_set_argument(u32 id, vm::ps3::ptr<sys_spu_thread_argument> arg); error_code sys_spu_thread_set_argument(u32 id, vm::ps3::ptr<sys_spu_thread_argument> arg);
error_code sys_spu_thread_group_create(vm::ps3::ptr<u32> id, u32 num, s32 prio, vm::ps3::ptr<sys_spu_thread_group_attribute> attr); error_code sys_spu_thread_group_create(vm::ps3::ptr<u32> id, u32 num, s32 prio, vm::ps3::ptr<sys_spu_thread_group_attribute> attr);
error_code sys_spu_thread_group_destroy(u32 id); error_code sys_spu_thread_group_destroy(u32 id);
error_code sys_spu_thread_group_start(u32 id); error_code sys_spu_thread_group_start(ppu_thread&, u32 id);
error_code sys_spu_thread_group_suspend(u32 id); error_code sys_spu_thread_group_suspend(u32 id);
error_code sys_spu_thread_group_resume(u32 id); error_code sys_spu_thread_group_resume(u32 id);
error_code sys_spu_thread_group_yield(u32 id); error_code sys_spu_thread_group_yield(u32 id);

View file

@ -1,10 +1,10 @@
#pragma once #pragma once
#include "Utilities/Thread.h"
#include "Utilities/mutex.h" #include "Utilities/mutex.h"
#include "Utilities/sema.h" #include "Utilities/sema.h"
#include "Utilities/cond.h" #include "Utilities/cond.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include <deque> #include <deque>
@ -107,23 +107,24 @@ struct lv2_obj
} }
// Remove the current thread from the scheduling queue, register timeout // Remove the current thread from the scheduling queue, register timeout
static void sleep(named_thread&, u64 wait_until); static void sleep_timeout(named_thread&, u64 timeout);
template <typename T> static void sleep(cpu_thread& thread, u64 timeout = 0)
static void sleep(T& thread, u64 start_time, u64 timeout)
{ {
sleep(thread, timeout ? start_time + timeout : -1); thread.state += cpu_flag::is_waiting;
sleep_timeout(thread, timeout);
} }
// Schedule the thread // Schedule the thread
static void awake(class cpu_thread&, u32 prio); static void awake(cpu_thread&, u32 prio);
template <typename T> static void awake(cpu_thread& thread)
static void awake(T& cpu)
{ {
awake(cpu, -1); awake(thread, -1);
} }
static void lock_all();
static void unlock_all();
static void cleanup(); static void cleanup();
private: private:

View file

@ -50,7 +50,7 @@ void lv2_timer::on_task()
} }
// TODO: use single global dedicated thread for busy waiting, no timer threads // TODO: use single global dedicated thread for busy waiting, no timer threads
lv2_obj::sleep(*this, next); lv2_obj::sleep_timeout(*this, next - _now);
thread_ctrl::wait_for(next - _now); thread_ctrl::wait_for(next - _now);
} }
else if (_state == SYS_TIMER_STATE_STOP) else if (_state == SYS_TIMER_STATE_STOP)
@ -290,15 +290,14 @@ error_code sys_timer_usleep(ppu_thread& ppu, u64 sleep_time)
{ {
sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time); sys_timer.trace("sys_timer_usleep(sleep_time=0x%llx)", sleep_time);
u64 start = ppu.gpr[10] = get_system_time();
u64 passed = 0; u64 passed = 0;
lv2_obj::sleep(ppu, start, std::max<u64>(1, sleep_time)); lv2_obj::sleep(ppu, std::max<u64>(1, sleep_time));
while (sleep_time >= passed) while (sleep_time >= passed)
{ {
thread_ctrl::wait_for(std::max<u64>(1, sleep_time - passed)); thread_ctrl::wait_for(std::max<u64>(1, sleep_time - passed));
passed = get_system_time() - start; passed = get_system_time() - ppu.start_time;
} }
return CELL_OK; return CELL_OK;

View file

@ -311,6 +311,13 @@ void Emulator::Load()
g_system = system_type::psv; g_system = system_type::psv;
m_status = Ready; m_status = Ready;
vm::psv::init(); vm::psv::init();
if (m_elf_path.empty())
{
m_elf_path = "host_root:" + m_path;
LOG_NOTICE(LOADER, "Elf path: %s", m_elf_path);
}
arm_load_exec(arm_exec); arm_load_exec(arm_exec);
} }
else else