CHECK_EMU_STATUS, autojoin_thread_t

This commit is contained in:
Nekotekina 2015-07-04 02:22:24 +03:00
parent 8f9e1100c8
commit 3064cf8101
28 changed files with 145 additions and 179 deletions

View File

@ -19,10 +19,7 @@ void SSemaphore::wait()
while (true)
{
if (Emu.IsStopped())
{
return;
}
CHECK_EMU_STATUS;
m_cond.wait_for(cv_lock, std::chrono::milliseconds(1));

View File

@ -1214,14 +1214,7 @@ thread_t::~thread_t() noexcept(false)
{
if (m_thread)
{
if (g_tls_this_thread != m_thread.get())
{
m_thread->m_thread.join();
}
else
{
throw EXCEPTION("Deadlock");
}
throw EXCEPTION("Neither joined nor detached");
}
}

View File

@ -84,6 +84,28 @@ public:
bool is_current() const;
};
class autojoin_thread_t final : private thread_t
{
public:
using thread_t::mutex;
using thread_t::cv;
public:
autojoin_thread_t() = delete;
autojoin_thread_t(std::function<std::string()> name, std::function<void()> func)
{
start(std::move(name), std::move(func));
}
virtual ~autojoin_thread_t() override
{
join();
}
using thread_t::is_current;
};
struct waiter_map_t
{
static const size_t size = 16;

View File

@ -609,10 +609,19 @@ u32 SPUThread::get_ch_value(u32 ch)
case SPU_RdEventStat:
{
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
u32 result;
while (!(result = ch_event_stat.load() & ch_event_mask) && !Emu.IsStopped())
while ((result = ch_event_stat.load() & ch_event_mask) == 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
CHECK_EMU_STATUS;
if (IsStopped()) throw CPUThreadStop{};
if (!lock) lock.lock();
cv.wait_for(lock, std::chrono::milliseconds(1));
}
return result;

View File

@ -4,6 +4,7 @@
#include "Emu/System.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/SysCalls/lv2/sys_time.h"
@ -615,9 +616,7 @@ namespace vm
if (context.GPR[1] < context.stack_addr)
{
LOG_ERROR(PPU, "vm::stack_push(0x%x,%d): stack overflow (SP=0x%llx, stack=*0x%x)", size, align_v, context.GPR[1], context.stack_addr);
context.GPR[1] = old_pos;
return 0;
throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=0x%llx, stack=*0x%x)", size, align_v, old_pos, context.stack_addr);
}
else
{
@ -628,8 +627,20 @@ namespace vm
case CPU_THREAD_SPU:
case CPU_THREAD_RAW_SPU:
{
assert(!"stack_push(): SPU not supported");
return 0;
SPUThread& context = static_cast<SPUThread&>(CPU);
old_pos = context.GPR[1]._u32[3];
context.GPR[1]._u32[3] -= align(size, 16);
context.GPR[1]._u32[3] &= ~(align_v - 1);
if (context.GPR[1]._u32[3] >= 0x40000) // extremely rough
{
throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=LS:0x%05x)", size, align_v, old_pos);
}
else
{
return context.GPR[1]._u32[3] + context.offset;
}
}
case CPU_THREAD_ARMv7:
@ -642,9 +653,7 @@ namespace vm
if (context.SP < context.stack_addr)
{
LOG_ERROR(ARMv7, "vm::stack_push(0x%x,%d): stack overflow (SP=0x%x, stack=*0x%x)", size, align_v, context.SP, context.stack_addr);
context.SP = old_pos;
return 0;
throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=0x%x, stack=*0x%x)", size, align_v, context.SP, context.stack_addr);
}
else
{
@ -654,8 +663,7 @@ namespace vm
default:
{
assert(!"stack_push(): invalid thread type");
return 0;
throw EXCEPTION("Invalid thread type (%d)", CPU.GetId());
}
}
}
@ -668,9 +676,9 @@ namespace vm
{
PPUThread& context = static_cast<PPUThread&>(CPU);
if (context.GPR[1] != addr && !Emu.IsStopped())
if (context.GPR[1] != addr)
{
LOG_ERROR(PPU, "vm::stack_pop(*0x%x,*0x%x): stack inconsistency (SP=0x%llx)", addr, old_pos, context.GPR[1]);
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%llx, old_pos=0x%x)", addr, context.GPR[1], old_pos);
}
context.GPR[1] = old_pos;
@ -680,7 +688,14 @@ namespace vm
case CPU_THREAD_SPU:
case CPU_THREAD_RAW_SPU:
{
assert(!"stack_pop(): SPU not supported");
SPUThread& context = static_cast<SPUThread&>(CPU);
if (context.GPR[1]._u32[3] + context.offset != addr)
{
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=LS:0x%05x, old_pos=LS:0x%05x)", addr, context.GPR[1]._u32[3], old_pos);
}
context.GPR[1]._u32[3] = old_pos;
return;
}
@ -688,9 +703,9 @@ namespace vm
{
ARMv7Context& context = static_cast<ARMv7Thread&>(CPU);
if (context.SP != addr && !Emu.IsStopped())
if (context.SP != addr)
{
LOG_ERROR(ARMv7, "vm::stack_pop(*0x%x,*0x%x): stack inconsistency (SP=0x%x)", addr, old_pos, context.SP);
throw EXCEPTION("Stack inconsistency (addr=0x%x, SP=0x%x, old_pos=0x%x)", addr, context.SP, old_pos);
}
context.SP = old_pos;
@ -699,8 +714,7 @@ namespace vm
default:
{
assert(!"stack_pop(): invalid thread type");
return;
throw EXCEPTION("Invalid thread type (%d)", CPU.GetType());
}
}
}

View File

@ -2456,14 +2456,16 @@ void RSXThread::Task()
m_last_flip_time = get_system_time() - 1000000;
thread_t vblank(WRAP_EXPR("VBlank thread"), [this]()
autojoin_thread_t vblank(WRAP_EXPR("VBlank Thread"), [this]()
{
const u64 start_time = get_system_time();
m_vblank_count = 0;
while (joinable() && !Emu.IsStopped())
while (joinable())
{
CHECK_EMU_STATUS;
if (get_system_time() - start_time > m_vblank_count * 1000000 / 60)
{
m_vblank_count++;
@ -2567,8 +2569,6 @@ void RSXThread::Task()
});
}
LOG_NOTICE(RSX, "RSX thread ended");
OnExitThread();
}

View File

@ -569,11 +569,8 @@ s32 cellAdecClose(u32 handle)
while (!adec->is_finished)
{
if (Emu.IsStopped())
{
cellAdec.Warning("cellAdecClose(%d) aborted", handle);
break;
}
CHECK_EMU_STATUS;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}

View File

@ -81,7 +81,7 @@ s32 cellAudioInit()
squeue_t<float*, BUFFER_NUM - 1> out_queue;
thread_t iat(WRAP_EXPR("Internal Audio Thread"), [&out_queue]()
autojoin_thread_t iat(WRAP_EXPR("Internal Audio Thread"), [&out_queue]()
{
const bool use_u16 = Ini.AudioConvertToU16.GetValue();

View File

@ -121,7 +121,7 @@ struct AudioPortConfig
atomic<level_set_t> level_set;
};
struct AudioConfig //custom structure
struct AudioConfig final // custom structure
{
atomic<AudioState> state;
thread_t thread;
@ -135,6 +135,14 @@ struct AudioConfig //custom structure
AudioConfig() = default;
~AudioConfig()
{
if (thread.joinable())
{
thread.join();
}
}
u32 open_port()
{
for (u32 i = 0; i < AUDIO_PORT_COUNT; i++)

View File

@ -690,15 +690,10 @@ s32 cellFsStReadWait(u32 fd, u64 size)
std::unique_lock<std::mutex> lock(file->mutex);
// wait for size availability or stream end
while (file->st_total_read - file->st_copied < size && file->st_total_read < file->st_read_size)
{
// wait for size availability or stream end
if (Emu.IsStopped())
{
cellFs.Warning("cellFsStReadWait(0x%x) aborted", fd);
return CELL_OK;
}
CHECK_EMU_STATUS;
file->cv.wait_for(lock, std::chrono::milliseconds(1));
}

View File

@ -105,7 +105,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
std::string msg = msgString.get_ptr();
thread_t(WRAP_EXPR("MsgDialog Thread"), [type, msg, callback, userData, extParam]()
thread_t(WRAP_EXPR("MsgDialog Thread"), [=]()
{
switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
{
@ -127,11 +127,8 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
while (!m_signal)
{
if (Emu.IsStopped())
{
cellSysutil.Warning("MsgDialog thread aborted");
return;
}
CHECK_EMU_STATUS;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}

View File

@ -423,10 +423,7 @@ void spursHandlerWaitReady(PPUThread& CPU, vm::ptr<CellSpurs> spurs)
while (true)
{
if (Emu.IsStopped())
{
sys_ppu_thread_exit(CPU, 0);
}
CHECK_EMU_STATUS;
if (spurs->handlerExiting.load())
{
@ -518,6 +515,8 @@ void spursHandlerEntry(PPUThread& CPU)
while (true)
{
CHECK_EMU_STATUS;
if (spurs->flags1 & SF1_EXIT_IF_NO_WORK)
{
spursHandlerWaitReady(CPU, spurs);
@ -538,14 +537,13 @@ void spursHandlerEntry(PPUThread& CPU)
throw EXCEPTION("sys_spu_thread_group_join() failed (0x%x)", rc);
}
if (Emu.IsStopped())
{
continue;
}
if ((spurs->flags1 & SF1_EXIT_IF_NO_WORK) == 0)
{
assert(spurs->handlerExiting.load() == 1 || Emu.IsStopped());
if (spurs->handlerExiting.load() != 1)
{
throw EXCEPTION("Unexpected handlerExiting value (false)");
}
sys_ppu_thread_exit(CPU, 0);
}
}

View File

@ -530,9 +530,7 @@ bool spursKernelWorkloadExit(SPUThread & spu) {
bool spursKernelEntry(SPUThread & spu) {
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (Emu.IsStopped()) {
return false;
}
CHECK_EMU_STATUS;
}
auto ctxt = vm::get_ptr<SpursKernelContext>(spu.offset + 0x100);
@ -676,7 +674,7 @@ void spursSysServiceIdleHandler(SPUThread & spu, SpursKernelContext * ctxt) {
// If all SPUs are idling and the exit_if_no_work flag is set then the SPU thread group must exit. Otherwise wait for external events.
if (spuIdling && shouldExit == false && foundReadyWorkload == false) {
// The system service blocks by making a reservation and waiting on the lock line reservation lost event.
if (Emu.IsStopped()) throw SpursModuleExit();
CHECK_EMU_STATUS;
if (!lock) lock.lock();
spu.cv.wait_for(lock, std::chrono::milliseconds(1));
continue;
@ -744,6 +742,7 @@ void spursSysServiceMain(SPUThread & spu, u32 pollStatus) {
cellSpursModulePutTrace(&pkt, ctxt->dmaTagId);
while (true) {
CHECK_EMU_STATUS;
// Process requests for the system service
spursSysServiceProcessRequests(spu, ctxt);
@ -784,7 +783,7 @@ poll:
cellSpursModulePutTrace(&pkt, ctxt->dmaTagId);
spursSysServiceIdleHandler(spu, ctxt);
if (Emu.IsStopped()) return;
CHECK_EMU_STATUS;
goto poll;
}

View File

@ -829,10 +829,7 @@ s32 _cellSyncLFQueueGetPushPointer(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queu
{
while (true)
{
if (Emu.IsStopped())
{
return -1;
}
CHECK_EMU_STATUS;
const auto old = queue->push1.load_sync();
auto push = old;
@ -1082,6 +1079,8 @@ s32 _cellSyncLFQueuePushBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm:
while (true)
{
CHECK_EMU_STATUS;
s32 res;
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
@ -1101,12 +1100,6 @@ s32 _cellSyncLFQueuePushBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm:
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped())
{
cellSync.Warning("_cellSyncLFQueuePushBody(queue=*0x%x) aborted", queue);
return CELL_OK;
}
}
const s32 depth = queue->m_depth;
@ -1142,10 +1135,7 @@ s32 _cellSyncLFQueueGetPopPointer(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue
{
while (true)
{
if (Emu.IsStopped())
{
return -1;
}
CHECK_EMU_STATUS;
const auto old = queue->pop1.load_sync();
auto pop = old;
@ -1395,6 +1385,8 @@ s32 _cellSyncLFQueuePopBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm::
while (true)
{
CHECK_EMU_STATUS;
s32 res;
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
@ -1414,12 +1406,6 @@ s32 _cellSyncLFQueuePopBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm::
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
if (Emu.IsStopped())
{
cellSync.Warning("_cellSyncLFQueuePopBody(queue=*0x%x) aborted", queue);
return CELL_OK;
}
}
const s32 depth = queue->m_depth;

View File

@ -330,13 +330,9 @@ s32 cellSysutilCheckCallback(PPUThread& CPU)
while (Emu.GetCallbackManager().Check(CPU, res))
{
count++;
CHECK_EMU_STATUS;
if (Emu.IsStopped())
{
cellSysutil.Warning("cellSysutilCheckCallback() aborted");
return CELL_OK;
}
count++;
if (res)
{

View File

@ -594,11 +594,8 @@ s32 cellVdecClose(u32 handle)
while (!vdec->is_finished)
{
if (Emu.IsStopped())
{
cellVdec.Warning("cellVdecClose(%d) aborted", handle);
break;
}
CHECK_EMU_STATUS;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}

View File

@ -186,6 +186,8 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
while (!cond->mutex->owner.expired() || !cond->signaled || cond->waiters.count(CPU.GetId()))
{
CHECK_EMU_STATUS;
const bool is_timedout = timeout && get_system_time() - start_time > timeout;
// check timeout
@ -203,12 +205,6 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout)
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_cond.Warning("sys_cond_wait(id=0x%x) aborted", cond_id);
return CELL_OK;
}
// wait on appropriate condition variable
(cond->signaled || is_timedout ? cond->mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -141,6 +141,8 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
break;
}
CHECK_EMU_STATUS;
if (ef->cancelled)
{
if (!--ef->cancelled)
@ -157,12 +159,6 @@ s32 sys_event_flag_wait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 t
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_event_flag.Warning("sys_event_flag_wait(id=0x%x) aborted", id);
return CELL_OK;
}
ef->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -103,8 +103,10 @@ s32 sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread,
std::unique_lock<std::mutex> cond_lock(tag.handler_mutex);
while (!Emu.IsStopped())
while (!CPU.IsStopped())
{
CHECK_EMU_STATUS;
// call interrupt handler until int status is clear
if (tag.stat.load())
{

View File

@ -180,6 +180,8 @@ s32 _sys_lwcond_queue_wait(PPUThread& CPU, u32 lwcond_id, u32 lwmutex_id, u64 ti
while ((!(cond->signaled1 && mutex->signaled) && !cond->signaled2) || cond->waiters.count(CPU.GetId()))
{
CHECK_EMU_STATUS;
const bool is_timedout = timeout && get_system_time() - start_time > timeout;
// check timeout
@ -210,12 +212,6 @@ s32 _sys_lwcond_queue_wait(PPUThread& CPU, u32 lwcond_id, u32 lwmutex_id, u64 ti
}
}
if (Emu.IsStopped())
{
sys_lwcond.Warning("_sys_lwcond_queue_wait(lwcond_id=0x%x) aborted", lwcond_id);
return CELL_OK;
}
(cond->signaled1 ? mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -77,18 +77,14 @@ s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout)
while (!mutex->signaled)
{
CHECK_EMU_STATUS;
if (timeout && get_system_time() - start_time > timeout)
{
mutex->waiters--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_lwmutex.Warning("_sys_lwmutex_lock(lwmutex_id=0x%x) aborted", lwmutex_id);
return CELL_OK;
}
mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -119,18 +119,14 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout)
while (!mutex->owner.expired())
{
CHECK_EMU_STATUS;
if (timeout && get_system_time() - start_time > timeout)
{
mutex->waiters--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_mutex.Warning("sys_mutex_lock(mutex_id=0x%x) aborted", mutex_id);
return CELL_OK;
}
mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -36,19 +36,20 @@ s32 sys_process_exit(s32 status)
LV2_LOCK;
if (!Emu.IsStopped())
CHECK_EMU_STATUS;
sys_process.Success("Process finished");
CallAfter([]()
{
sys_process.Success("Process finished");
Emu.Stop();
});
CallAfter([]()
{
Emu.Stop();
});
while (true)
{
CHECK_EMU_STATUS;
while (!Emu.IsStopped())
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return CELL_OK;

View File

@ -84,18 +84,14 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout)
while (rwlock->writer || rwlock->wwaiters)
{
CHECK_EMU_STATUS;
if (timeout && get_system_time() - start_time > timeout)
{
rwlock->rwaiters--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=0x%x) aborted", rw_lock_id);
return CELL_OK;
}
rwlock->rcv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
@ -179,18 +175,14 @@ s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout)
while (rwlock->readers || rwlock->writer)
{
CHECK_EMU_STATUS;
if (timeout && get_system_time() - start_time > timeout)
{
rwlock->wwaiters--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=0x%x) aborted", rw_lock_id);
return CELL_OK;
}
rwlock->wcv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -91,18 +91,14 @@ s32 sys_semaphore_wait(u32 sem, u64 timeout)
while (semaphore->value <= 0)
{
CHECK_EMU_STATUS;
if (timeout && get_system_time() - start_time > timeout)
{
semaphore->waiters--;
return CELL_ETIMEDOUT;
}
if (Emu.IsStopped())
{
sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem);
return CELL_OK;
}
semaphore->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -546,11 +546,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr<u32> cause, vm::ptr<u32> status)
break;
}
if (Emu.IsStopped())
{
sys_spu.Warning("sys_spu_thread_group_join(id=0x%x) aborted", id);
return CELL_OK;
}
CHECK_EMU_STATUS;
group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}

View File

@ -60,7 +60,6 @@ lv2_timer_t::lv2_timer_t()
lv2_timer_t::~lv2_timer_t()
{
thread.cv.notify_one();
thread.join();
}
@ -253,13 +252,9 @@ s32 sys_timer_sleep(u32 sleep_time)
while (useconds > (passed = get_system_time() - start_time) + 1000)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
CHECK_EMU_STATUS;
if (Emu.IsStopped())
{
sys_timer.Warning("sys_timer_sleep(sleep_time=%d) aborted", sleep_time);
return CELL_OK;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (useconds > passed)
@ -280,13 +275,9 @@ s32 sys_timer_usleep(u64 sleep_time)
while (sleep_time > (passed = get_system_time() - start_time) + 1000)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
CHECK_EMU_STATUS;
if (Emu.IsStopped())
{
sys_timer.Warning("sys_timer_usleep(sleep_time=0x%llx) aborted", sleep_time);
return CELL_OK;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (sleep_time > passed)

View File

@ -19,7 +19,7 @@ struct sys_timer_information_t
be_t<u32> pad;
};
struct lv2_timer_t
struct lv2_timer_t final
{
std::weak_ptr<lv2_event_queue_t> port; // event queue
u64 source; // event source