From 9883e1e8b8393826f61c91d26be4abedfb33a5e3 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 8 Mar 2015 18:25:31 +0300 Subject: [PATCH 01/18] Lv2 Timer rewritten --- rpcs3/Emu/SysCalls/SysCalls.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_timer.cpp | 244 +++++++++++++++++++++------ rpcs3/Emu/SysCalls/lv2/sys_timer.h | 37 ++-- 3 files changed, 221 insertions(+), 62 deletions(-) diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index a132eb2da9..be5b11b94d 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -108,7 +108,7 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_timer_create), //70 (0x046) bind_func(sys_timer_destroy), //71 (0x047) bind_func(sys_timer_get_information), //72 (0x048) - bind_func(sys_timer_start), //73 (0x049) + bind_func(_sys_timer_start), //73 (0x049) bind_func(sys_timer_stop), //74 (0x04A) bind_func(sys_timer_connect_event_queue), //75 (0x04B) bind_func(sys_timer_disconnect_event_queue), //76 (0x04C) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index 0c014e1738..e1bbfe51dc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -4,100 +4,218 @@ #include "Emu/IdManager.h" #include "Emu/SysCalls/SysCalls.h" -#include "Emu/Event.h" +#include "Utilities/Thread.h" +#include "sys_time.h" #include "sys_event.h" +#include "sys_process.h" #include "sys_timer.h" SysCallBase sys_timer("sys_timer"); s32 sys_timer_create(vm::ptr timer_id) { - sys_timer.Warning("sys_timer_create(timer_id_addr=0x%x)", timer_id.addr()); + sys_timer.Warning("sys_timer_create(timer_id=*0x%x)", timer_id); + + std::shared_ptr timer(new timer_t); + + thread_t(fmt::format("Timer[%d] Thread", (*timer_id = Emu.GetIdManager().GetNewID(timer, TYPE_TIMER))), [timer]() + { + LV2_LOCK; + + while (!timer.unique() && !Emu.IsStopped()) + { + if (timer->state == SYS_TIMER_STATE_RUN) + { + if (get_system_time() >= timer->start) + { + std::shared_ptr queue = timer->port.lock(); + + if (queue) + { + queue->events.emplace_back(timer->source, timer->data1, timer->data2, timer->start); + queue->cv.notify_one(); + } + + if (timer->period && queue) + { + timer->start += timer->period; // set next expiration time + + continue; // hack: check again + } + else + { + timer->state = SYS_TIMER_STATE_STOP; // stop if oneshot or the event port was disconnected (TODO: is it correct?) + } + } + } + + timer->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); + } + + }).detach(); - std::shared_ptr timer_data(new timer); - *timer_id = Emu.GetIdManager().GetNewID(timer_data, TYPE_TIMER); return CELL_OK; } s32 sys_timer_destroy(u32 timer_id) { - sys_timer.Todo("sys_timer_destroy(timer_id=%d)", timer_id); + sys_timer.Warning("sys_timer_destroy(timer_id=%d)", timer_id); - if(!Emu.GetIdManager().CheckID(timer_id)) return CELL_ESRCH; + LV2_LOCK; + + std::shared_ptr timer; + if (!Emu.GetIdManager().GetIDData(timer_id, timer)) + { + return CELL_ESRCH; + } + + if (!timer->port.expired()) + { + return CELL_EISCONN; + } Emu.GetIdManager().RemoveID(timer_id); + return CELL_OK; } s32 sys_timer_get_information(u32 timer_id, vm::ptr info) { - sys_timer.Warning("sys_timer_get_information(timer_id=%d, info_addr=0x%x)", timer_id, info.addr()); - - std::shared_ptr timer_data = nullptr; - if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH; + sys_timer.Warning("sys_timer_get_information(timer_id=%d, info=*0x%x)", timer_id, info); + + LV2_LOCK; + + std::shared_ptr timer; + if (!Emu.GetIdManager().GetIDData(timer_id, timer)) + { + return CELL_ESRCH; + } + + info->next_expiration_time = timer->start; + + info->period = timer->period; + + info->timer_state = timer->state; - *info = timer_data->timer_information_t; return CELL_OK; } -s32 sys_timer_start(u32 timer_id, s64 base_time, u64 period) +s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period) { - sys_timer.Warning("sys_timer_start_periodic_absolute(timer_id=%d, basetime=%lld, period=%lld)", timer_id, base_time, period); + sys_timer.Warning("_sys_timer_start(timer_id=%d, base_time=0x%llx, period=0x%llx)", timer_id, base_time, period); - std::shared_ptr timer_data = nullptr; - if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH; + const u64 start_time = get_system_time(); - if(timer_data->timer_information_t.timer_state != SYS_TIMER_STATE_STOP) return CELL_EBUSY; - if(period < 100) return CELL_EINVAL; - //TODO: if (timer is not connected to an event queue) return CELL_ENOTCONN; - - timer_data->timer_information_t.next_expiration_time = base_time; - timer_data->timer_information_t.period = period; - timer_data->timer_information_t.timer_state = SYS_TIMER_STATE_RUN; - //TODO: ? - std::function task(std::bind(sys_timer_stop, timer_id)); - std::thread([period, task]() { - std::this_thread::sleep_for(std::chrono::milliseconds(period)); - task(); - }).detach(); + LV2_LOCK; + + std::shared_ptr timer; + if (!Emu.GetIdManager().GetIDData(timer_id, timer)) + { + return CELL_ESRCH; + } + + if (timer->state != SYS_TIMER_STATE_STOP) + { + return CELL_EBUSY; + } + + if (!period) + { + // oneshot timer (TODO: what will happen if both args are 0?) + + if (start_time >= base_time) + { + return CELL_ETIMEDOUT; + } + } + else + { + // periodic timer + + if (period < 100) + { + return CELL_EINVAL; + } + } + + if (timer->port.expired()) + { + return CELL_ENOTCONN; + } + + // sys_timer_start_periodic() will use current time (TODO: is it correct?) + + timer->start = base_time ? base_time : start_time + period; + timer->period = period; + timer->state = SYS_TIMER_STATE_RUN; + timer->cv.notify_one(); return CELL_OK; } s32 sys_timer_stop(u32 timer_id) { - sys_timer.Todo("sys_timer_stop()"); + sys_timer.Warning("sys_timer_stop()"); - std::shared_ptr timer_data = nullptr; - if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH; + LV2_LOCK; + + std::shared_ptr timer; + if (!Emu.GetIdManager().GetIDData(timer_id, timer)) + { + return CELL_ESRCH; + } + + timer->state = SYS_TIMER_STATE_STOP; // stop timer - timer_data->timer_information_t.timer_state = SYS_TIMER_STATE_STOP; return CELL_OK; } s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2) { - sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)", - timer_id, queue_id, name, data1, data2); + sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)", timer_id, queue_id, name, data1, data2); - std::shared_ptr timer_data = nullptr; - std::shared_ptr equeue = nullptr; - if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH; - if(!Emu.GetIdManager().GetIDData(queue_id, equeue)) return CELL_ESRCH; + LV2_LOCK; - //TODO: ? + std::shared_ptr timer; + std::shared_ptr queue; + + if (!Emu.GetIdManager().GetIDData(timer_id, timer) || !Emu.GetIdManager().GetIDData(queue_id, queue)) + { + return CELL_ESRCH; + } + + if (!timer->port.expired()) + { + return CELL_EISCONN; + } + + timer->port = queue; // connect event queue + timer->source = name ? name : ((u64)process_getpid() << 32) | timer_id; + timer->data1 = data1; + timer->data2 = data2; return CELL_OK; } s32 sys_timer_disconnect_event_queue(u32 timer_id) { - sys_timer.Todo("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id); + sys_timer.Warning("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id); - std::shared_ptr timer_data = nullptr; - if(!Emu.GetIdManager().GetIDData(timer_id, timer_data)) return CELL_ESRCH; + LV2_LOCK; - //TODO: ? + std::shared_ptr timer; + if (!Emu.GetIdManager().GetIDData(timer_id, timer)) + { + return CELL_ESRCH; + } + + if (timer->port.expired()) + { + return CELL_ENOTCONN; + } + + timer->port.reset(); // disconnect event queue + timer->state = SYS_TIMER_STATE_STOP; // stop timer return CELL_OK; } @@ -105,31 +223,55 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id) s32 sys_timer_sleep(u32 sleep_time) { sys_timer.Log("sys_timer_sleep(sleep_time=%d)", sleep_time); - for (u32 i = 0; i < sleep_time; i++) + + const u64 start_time = get_system_time(); + + const u64 useconds = sleep_time * 1000000ull; + + u64 passed; + + while (useconds > (passed = get_system_time() - start_time) + 1000) { - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (Emu.IsStopped()) { sys_timer.Warning("sys_timer_sleep(sleep_time=%d) aborted", sleep_time); return CELL_OK; } } + + if (useconds > passed) + { + std::this_thread::sleep_for(std::chrono::microseconds(useconds - passed)); + } + return CELL_OK; } s32 sys_timer_usleep(u64 sleep_time) { - sys_timer.Log("sys_timer_usleep(sleep_time=%lld)", sleep_time); - if (sleep_time > 0xFFFFFFFFFFFF) sleep_time = 0xFFFFFFFFFFFF; //2^48-1 - for (u32 i = 0; i < sleep_time / 1000000; i++) + sys_timer.Log("sys_timer_usleep(sleep_time=0x%llx)", sleep_time); + + const u64 start_time = get_system_time(); + + u64 passed; + + while (sleep_time > (passed = get_system_time() - start_time) + 1000) { - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (Emu.IsStopped()) { - sys_timer.Warning("sys_timer_usleep(sleep_time=%lld) aborted", sleep_time); + sys_timer.Warning("sys_timer_usleep(sleep_time=0x%llx) aborted", sleep_time); return CELL_OK; } } - std::this_thread::sleep_for(std::chrono::microseconds(sleep_time % 1000000)); + + if (sleep_time > passed) + { + std::this_thread::sleep_for(std::chrono::microseconds(sleep_time - passed)); + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.h b/rpcs3/Emu/SysCalls/lv2/sys_timer.h index 61cd8bbe8e..47862e39cc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.h @@ -1,28 +1,45 @@ #pragma once -enum +// Timer State +enum : u32 { - SYS_TIMER_STATE_STOP = 0x00U, - SYS_TIMER_STATE_RUN = 0x01U, + SYS_TIMER_STATE_STOP = 0, + SYS_TIMER_STATE_RUN = 1, }; struct sys_timer_information_t { - s64 next_expiration_time; //system_time_t - u64 period; //usecond_t - u32 timer_state; - u32 pad; + be_t next_expiration_time; + be_t period; + be_t timer_state; + be_t pad; }; -struct timer +struct timer_t { - sys_timer_information_t timer_information_t; + std::weak_ptr port; // event queue + u64 source; // event source + u64 data1; // event arg 1 + u64 data2; // event arg 2 + + u64 start; // next expiration time + u64 period; // period (oneshot if 0) + + std::atomic state; // timer state + std::condition_variable cv; + + timer_t() + : start(0) + , period(0) + , state(SYS_TIMER_STATE_STOP) + { + } }; s32 sys_timer_create(vm::ptr timer_id); s32 sys_timer_destroy(u32 timer_id); s32 sys_timer_get_information(u32 timer_id, vm::ptr info); -s32 sys_timer_start(u32 timer_id, s64 basetime, u64 period); +s32 _sys_timer_start(u32 timer_id, u64 basetime, u64 period); // basetime type changed from s64 s32 sys_timer_stop(u32 timer_id); s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2); s32 sys_timer_disconnect_event_queue(u32 timer_id); From 507798c541a1934758ac374d1dbe0815f04e64ef Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Mar 2015 00:56:45 +0300 Subject: [PATCH 02/18] Lv2 Lwmutex --- rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp | 6 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 312 ++++++++++++++++++- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h | 11 +- rpcs3/Emu/SysCalls/SysCalls.cpp | 14 +- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 9 +- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp | 205 +----------- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h | 84 +++-- rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp | 61 ---- rpcs3/Emu/SysCalls/lv2/sys_spinlock.h | 7 - rpcs3/emucore.vcxproj | 2 - rpcs3/emucore.vcxproj.filters | 6 - 11 files changed, 416 insertions(+), 301 deletions(-) delete mode 100644 rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp delete mode 100644 rpcs3/Emu/SysCalls/lv2/sys_spinlock.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index de19a0fab6..b5f59e1ee7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -167,10 +167,8 @@ s32 spursInit( } } - if (s32 res = lwmutex_create(spurs->m.mutex, SYS_SYNC_PRIORITY, SYS_SYNC_NOT_RECURSIVE, *(u64*)"_spuPrv")) - { - assert(!"lwmutex_create() failed"); - } + lwmutex_create(spurs->m.mutex, false, SYS_SYNC_PRIORITY, *(u64*)"_spuPrv"); + if (s32 res = lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv")) { assert(!"lwcond_create() failed"); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 55d0636cc0..6104cb99fb 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -11,7 +11,6 @@ #include "Emu/SysCalls/lv2/sys_interrupt.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_spinlock.h" #include "Emu/SysCalls/lv2/sys_prx.h" #include "Emu/SysCalls/lv2/sys_ppu_thread.h" #include "Emu/SysCalls/lv2/sys_process.h" @@ -33,6 +32,8 @@ u32 g_tls_size; std::array, TLS_MAX> g_tls_owners; +waiter_map_t g_sys_spinlock_wm("sys_spinlock_wm"); // TODO + void sys_initialize_tls() { sysPrxForUser.Log("sys_initialize_tls()"); @@ -89,6 +90,262 @@ void ppu_free_tls(u32 thread) } } +s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) +{ + sysPrxForUser.Warning("sys_lwmutex_create(lwmutex=*0x%x, attr=*0x%x)", lwmutex, attr); + + const bool recursive = attr->recursive.data() == se32(SYS_SYNC_RECURSIVE); + + if (!recursive && attr->recursive.data() != se32(SYS_SYNC_NOT_RECURSIVE)) + { + sysPrxForUser.Error("sys_lwmutex_create(): invalid recursive attribute (0x%x)", attr->recursive); + return CELL_EINVAL; + } + + const u32 protocol = attr->protocol; + + switch (protocol) + { + case SYS_SYNC_FIFO: break; + case SYS_SYNC_RETRY: break; + case SYS_SYNC_PRIORITY: break; + default: sysPrxForUser.Error("sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL; + } + + std::shared_ptr lw(new lwmutex_t(protocol, attr->name_u64)); + + lwmutex->lock_var.write_relaxed({ lwmutex::free, lwmutex::zero }); + lwmutex->attribute = attr->recursive | attr->protocol; + lwmutex->recursive_count = 0; + lwmutex->sleep_queue = Emu.GetIdManager().GetNewID(lw); + + return CELL_OK; +} + +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Warning("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); + + // check to prevent recursive locking in the next call + if (lwmutex->lock_var.read_relaxed().owner == CPU.GetId()) + { + return CELL_EBUSY; + } + + // attempt to lock the mutex + if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) + { + return res; + } + + // call the syscall + if (s32 res = _sys_lwmutex_destroy(CPU, lwmutex->sleep_queue)) + { + // unlock the mutex if failed + sys_lwmutex_unlock(CPU, lwmutex); + + return res; + } + + // deleting succeeded + lwmutex->owner.exchange(lwmutex::dead); + + return CELL_OK; +} + +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) +{ + sysPrxForUser.Log("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout); + + const be_t tid = be_t::make(CPU.GetId()); + + // try to lock lightweight mutex + const be_t old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid); + + if (old_owner.data() == se32(lwmutex_free)) + { + // locking succeeded + return CELL_OK; + } + + if (old_owner.data() == tid.data()) + { + // recursive locking + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0) + { + // if not recursive + return CELL_EDEADLK; + } + + if (lwmutex->recursive_count.data() == -1) + { + // if recursion limit reached + return CELL_EKRESOURCE; + } + + // recursive locking succeeded + lwmutex->recursive_count++; + lwmutex->lock_var.read_sync(); + + return CELL_OK; + } + + if (old_owner.data() == se32(lwmutex_dead)) + { + // invalid or deleted mutex + return CELL_EINVAL; + } + + for (u32 i = 0; i < 300; i++) + { + if (lwmutex->owner.read_relaxed().data() == se32(lwmutex_free)) + { + if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) + { + // locking succeeded + return CELL_OK; + } + } + } + + lwmutex->waiter.atomic_op([](be_t& value){ value++; }); + + if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) + { + // locking succeeded + lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + + return CELL_OK; + } + + // lock using the syscall + const s32 res = _sys_lwmutex_lock(CPU, lwmutex->sleep_queue, timeout); + + lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + + if (res == CELL_OK) + { + // locking succeeded + lwmutex->owner.exchange(tid); + + return CELL_OK; + } + + if (res == CELL_EBUSY && lwmutex->attribute.data() & se32(SYS_SYNC_RETRY)) + { + // TODO (protocol is ignored in current implementation) + throw __FUNCTION__; + } + + return res; +} + +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Log("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex); + + const be_t tid = be_t::make(CPU.GetId()); + + // try to lock lightweight mutex + const be_t old_owner = lwmutex->owner.compare_and_swap(lwmutex::free, tid); + + if (old_owner.data() == se32(lwmutex_free)) + { + // locking succeeded + return CELL_OK; + } + + if (old_owner.data() == tid.data()) + { + // recursive locking + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_RECURSIVE)) == 0) + { + // if not recursive + return CELL_EDEADLK; + } + + if (lwmutex->recursive_count.data() == -1) + { + // if recursion limit reached + return CELL_EKRESOURCE; + } + + // recursive locking succeeded + lwmutex->recursive_count++; + lwmutex->lock_var.read_sync(); + + return CELL_OK; + } + + if (old_owner.data() == se32(lwmutex_dead)) + { + // invalid or deleted mutex + return CELL_EINVAL; + } + + if (old_owner.data() == se32(lwmutex_busy)) + { + // should be locked by the syscall + const s32 res = _sys_lwmutex_trylock(CPU, lwmutex->sleep_queue); + + if (res == CELL_OK) + { + // locking succeeded + lwmutex->owner.exchange(tid); + } + + return res; + } + + // locked by another thread + return CELL_EBUSY; +} + +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) +{ + sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); + + const be_t tid = be_t::make(CPU.GetId()); + + // check owner + if (lwmutex->owner.read_relaxed() != tid) + { + return CELL_EPERM; + } + + if (lwmutex->recursive_count.data()) + { + // recursive unlocking succeeded + lwmutex->recursive_count--; + + return CELL_OK; + } + + // ensure that waiter is zero + if (lwmutex->lock_var.compare_and_swap_test({ tid, lwmutex::zero }, { lwmutex::free, lwmutex::zero })) + { + // unlocking succeeded + return CELL_OK; + } + + if (lwmutex->attribute.data() & se32(SYS_SYNC_RETRY)) + { + // TODO (protocol is ignored in current implementation) + } + + lwmutex->owner.exchange(lwmutex::busy); + + // call the syscall + if (_sys_lwmutex_unlock(CPU, lwmutex->sleep_queue) == CELL_ESRCH) + { + return CELL_ESRCH; + } + + return CELL_OK; +} + std::string ps3_fmt(PPUThread& context, vm::ptr fmt, u32 g_count, u32 f_count, u32 v_count) { std::string result; @@ -575,6 +832,59 @@ s32 sys_process_get_paramsfo(vm::ptr buffer) return _sys_process_get_paramsfo(buffer); } +void sys_spinlock_initialize(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_initialize(lock=*0x%x)", lock); + + // prx: set 0 and sync + lock->exchange(be_t::make(0)); +} + +void sys_spinlock_lock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_lock(lock=*0x%x)", lock); + + // prx: exchange with 0xabadcafe, repeat until exchanged with 0 + while (lock->exchange(be_t::make(0xabadcafe)).data()) + { + while (lock->read_relaxed().data()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + if (Emu.IsStopped()) + { + break; + } + } + + if (Emu.IsStopped()) + { + sysPrxForUser.Warning("sys_spinlock_lock(lock=*0x%x) aborted", lock); + break; + } + } +} + +s32 sys_spinlock_trylock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_trylock(lock=*0x%x)", lock); + + // prx: exchange with 0xabadcafe, translate exchanged value + if (lock->exchange(be_t::make(0xabadcafe)).data()) + { + return CELL_EBUSY; + } + + return CELL_OK; +} + +void sys_spinlock_unlock(vm::ptr> lock) +{ + sysPrxForUser.Log("sys_spinlock_unlock(lock=*0x%x)", lock); + + // prx: sync and set 0 + lock->exchange(be_t::make(0)); +} + Module sysPrxForUser("sysPrxForUser", []() { g_tls_start = 0; diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h index 76234c5c4b..7a461b06e5 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h @@ -22,5 +22,14 @@ extern vm::ptr spu_printf_dgcb; extern vm::ptr spu_printf_atcb; extern vm::ptr spu_printf_dtcb; -// SysCalls +// Functions vm::ptr _sys_memset(vm::ptr dst, s32 value, u32 size); + +struct sys_lwmutex_t; +struct sys_lwmutex_attribute_t; + +s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index be5b11b94d..55dd25915a 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -108,7 +108,7 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_timer_create), //70 (0x046) bind_func(sys_timer_destroy), //71 (0x047) bind_func(sys_timer_get_information), //72 (0x048) - bind_func(_sys_timer_start), //73 (0x049) + bind_func(_sys_timer_start), //73 (0x049) bind_func(sys_timer_stop), //74 (0x04A) bind_func(sys_timer_connect_event_queue), //75 (0x04B) bind_func(sys_timer_disconnect_event_queue), //76 (0x04C) @@ -124,17 +124,17 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_event_flag_trywait), //86 (0x056) bind_func(sys_event_flag_set), //87 (0x057) bind_func(sys_interrupt_thread_eoi), //88 (0x058) - bind_func(_sys_interrupt_thread_disestablish), //89 (0x059) + bind_func(_sys_interrupt_thread_disestablish), //89 (0x059) bind_func(sys_semaphore_create), //90 (0x05A) bind_func(sys_semaphore_destroy), //91 (0x05B) bind_func(sys_semaphore_wait), //92 (0x05C) bind_func(sys_semaphore_trywait), //93 (0x05D) bind_func(sys_semaphore_post), //94 (0x05E) - null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create - null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy - null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock - null_func,//bind_func(_sys_lwmutex_???lock), //98 (0x062) // internal, used by sys_lwmutex_unlock - null_func,//bind_func(_sys_lwmutex_???lock), //99 (0x063) // internal, used by sys_lwmutex_trylock + bind_func(_sys_lwmutex_create), //95 (0x05F) + bind_func(_sys_lwmutex_destroy), //96 (0x060) + bind_func(_sys_lwmutex_lock), //97 (0x061) + bind_func(_sys_lwmutex_unlock), //98 (0x062) + bind_func(_sys_lwmutex_trylock), //99 (0x063) bind_func(sys_mutex_create), //100 (0x064) bind_func(sys_mutex_destroy), //101 (0x065) bind_func(sys_mutex_lock), //102 (0x066) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index cf0182a43f..5ee5c0c34e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -5,6 +5,7 @@ #include "Emu/SysCalls/SysCalls.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/SysCalls/Modules/sysPrxForUser.h" #include "sleep_queue.h" #include "sys_time.h" #include "sys_lwmutex.h" @@ -159,8 +160,8 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) lw->queue.push(tid_le, mutex->attribute); - auto old_recursive = mutex->recursive_count.read_relaxed(); - mutex->recursive_count.exchange(be_t::make(0)); + auto old_recursive = mutex->recursive_count; + mutex->recursive_count = 0; auto target = be_t::make(sq->signal(mutex->attribute)); if (!mutex->owner.compare_and_swap_test(tid, target)) @@ -173,7 +174,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) { if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads { - s32 res = mutex->lock(tid, timeout ? get_system_time() - start_time : 0); // this is bad + s32 res = sys_lwmutex_lock(CPU, mutex, timeout ? get_system_time() - start_time : 0); // this is bad if (res == CELL_OK) { break; @@ -226,6 +227,6 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) } } - mutex->recursive_count.exchange(old_recursive); + mutex->recursive_count = old_recursive; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 319fe29466..3336574681 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -12,210 +12,37 @@ SysCallBase sys_lwmutex("sys_lwmutex"); -s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) +void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name) { - std::shared_ptr sq(new sleep_queue_t(name_u64)); + std::shared_ptr lw(new lwmutex_t(protocol, name)); - lwmutex.owner.write_relaxed(be_t::make(0)); - lwmutex.waiter.write_relaxed(be_t::make(~0)); - lwmutex.attribute = protocol | recursive; - lwmutex.recursive_count.write_relaxed(be_t::make(0)); - u32 sq_id = Emu.GetIdManager().GetNewID(sq, TYPE_LWMUTEX); - lwmutex.sleep_queue = sq_id; - sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, vm::get_addr(&lwmutex))); - - // passing be_t (test) - sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), lwmutex.attribute, sq_id); - return CELL_OK; + lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero }); + lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE); + lwmutex.recursive_count = 0; + lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(lw, TYPE_LWMUTEX); } -s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr) +s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6) { - sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); - - switch (attr->recursive.data()) - { - case se32(SYS_SYNC_RECURSIVE): break; - case se32(SYS_SYNC_NOT_RECURSIVE): break; - default: sys_lwmutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL; - } - - switch (attr->protocol.data()) - { - case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): break; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; - case se32(SYS_SYNC_FIFO): break; - default: sys_lwmutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; - } - - return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64); + throw __FUNCTION__; } -s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); - - u32 sq_id = lwmutex->sleep_queue; - if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH; - - if (s32 res = lwmutex->trylock(be_t::make(~0))) - { - return res; - } - - // try to make it unable to lock - lwmutex->all_info() = 0; - lwmutex->attribute = 0xDEADBEEF; - lwmutex->sleep_queue = 0; - Emu.GetIdManager().RemoveID(sq_id); - return CELL_OK; + throw __FUNCTION__; } -s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) +s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout) { - sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout); - - return lwmutex->lock(be_t::make(CPU.GetId()), timeout); + throw __FUNCTION__; } -s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr()); - - return lwmutex->trylock(be_t::make(CPU.GetId())); + throw __FUNCTION__; } -s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) +s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id) { - sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr()); - - return lwmutex->unlock(be_t::make(CPU.GetId())); -} - -s32 sys_lwmutex_t::trylock(be_t tid) -{ - if (attribute.data() == se32(0xDEADBEEF)) - { - return CELL_EINVAL; - } - - if (!Emu.GetIdManager().CheckID(sleep_queue)) - { - return CELL_ESRCH; - } - - const be_t old_owner = owner.read_sync(); - - if (old_owner == tid) - { - if (attribute.data() & se32(SYS_SYNC_RECURSIVE)) - { - auto rv = recursive_count.read_relaxed(); - if (!~(rv++).data()) - { - return CELL_EKRESOURCE; - } - - recursive_count.exchange(rv); - return CELL_OK; - } - else - { - return CELL_EDEADLK; - } - } - - if (!owner.compare_and_swap_test(be_t::make(0), tid)) - { - return CELL_EBUSY; - } - - recursive_count.exchange(be_t::make(1)); - return CELL_OK; -} - -s32 sys_lwmutex_t::unlock(be_t tid) -{ - if (owner.read_sync() != tid) - { - return CELL_EPERM; - } - - auto rv = recursive_count.read_relaxed(); - if (!rv.data() || (rv.data() != se32(1) && (attribute.data() & se32(SYS_SYNC_NOT_RECURSIVE)))) - { - sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv); - rv = 1; - } - - rv--; - recursive_count.exchange(rv); - if (!rv.data()) - { - std::shared_ptr sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) - { - return CELL_ESRCH; - } - - if (!owner.compare_and_swap_test(tid, be_t::make(sq->signal(attribute)))) - { - assert(!"sys_lwmutex_t::unlock() failed"); - } - } - - return CELL_OK; -} - -s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) -{ - const u64 start_time = get_system_time(); - - switch (s32 res = trylock(tid)) - { - case static_cast(CELL_EBUSY): break; - default: return res; - } - - std::shared_ptr sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) - { - return CELL_ESRCH; - } - - sq->push(tid, attribute); - - while (true) - { - auto old_owner = owner.compare_and_swap(be_t::make(0), tid); - if (!old_owner.data() || old_owner == tid) - { - break; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - - if (timeout && get_system_time() - start_time > timeout) - { - if (!sq->invalidate(tid, attribute)) - { - assert(!"sys_lwmutex_t::lock() failed (timeout)"); - } - return CELL_ETIMEDOUT; - } - - if (Emu.IsStopped()) - { - sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); - return CELL_OK; - } - } - - if (!sq->invalidate(tid, attribute) && !sq->pop(tid, attribute)) - { - assert(!"sys_lwmutex_t::lock() failed (locking)"); - } - recursive_count.exchange(be_t::make(1)); - return CELL_OK; + throw __FUNCTION__; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index ce29524d48..7f76a4c8a2 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -4,6 +4,7 @@ struct sys_lwmutex_attribute_t { be_t protocol; be_t recursive; + union { char name[8]; @@ -11,33 +12,78 @@ struct sys_lwmutex_attribute_t }; }; +enum : u32 +{ + lwmutex_zero = 0u, + lwmutex_free = 0u - 1u, + lwmutex_dead = 0u - 2u, + lwmutex_busy = 0u - 3u, +}; + +namespace lwmutex +{ + template + struct const_be_u32_t + { + static const u32 value = _value; + + operator const be_t() const + { + return be_t::make(value); + } + }; + + static const_be_u32_t zero; + static const_be_u32_t free; + static const_be_u32_t dead; + static const_be_u32_t busy; +} + struct sys_lwmutex_t { - atomic_t owner; - atomic_t waiter; // currently not used - be_t attribute; - atomic_t recursive_count; - be_t sleep_queue; - be_t pad; - - u64& all_info() + struct sync_var_t { - return *(reinterpret_cast(this)); - } + be_t owner; + be_t waiter; + }; - s32 trylock(be_t tid); - s32 unlock(be_t tid); - s32 lock(be_t tid, u64 timeout); + union + { + atomic_t lock_var; + + struct + { + atomic_t owner; + atomic_t waiter; + }; + }; + + be_t attribute; + be_t recursive_count; + be_t sleep_queue; // lwmutex pseudo-id + be_t pad; +}; + +struct lwmutex_t +{ + const u32 protocol; + const u64 name; + + lwmutex_t(u32 protocol, u64 name) + : protocol(protocol) + , name(name) + { + } }; // Aux -s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); +void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name); class PPUThread; // SysCalls -s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); -s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); -s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); +s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6); +s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id); +s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout); +s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id); +s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp deleted file mode 100644 index e7ec98dc93..0000000000 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/SysCalls.h" - -#include "sys_spinlock.h" - -SysCallBase sys_spinlock("sys_spinlock"); - -void sys_spinlock_initialize(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_initialize(lock_addr=0x%x)", lock.addr()); - - // prx: set 0 and sync - lock->exchange(be_t::make(0)); -} - -void sys_spinlock_lock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.addr()); - - // prx: exchange with 0xabadcafe, repeat until exchanged with 0 - while (lock->exchange(be_t::make(0xabadcafe)).data()) - { - while (lock->read_relaxed().data()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - break; - } - } - - if (Emu.IsStopped()) - { - sys_spinlock.Warning("sys_spinlock_lock(0x%x) aborted", lock.addr()); - break; - } - } -} - -s32 sys_spinlock_trylock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.addr()); - - // prx: exchange with 0xabadcafe, translate exchanged value - if (lock->exchange(be_t::make(0xabadcafe)).data()) - { - return CELL_EBUSY; - } - - return CELL_OK; -} - -void sys_spinlock_unlock(vm::ptr> lock) -{ - sys_spinlock.Log("sys_spinlock_unlock(lock_addr=0x%x)", lock.addr()); - - // prx: sync and set 0 - lock->exchange(be_t::make(0)); -} diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h deleted file mode 100644 index 42a2bb5a6c..0000000000 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -// SysCalls -void sys_spinlock_initialize(vm::ptr> lock); -void sys_spinlock_lock(vm::ptr> lock); -s32 sys_spinlock_trylock(vm::ptr> lock); -void sys_spinlock_unlock(vm::ptr> lock); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index c3d5e90d0e..d0f086572f 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -194,7 +194,6 @@ - @@ -457,7 +456,6 @@ - diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 0d0905572a..c1fa6b8ea9 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -512,9 +512,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Emu\SysCalls\lv2 @@ -1282,9 +1279,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Emu\SysCalls\lv2 From 8155ef5e67fe0c8fe3c957940babb77caf0d9179 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Mar 2015 04:30:34 +0300 Subject: [PATCH 03/18] Lv2 lwmutex "true" syscalls experimentally implemented --- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 20 +-- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp | 124 +++++++++++++++++-- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h | 27 ++-- 3 files changed, 142 insertions(+), 29 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 6104cb99fb..c43658a119 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -139,7 +139,7 @@ s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) } // call the syscall - if (s32 res = _sys_lwmutex_destroy(CPU, lwmutex->sleep_queue)) + if (s32 res = _sys_lwmutex_destroy(lwmutex->sleep_queue)) { // unlock the mutex if failed sys_lwmutex_unlock(CPU, lwmutex); @@ -209,20 +209,21 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout } } - lwmutex->waiter.atomic_op([](be_t& value){ value++; }); + // atomically increment waiter value using 64 bit op + lwmutex->all_info.atomic_op([](be_t& value){ value++; }); if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) { // locking succeeded - lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + lwmutex->all_info.atomic_op([](be_t& value){ value--; }); return CELL_OK; } // lock using the syscall - const s32 res = _sys_lwmutex_lock(CPU, lwmutex->sleep_queue, timeout); + const s32 res = _sys_lwmutex_lock(lwmutex->sleep_queue, timeout); - lwmutex->waiter.atomic_op([](be_t& value){ value--; }); + lwmutex->all_info.atomic_op([](be_t& value){ value--; }); if (res == CELL_OK) { @@ -285,10 +286,10 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) return CELL_EINVAL; } - if (old_owner.data() == se32(lwmutex_busy)) + if (old_owner.data() == se32(lwmutex_reserved)) { // should be locked by the syscall - const s32 res = _sys_lwmutex_trylock(CPU, lwmutex->sleep_queue); + const s32 res = _sys_lwmutex_trylock(lwmutex->sleep_queue); if (res == CELL_OK) { @@ -335,10 +336,11 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) // TODO (protocol is ignored in current implementation) } - lwmutex->owner.exchange(lwmutex::busy); + // set special value + lwmutex->owner.exchange(lwmutex::reserved); // call the syscall - if (_sys_lwmutex_unlock(CPU, lwmutex->sleep_queue) == CELL_ESRCH) + if (_sys_lwmutex_unlock(lwmutex->sleep_queue) == CELL_ESRCH) { return CELL_ESRCH; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 3336574681..43dc044e59 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -14,35 +14,137 @@ SysCallBase sys_lwmutex("sys_lwmutex"); void lwmutex_create(sys_lwmutex_t& lwmutex, bool recursive, u32 protocol, u64 name) { - std::shared_ptr lw(new lwmutex_t(protocol, name)); + std::shared_ptr mutex(new lwmutex_t(protocol, name)); lwmutex.lock_var.write_relaxed({ lwmutex::free, lwmutex::zero }); lwmutex.attribute = protocol | (recursive ? SYS_SYNC_RECURSIVE : SYS_SYNC_NOT_RECURSIVE); lwmutex.recursive_count = 0; - lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(lw, TYPE_LWMUTEX); + lwmutex.sleep_queue = Emu.GetIdManager().GetNewID(mutex, TYPE_LWMUTEX); } s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6) { - throw __FUNCTION__; + sys_lwmutex.Warning("_sys_lwmutex_create(lwmutex_id=*0x%x, protocol=0x%x, control=*0x%x, arg4=0x%x, name=0x%llx, arg6=0x%x)", lwmutex_id, protocol, control, arg4, name, arg6); + + switch (protocol) + { + case SYS_SYNC_FIFO: break; + case SYS_SYNC_RETRY: break; + case SYS_SYNC_PRIORITY: break; + default: sys_lwmutex.Error("_sys_lwmutex_create(): invalid protocol (0x%x)", protocol); return CELL_EINVAL; + } + + if (arg4 != 0x80000001 || arg6) + { + sys_lwmutex.Error("_sys_lwmutex_create(): unknown parameters (arg4=0x%x, arg6=0x%x)", arg4, arg6); + } + + std::shared_ptr mutex(new lwmutex_t(protocol, name)); + + *lwmutex_id = Emu.GetIdManager().GetNewID(mutex, TYPE_LWMUTEX); + + return CELL_OK; } -s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id) +s32 _sys_lwmutex_destroy(u32 lwmutex_id) { - throw __FUNCTION__; + sys_lwmutex.Warning("_sys_lwmutex_destroy(lwmutex_id=%d)", lwmutex_id); + + LV2_LOCK; + + std::shared_ptr mutex; + if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + if (mutex->waiters) + { + return CELL_EBUSY; + } + + Emu.GetIdManager().RemoveID(lwmutex_id); + + return CELL_OK; } -s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout) +s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout) { - throw __FUNCTION__; + sys_lwmutex.Log("_sys_lwmutex_lock(lwmutex_id=%d, timeout=0x%llx)", lwmutex_id, timeout); + + const u64 start_time = get_system_time(); + + LV2_LOCK; + + std::shared_ptr mutex; + if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + // protocol is ignored in current implementation + mutex->waiters++; assert(mutex->waiters > 0); + + while (!mutex->signals) + { + if (timeout && get_system_time() - start_time > timeout) + { + mutex->waiters--; assert(mutex->waiters >= 0); + return CELL_ETIMEDOUT; + } + + if (Emu.IsStopped()) + { + sys_lwmutex.Warning("_sys_lwmutex_lock(lwmutex_id=%d) aborted", lwmutex_id); + return CELL_OK; + } + + mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); + } + + mutex->signals--; + + mutex->waiters--; assert(mutex->waiters >= 0); + + return CELL_OK; } -s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id) +s32 _sys_lwmutex_trylock(u32 lwmutex_id) { - throw __FUNCTION__; + sys_lwmutex.Log("_sys_lwmutex_trylock(lwmutex_id=%d)", lwmutex_id); + + LV2_LOCK; + + std::shared_ptr mutex; + if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + if (mutex->waiters || !mutex->signals) + { + return CELL_EBUSY; + } + + mutex->signals--; + + return CELL_OK; } -s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id) +s32 _sys_lwmutex_unlock(u32 lwmutex_id) { - throw __FUNCTION__; + sys_lwmutex.Log("_sys_lwmutex_unlock(lwmutex_id=%d)", lwmutex_id); + + LV2_LOCK; + + std::shared_ptr mutex; + if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + mutex->signals++; + mutex->cv.notify_one(); + + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 7f76a4c8a2..4cf3a0ed3a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -14,10 +14,10 @@ struct sys_lwmutex_attribute_t enum : u32 { - lwmutex_zero = 0u, - lwmutex_free = 0u - 1u, - lwmutex_dead = 0u - 2u, - lwmutex_busy = 0u - 3u, + lwmutex_zero = 0u, + lwmutex_free = 0u - 1u, + lwmutex_dead = 0u - 2u, + lwmutex_reserved = 0u - 3u, }; namespace lwmutex @@ -36,7 +36,7 @@ namespace lwmutex static const_be_u32_t zero; static const_be_u32_t free; static const_be_u32_t dead; - static const_be_u32_t busy; + static const_be_u32_t reserved; } struct sys_lwmutex_t @@ -56,6 +56,8 @@ struct sys_lwmutex_t atomic_t owner; atomic_t waiter; }; + + atomic_t all_info; }; be_t attribute; @@ -69,6 +71,13 @@ struct lwmutex_t const u32 protocol; const u64 name; + // this object is not truly a mutex and its syscall names are wrong, it's probabably sleep queue or something + std::atomic signals; + + // TODO: use sleep queue, possibly remove condition variable + std::condition_variable cv; + std::atomic waiters; + lwmutex_t(u32 protocol, u64 name) : protocol(protocol) , name(name) @@ -83,7 +92,7 @@ class PPUThread; // SysCalls s32 _sys_lwmutex_create(vm::ptr lwmutex_id, u32 protocol, vm::ptr control, u32 arg4, u64 name, u32 arg6); -s32 _sys_lwmutex_destroy(PPUThread& CPU, u32 lwmutex_id); -s32 _sys_lwmutex_lock(PPUThread& CPU, u32 lwmutex_id, u64 timeout); -s32 _sys_lwmutex_trylock(PPUThread& CPU, u32 lwmutex_id); -s32 _sys_lwmutex_unlock(PPUThread& CPU, u32 lwmutex_id); +s32 _sys_lwmutex_destroy(u32 lwmutex_id); +s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout); +s32 _sys_lwmutex_trylock(u32 lwmutex_id); +s32 _sys_lwmutex_unlock(u32 lwmutex_id); From 1653991b9d03b9f17a6ed8fc9fb6ea645e13bf63 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Mar 2015 04:57:50 +0300 Subject: [PATCH 04/18] Using "using" in vm::ptr/ref --- rpcs3/Emu/ARMv7/Modules/sceFios.cpp | 4 +- rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp | 4 +- rpcs3/Emu/Memory/atomic.h | 17 +-- rpcs3/Emu/Memory/vm_ptr.h | 134 +++----------------- rpcs3/Emu/Memory/vm_ref.h | 79 +++--------- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 4 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 8 +- rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp | 8 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 6 +- 13 files changed, 62 insertions(+), 212 deletions(-) diff --git a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp index d542e97549..71dab26ea1 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp @@ -677,12 +677,12 @@ SceFiosDate sceFiosDateGetCurrent() throw __FUNCTION__; } -SceFiosDate sceFiosDateFromComponents(const struct vm::psv::ptr pComponents) +SceFiosDate sceFiosDateFromComponents(vm::psv::ptr pComponents) { throw __FUNCTION__; } -struct vm::psv::ptr sceFiosDateToComponents(SceFiosDate date, struct vm::psv::ptr pOutComponents) +vm::psv::ptr sceFiosDateToComponents(SceFiosDate date, vm::psv::ptr pOutComponents) { throw __FUNCTION__; } diff --git a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp index cdb9f5aa8e..31c0d665f3 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceNpMatching.cpp @@ -287,7 +287,7 @@ struct SceNpMatching2RoomGroup struct SceNpMatching2RoomMemberDataExternal { - struct vm::psv::ptr next; + vm::psv::ptr next; SceNpId npId; u64 joinDate; SceNpMatching2Role role; @@ -297,7 +297,7 @@ struct SceNpMatching2RoomMemberDataExternal struct SceNpMatching2RoomMemberDataInternal { - struct vm::psv::ptr next; + vm::psv::ptr next; SceNpId npId; u64 joinDate; diff --git a/rpcs3/Emu/Memory/atomic.h b/rpcs3/Emu/Memory/atomic.h index 7e0261b6e7..a97f40db30 100644 --- a/rpcs3/Emu/Memory/atomic.h +++ b/rpcs3/Emu/Memory/atomic.h @@ -195,29 +195,20 @@ public: const atomic_type res = InterlockedXor(&data, (atomic_type&)(right)) ^ (atomic_type&)(right); return (T&)res; } - }; -template struct atomic_le_t : public _atomic_base -{ -}; +template using atomic_le_t = _atomic_base; -template struct atomic_be_t : public _atomic_base::type> -{ -}; +template using atomic_be_t = _atomic_base::type>; namespace ps3 { - template struct atomic_t : public atomic_be_t - { - }; + template using atomic_t = atomic_be_t; } namespace psv { - template struct atomic_t : public atomic_le_t - { - }; + template using atomic_t = atomic_le_t; } using namespace ps3; diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index be49e8a42d..4301dc4dc1 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -411,106 +411,30 @@ namespace vm }; //BE pointer to LE data - template struct bptrl : public _ptr_base::type> - { - static const bptrl make(AT addr) - { - auto res = _ptr_base::type>::make(convert_le_be::type>(addr)); - return static_cast(res); - } - - using _ptr_base::type>::operator=; - }; + template using bptrl = _ptr_base::type>; //BE pointer to BE data - template struct bptrb : public _ptr_base::type, lvl, typename to_be_t::type> - { - static const bptrb make(AT addr) - { - auto res = _ptr_base::type, lvl, typename to_be_t::type>::make(convert_le_be::type>(addr)); - return static_cast(res); - } - - using _ptr_base::type, lvl, typename to_be_t::type>::operator=; - }; + template using bptrb = _ptr_base::type, lvl, typename to_be_t::type>; //LE pointer to BE data - template struct lptrb : public _ptr_base::type, lvl, AT> - { - static const lptrb make(AT addr) - { - auto res = _ptr_base::type, lvl, AT>::make(addr); - return static_cast(res); - } - - using _ptr_base::type, lvl, AT>::operator=; - }; + template using lptrb = _ptr_base::type, lvl, AT>; //LE pointer to LE data - template struct lptrl : public _ptr_base - { - static const lptrl make(AT addr) - { - auto res = _ptr_base::make(addr); - return static_cast(res); - } - - using _ptr_base::operator=; - }; + template using lptrl = _ptr_base; namespace ps3 { - template struct ptr; - template struct bptr; - //default pointer for HLE functions (LE pointer to BE data) - template struct ptr : public lptrb - { - static const ptr make(AT addr) - { - auto res = lptrb::make(addr); - return static_cast(res); - } - - vm::ps3::bptr to_be() const - { - return vm::ps3::bptr::make(this->addr()); - } - - using lptrb::operator=; - }; + template using ptr = lptrb; //default pointer for HLE structures (BE pointer to BE data) - template struct bptr : public bptrb - { - static const bptr make(AT addr) - { - auto res = bptrb::make(addr); - return static_cast(res); - } - - vm::ps3::ptr to_le() const - { - return vm::ps3::ptr::make(this->addr()); - } - - using bptrb::operator=; - }; + template using bptr = bptrb; } namespace psv { //default pointer for HLE functions & structures (LE pointer to LE data) - template struct ptr : public lptrl - { - static const ptr make(AT addr) - { - auto res = lptrl::make(addr); - return static_cast(res); - } - - using lptrl::operator=; - }; + template using ptr = lptrl; } //PS3 emulation is main now, so lets it be as default @@ -519,36 +443,14 @@ namespace vm namespace fmt { - // external specializations for fmt::format function + // external specialization for fmt::format function template - struct unveil, false> + struct unveil, false> { typedef typename unveil::result_type result_type; - __forceinline static result_type get_value(const vm::ps3::ptr& arg) - { - return unveil::get_value(arg.addr()); - } - }; - - template - struct unveil, false> - { - typedef typename unveil::result_type result_type; - - __forceinline static result_type get_value(const vm::ps3::bptr& arg) - { - return unveil::get_value(arg.addr()); - } - }; - - template - struct unveil, false> - { - typedef typename unveil::result_type result_type; - - __forceinline static result_type get_value(const vm::psv::ptr& arg) + __forceinline static result_type get_value(const vm::_ptr_base& arg) { return unveil::get_value(arg.addr()); } @@ -561,16 +463,16 @@ template struct cast_ppu_gpr; template -struct cast_ppu_gpr, false> +struct cast_ppu_gpr, false> { - __forceinline static u64 to_gpr(const vm::ps3::ptr& value) + __forceinline static u64 to_gpr(const vm::_ptr_base& value) { return value.addr(); } - __forceinline static vm::ps3::ptr from_gpr(const u64 reg) + __forceinline static vm::_ptr_base from_gpr(const u64 reg) { - return vm::ps3::ptr::make(cast_ppu_gpr::value>::from_gpr(reg)); + return vm::_ptr_base::make(cast_ppu_gpr::value>::from_gpr(reg)); } }; @@ -580,15 +482,15 @@ template struct cast_armv7_gpr; template -struct cast_armv7_gpr, false> +struct cast_armv7_gpr, false> { - __forceinline static u32 to_gpr(const vm::psv::ptr& value) + __forceinline static u32 to_gpr(const vm::_ptr_base& value) { return value.addr(); } - __forceinline static vm::psv::ptr from_gpr(const u32 reg) + __forceinline static vm::_ptr_base from_gpr(const u32 reg) { - return vm::psv::ptr::make(cast_armv7_gpr::value>::from_gpr(reg)); + return vm::_ptr_base::make(cast_armv7_gpr::value>::from_gpr(reg)); } }; diff --git a/rpcs3/Emu/Memory/vm_ref.h b/rpcs3/Emu/Memory/vm_ref.h index f7256cedff..c13d3a502a 100644 --- a/rpcs3/Emu/Memory/vm_ref.h +++ b/rpcs3/Emu/Memory/vm_ref.h @@ -61,51 +61,30 @@ namespace vm }; //BE reference to LE data - template struct brefl : public _ref_base::type> - { - using _ref_base::type>::operator=; - }; + template using brefl = _ref_base::type>; //BE reference to BE data - template struct brefb : public _ref_base::type, typename to_be_t::type> - { - using _ref_base::type, typename to_be_t::type>::operator=; - }; + template using brefb = _ref_base::type, typename to_be_t::type>; //LE reference to BE data - template struct lrefb : public _ref_base::type, AT> - { - using _ref_base::type, AT>::operator=; - }; + template using lrefb = _ref_base::type, AT>; //LE reference to LE data - template struct lrefl : public _ref_base - { - using _ref_base::operator=; - }; + template using lrefl = _ref_base; namespace ps3 { //default reference for HLE functions (LE reference to BE data) - template struct ref : public lrefb - { - using lrefb::operator=; - }; + template using ref = lrefb; //default reference for HLE structures (BE reference to BE data) - template struct bref : public brefb - { - using brefb::operator=; - }; + template using bref = brefb; } namespace psv { //default reference for HLE functions & structures (LE reference to LE data) - template struct ref : public lrefl - { - using lrefl::operator=; - }; + template using ref = lrefl; } //PS3 emulation is main now, so lets it be as default @@ -114,36 +93,14 @@ namespace vm namespace fmt { - // external specializations for fmt::format function + // external specialization for fmt::format function template - struct unveil, false> + struct unveil, false> { typedef typename unveil::result_type result_type; - __forceinline static result_type get_value(const vm::ps3::ref& arg) - { - return unveil::get_value(arg.addr()); - } - }; - - template - struct unveil, false> - { - typedef typename unveil::result_type result_type; - - __forceinline static result_type get_value(const vm::ps3::bref& arg) - { - return unveil::get_value(arg.addr()); - } - }; - - template - struct unveil, false> - { - typedef typename unveil::result_type result_type; - - __forceinline static result_type get_value(const vm::psv::ref& arg) + __forceinline static result_type get_value(const vm::_ref_base& arg) { return unveil::get_value(arg.addr()); } @@ -156,16 +113,16 @@ template struct cast_ppu_gpr; template -struct cast_ppu_gpr, false> +struct cast_ppu_gpr, false> { - __forceinline static u64 to_gpr(const vm::ps3::ref& value) + __forceinline static u64 to_gpr(const vm::_ref_base& value) { return value.addr(); } - __forceinline static vm::ps3::ref from_gpr(const u64 reg) + __forceinline static vm::_ref_base from_gpr(const u64 reg) { - return vm::ps3::ref::make(cast_ppu_gpr::value>::from_gpr(reg)); + return vm::_ref_base::make(cast_ppu_gpr::value>::from_gpr(reg)); } }; @@ -175,15 +132,15 @@ template struct cast_armv7_gpr; template -struct cast_armv7_gpr, false> +struct cast_armv7_gpr, false> { - __forceinline static u32 to_gpr(const vm::psv::ref& value) + __forceinline static u32 to_gpr(const vm::_ref_base& value) { return value.addr(); } - __forceinline static vm::psv::ref from_gpr(const u32 reg) + __forceinline static vm::_ref_base from_gpr(const u32 reg) { - return vm::psv::ref::make(cast_armv7_gpr::value>::from_gpr(reg)); + return vm::_ref_base::make(cast_armv7_gpr::value>::from_gpr(reg)); } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index fbc4769c7b..f2c2216316 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -530,7 +530,7 @@ int cellAdecOpen(vm::ptr type, vm::ptr res, vm:: if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG; - *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg)); + *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg)); return CELL_OK; } @@ -542,7 +542,7 @@ int cellAdecOpenEx(vm::ptr type, vm::ptr res, if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG; - *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg)); + *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg)); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index f5fc056ef9..dcf6008181 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -814,7 +814,7 @@ int cellDmuxOpen(vm::ptr demuxerType, vm::ptrmemAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg)); return CELL_OK; } @@ -832,7 +832,7 @@ int cellDmuxOpenEx(vm::ptr demuxerType, vm::ptrmemAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg)); return CELL_OK; } @@ -850,7 +850,7 @@ int cellDmuxOpen2(vm::ptr demuxerType2, vm::ptrmemAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc, demuxerCb->cbArg)); return CELL_OK; } @@ -1008,7 +1008,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil std::shared_ptr es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - esCb->cbEsMsgFunc.to_le(), esCb->cbArg, esSpecificInfo_addr)); + esCb->cbEsMsgFunc, esCb->cbArg, esSpecificInfo_addr)); u32 id = Emu.GetIdManager().GetNewID(es); es->id = id; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp index a51e75af76..6f26cea6c3 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp @@ -41,7 +41,7 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptr> fd; - int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr::make(0), 0); current_subHandle->fd = fd.value(); if (ret != CELL_OK) return CELL_GIFDEC_ERROR_OPEN_FILE; diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp index bbb007588a..a88cbd8921 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp @@ -47,7 +47,7 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptr> fd; - int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr::make(0), 0); current_subHandle->fd = fd.value(); if (ret != CELL_OK) return CELL_JPGDEC_ERROR_OPEN_FILE; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp index 539161c412..9e10fdf8dc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp @@ -78,7 +78,7 @@ s32 pngDecOpen( case se32(CELL_PNGDEC_FILE): // Get file descriptor vm::var> fd; - int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + int ret = cellFsOpen(src->fileName, 0, fd, vm::ptr::make(0), 0); stream->fd = fd.value(); if (ret != CELL_OK) return CELL_PNGDEC_ERROR_OPEN_FILE; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index db244d22f2..5ca28a0f6c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -382,9 +382,9 @@ s32 cellSaveDataListSave2( return CELL_SAVEDATA_ERROR_CBRESULT; } - setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum); + setSaveDataList(saveEntries, listSet->fixedList, listSet->fixedListNum); if (listSet->newData) - addNewSaveDataEntry(saveEntries, listSet->newData.to_le()); + addNewSaveDataEntry(saveEntries, listSet->newData); if (saveEntries.size() == 0) { cellSysutil.Error("cellSaveDataListSave2: No save entries found!"); // TODO: Find a better way to handle this error return CELL_OK; @@ -474,9 +474,9 @@ s32 cellSaveDataListLoad2( return CELL_SAVEDATA_ERROR_CBRESULT; } - setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum); + setSaveDataList(saveEntries, listSet->fixedList, listSet->fixedListNum); if (listSet->newData) - addNewSaveDataEntry(saveEntries, listSet->newData.to_le()); + addNewSaveDataEntry(saveEntries, listSet->newData); if (saveEntries.size() == 0) { cellSysutil.Error("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 26447c0c72..712eb75e50 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -576,7 +576,7 @@ int cellVdecOpen(vm::ptr type, vm::ptrcodecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg)); + *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg)); return CELL_OK; } @@ -586,7 +586,7 @@ int cellVdecOpenEx(vm::ptr type, vm::ptrcodecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg)); + *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg)); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 5ee5c0c34e..5d7d86e196 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -68,7 +68,7 @@ s32 sys_lwcond_signal(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = lwcond->lwmutex.to_le(); + auto mutex = lwcond->lwmutex; if (u32 target = lw->queue.signal(mutex->attribute)) { @@ -92,7 +92,7 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = lwcond->lwmutex.to_le(); + auto mutex = lwcond->lwmutex; while (u32 target = lw->queue.signal(mutex->attribute)) { @@ -141,7 +141,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) return CELL_ESRCH; } - auto mutex = lwcond->lwmutex.to_le(); + auto mutex = lwcond->lwmutex; u32 tid_le = CPU.GetId(); auto tid = be_t::make(tid_le); From 2709dc2e36b6c2b16acccd2495d267c83a5b80d1 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Mar 2015 05:05:53 +0300 Subject: [PATCH 05/18] Compilation fix --- rpcs3/Emu/SysCalls/lv2/sys_timer.cpp | 14 +++++++------- rpcs3/Emu/SysCalls/lv2/sys_timer.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index e1bbfe51dc..8cb4c8f618 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -16,7 +16,7 @@ s32 sys_timer_create(vm::ptr timer_id) { sys_timer.Warning("sys_timer_create(timer_id=*0x%x)", timer_id); - std::shared_ptr timer(new timer_t); + std::shared_ptr timer(new lv2_timer_t); thread_t(fmt::format("Timer[%d] Thread", (*timer_id = Emu.GetIdManager().GetNewID(timer, TYPE_TIMER))), [timer]() { @@ -63,7 +63,7 @@ s32 sys_timer_destroy(u32 timer_id) LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; if (!Emu.GetIdManager().GetIDData(timer_id, timer)) { return CELL_ESRCH; @@ -85,7 +85,7 @@ s32 sys_timer_get_information(u32 timer_id, vm::ptr inf LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; if (!Emu.GetIdManager().GetIDData(timer_id, timer)) { return CELL_ESRCH; @@ -108,7 +108,7 @@ s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period) LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; if (!Emu.GetIdManager().GetIDData(timer_id, timer)) { return CELL_ESRCH; @@ -159,7 +159,7 @@ s32 sys_timer_stop(u32 timer_id) LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; if (!Emu.GetIdManager().GetIDData(timer_id, timer)) { return CELL_ESRCH; @@ -176,7 +176,7 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; std::shared_ptr queue; if (!Emu.GetIdManager().GetIDData(timer_id, timer) || !Emu.GetIdManager().GetIDData(queue_id, queue)) @@ -203,7 +203,7 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id) LV2_LOCK; - std::shared_ptr timer; + std::shared_ptr timer; if (!Emu.GetIdManager().GetIDData(timer_id, timer)) { return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.h b/rpcs3/Emu/SysCalls/lv2/sys_timer.h index 47862e39cc..3057a38a18 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.h @@ -15,7 +15,7 @@ struct sys_timer_information_t be_t pad; }; -struct timer_t +struct lv2_timer_t { std::weak_ptr port; // event queue u64 source; // event source @@ -28,7 +28,7 @@ struct timer_t std::atomic state; // timer state std::condition_variable cv; - timer_t() + lv2_timer_t() : start(0) , period(0) , state(SYS_TIMER_STATE_STOP) From 3cf80b08313f0633e11bb8a927866c38ea2f8297 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Mar 2015 22:56:55 +0300 Subject: [PATCH 06/18] sys_lwcond* funcs moved and rewritten --- rpcs3/Emu/ARMv7/Modules/sceLibc.cpp | 2 - rpcs3/Emu/Memory/atomic.h | 36 +++ rpcs3/Emu/Memory/vm_ptr.h | 44 +-- rpcs3/Emu/Memory/vm_ref.h | 4 +- rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp | 8 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 302 +++++++++++++++++-- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h | 10 + rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp | 4 +- rpcs3/Emu/SysCalls/SysCalls.cpp | 11 +- rpcs3/Emu/SysCalls/lv2/sys_cond.cpp | 14 +- rpcs3/Emu/SysCalls/lv2/sys_cond.h | 3 +- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 205 ++----------- rpcs3/Emu/SysCalls/lv2/sys_lwcond.h | 28 +- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp | 10 +- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h | 2 +- rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp | 24 +- rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp | 6 +- rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h | 8 +- 18 files changed, 433 insertions(+), 288 deletions(-) diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index bd21c9405d..c724fe56a7 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -175,8 +175,6 @@ namespace sce_libc_func void exit(ARMv7Context& context) { sceLibc.Warning("exit()"); - - LV2_LOCK; for (auto func : g_atexit) { diff --git a/rpcs3/Emu/Memory/atomic.h b/rpcs3/Emu/Memory/atomic.h index a97f40db30..d9dd6e96db 100644 --- a/rpcs3/Emu/Memory/atomic.h +++ b/rpcs3/Emu/Memory/atomic.h @@ -197,6 +197,42 @@ public: } }; +__forceinline static u64 operator ++(_atomic_base>& left, int) +{ + u64 result; + + left.atomic_op([&result](be_t& value) + { + result = value++; + }); + + return result; +} + +__forceinline static u64 operator --(_atomic_base>& left, int) +{ + u64 result; + + left.atomic_op([&result](be_t& value) + { + result = value--; + }); + + return result; +} + +__forceinline static u64 operator +=(_atomic_base>& left, u64 right) +{ + u64 result; + + left.atomic_op([&result, right](be_t& value) + { + result = (value += right); + }); + + return result; +} + template using atomic_le_t = _atomic_base; template using atomic_be_t = _atomic_base::type>; diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 4301dc4dc1..79fca811d9 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -78,10 +78,10 @@ namespace vm } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } AT addr() const @@ -94,9 +94,9 @@ namespace vm m_addr = value; } - static const _ptr_base make(const AT& addr) + static _ptr_base make(const AT& addr) { - return reinterpret_cast(addr); + return reinterpret_cast<_ptr_base&>(addr); } _ptr_base& operator = (const _ptr_base& right) = default; @@ -203,10 +203,10 @@ namespace vm } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } T* get_ptr() const @@ -269,17 +269,17 @@ namespace vm explicit operator bool() const { return m_addr != 0; } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } static const _ptr_base make(const AT& addr) @@ -332,10 +332,10 @@ namespace vm explicit operator bool() const { return m_addr != 0; } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } static const _ptr_base make(const AT& addr) @@ -381,10 +381,10 @@ namespace vm explicit operator bool() const { return m_addr != 0; } template - operator const _ptr_base() const + operator _ptr_base() const { - const AT2 addr = convert_le_be(m_addr); - return reinterpret_cast&>(addr); + AT2 addr = convert_le_be(m_addr); + return reinterpret_cast<_ptr_base&>(addr); } static const _ptr_base make(const AT& addr) @@ -467,7 +467,7 @@ struct cast_ppu_gpr, false> { __forceinline static u64 to_gpr(const vm::_ptr_base& value) { - return value.addr(); + return cast_ppu_gpr::value>::to_gpr(value.addr()); } __forceinline static vm::_ptr_base from_gpr(const u64 reg) @@ -486,7 +486,7 @@ struct cast_armv7_gpr, false> { __forceinline static u32 to_gpr(const vm::_ptr_base& value) { - return value.addr(); + return cast_armv7_gpr::value>::to_gpr(value.addr()); } __forceinline static vm::_ptr_base from_gpr(const u32 reg) diff --git a/rpcs3/Emu/Memory/vm_ref.h b/rpcs3/Emu/Memory/vm_ref.h index c13d3a502a..c43474bea5 100644 --- a/rpcs3/Emu/Memory/vm_ref.h +++ b/rpcs3/Emu/Memory/vm_ref.h @@ -117,7 +117,7 @@ struct cast_ppu_gpr, false> { __forceinline static u64 to_gpr(const vm::_ref_base& value) { - return value.addr(); + return cast_ppu_gpr::value>::to_gpr(value.addr()); } __forceinline static vm::_ref_base from_gpr(const u64 reg) @@ -136,7 +136,7 @@ struct cast_armv7_gpr, false> { __forceinline static u32 to_gpr(const vm::_ref_base& value) { - return value.addr(); + return cast_armv7_gpr::value>::to_gpr(value.addr()); } __forceinline static vm::_ref_base from_gpr(const u32 reg) diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index b5f59e1ee7..7b78219c5d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -168,11 +168,7 @@ s32 spursInit( } lwmutex_create(spurs->m.mutex, false, SYS_SYNC_PRIORITY, *(u64*)"_spuPrv"); - - if (s32 res = lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv")) - { - assert(!"lwcond_create() failed"); - } + lwcond_create(spurs->m.cond, spurs->m.mutex, *(u64*)"_spuPrv"); spurs->m.flags1 = (flags & SAF_EXIT_IF_NO_WORK ? SF1_EXIT_IF_NO_WORK : 0) | (isSecond ? SF1_32_WORKLOADS : 0); spurs->m.wklFlagReceiver.write_relaxed(0xff); @@ -848,7 +844,7 @@ s32 spursWakeUp(PPUThread& CPU, vm::ptr spurs) { assert(!"sys_lwmutex_lock() failed"); } - if (s32 res = sys_lwcond_signal(spurs->get_lwcond())) + if (s32 res = sys_lwcond_signal(CPU, spurs->get_lwcond())) { assert(!"sys_lwcond_signal() failed"); } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index c43658a119..517904ae66 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -124,7 +124,7 @@ s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr lwmutex) { - sysPrxForUser.Warning("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); + sysPrxForUser.Log("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex); // check to prevent recursive locking in the next call if (lwmutex->lock_var.read_relaxed().owner == CPU.GetId()) @@ -210,12 +210,12 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout } // atomically increment waiter value using 64 bit op - lwmutex->all_info.atomic_op([](be_t& value){ value++; }); + lwmutex->all_info++; if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) { // locking succeeded - lwmutex->all_info.atomic_op([](be_t& value){ value--; }); + lwmutex->all_info--; return CELL_OK; } @@ -223,7 +223,7 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout // lock using the syscall const s32 res = _sys_lwmutex_lock(lwmutex->sleep_queue, timeout); - lwmutex->all_info.atomic_op([](be_t& value){ value--; }); + lwmutex->all_info--; if (res == CELL_OK) { @@ -348,6 +348,275 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) return CELL_OK; } +s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr) +{ + sysPrxForUser.Warning("sys_lwcond_create(lwcond=*0x%x, lwmutex=*0x%x, attr=*0x%x)", lwcond, lwmutex, attr); + + std::shared_ptr lwc(new lwcond_t(attr->name_u64)); + + lwcond->lwcond_queue = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); + lwcond->lwmutex = lwmutex; + + return CELL_OK; +} + +s32 sys_lwcond_destroy(vm::ptr lwcond) +{ + sysPrxForUser.Log("sys_lwcond_destroy(lwcond=*0x%x)", lwcond); + + const s32 res = _sys_lwcond_destroy(lwcond->lwcond_queue); + + if (res == CELL_OK) + { + lwcond->lwcond_queue = lwmutex::dead; + } + + return res; +} + +s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr lwcond) +{ + sysPrxForUser.Log("sys_lwcond_signal(lwcond=*0x%x)", lwcond); + + const vm::ptr lwmutex = lwcond->lwmutex; + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) + { + // TODO (protocol ignored) + } + + if (lwmutex->owner.read_relaxed() == CPU.GetId()) + { + // if owns the mutex + lwmutex->all_info++; + + // call the syscall + if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 1)) + { + lwmutex->all_info--; + + return res == CELL_EPERM ? CELL_OK : res; + } + + return CELL_OK; + } + + if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) + { + // if locking failed + + if (res != CELL_EBUSY) + { + return CELL_ESRCH; + } + + // call the syscall + return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2); + } + + // if locking succeeded + lwmutex->all_info++; + + // call the syscall + if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 3)) + { + lwmutex->all_info--; + + // unlock the lightweight mutex + sys_lwmutex_unlock(CPU, lwmutex); + + return res == CELL_ENOENT ? CELL_OK : res; + } + + return CELL_OK; +} + +s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr lwcond) +{ + sysPrxForUser.Log("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond); + + const vm::ptr lwmutex = lwcond->lwmutex; + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) + { + // TODO (protocol ignored) + } + + if (lwmutex->owner.read_relaxed() == CPU.GetId()) + { + // if owns the mutex, call the syscall + const s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); + + if (res <= 0) + { + // return error or CELL_OK + return res; + } + + lwmutex->all_info += res; + + return CELL_OK; + } + + if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) + { + // if locking failed + + if (res != CELL_EBUSY) + { + return CELL_ESRCH; + } + + // call the syscall + return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); + } + + // if locking succeeded, call the syscall + s32 res = _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 1); + + if (res > 0) + { + lwmutex->all_info += res; + + res = CELL_OK; + } + + // unlock mutex + sys_lwmutex_unlock(CPU, lwmutex); + + return res; +} + +s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr lwcond, u32 ppu_thread_id) +{ + sysPrxForUser.Log("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=%d)", lwcond, ppu_thread_id); + + const vm::ptr lwmutex = lwcond->lwmutex; + + if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) + { + // TODO (protocol ignored) + } + + if (lwmutex->owner.read_relaxed() == CPU.GetId()) + { + // if owns the mutex + lwmutex->all_info++; + + // call the syscall + if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 1)) + { + lwmutex->all_info--; + + return res; + } + + return CELL_OK; + } + + if (s32 res = sys_lwmutex_trylock(CPU, lwmutex)) + { + // if locking failed + + if (res != CELL_EBUSY) + { + return CELL_ESRCH; + } + + // call the syscall + return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); + } + + // if locking succeeded + lwmutex->all_info++; + + // call the syscall + if (s32 res = _sys_lwcond_signal(lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 3)) + { + lwmutex->all_info--; + + // unlock the lightweight mutex + sys_lwmutex_unlock(CPU, lwmutex); + + return res; + } + + return CELL_OK; +} + +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) +{ + sysPrxForUser.Log("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout); + + const be_t tid = be_t::make(CPU.GetId()); + + const vm::ptr lwmutex = lwcond->lwmutex; + + if (lwmutex->owner.read_relaxed() != tid) + { + // if not owner of the mutex + return CELL_EPERM; + } + + // save old recursive value + const be_t recursive_value = lwmutex->recursive_count; + + // set special value + lwmutex->owner.write_relaxed(lwmutex::reserved); + lwmutex->recursive_count = 0; + + // call the syscall + s32 res = _sys_lwcond_queue_wait(lwcond->lwcond_queue, lwmutex->sleep_queue, timeout); + + if (res == CELL_OK || res == CELL_ESRCH) + { + if (res == CELL_OK) + { + lwmutex->all_info--; + } + + // restore owner and recursive value + lwmutex->owner.exchange(tid); + lwmutex->recursive_count = recursive_value; + + return res; + } + + if (res == CELL_EBUSY || res == CELL_ETIMEDOUT) + { + const s32 res2 = sys_lwmutex_lock(CPU, lwmutex, 0); + + if (res2 == CELL_OK) + { + // if successfully locked, restore recursive value + lwmutex->recursive_count = recursive_value; + + return res == CELL_EBUSY ? CELL_OK : res; + } + + return res2; + } + + if (res == CELL_EDEADLK) + { + const auto owner = lwmutex->owner.read_relaxed(); + + if (owner.data() != se32(lwmutex_reserved)) + { + sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected lwmutex->owner (0x%x)", lwcond, owner); + } + + // restore owner and recursive value + lwmutex->owner.exchange(tid); + lwmutex->recursive_count = recursive_value; + + return CELL_ETIMEDOUT; + } + + sysPrxForUser.Fatal("sys_lwconde_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res); + return res; +} + std::string ps3_fmt(PPUThread& context, vm::ptr fmt, u32 g_count, u32 f_count, u32 v_count) { std::string result; @@ -849,14 +1118,7 @@ void sys_spinlock_lock(vm::ptr> lock) // prx: exchange with 0xabadcafe, repeat until exchanged with 0 while (lock->exchange(be_t::make(0xabadcafe)).data()) { - while (lock->read_relaxed().data()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - break; - } - } + g_sys_spinlock_wm.wait_op(lock.addr(), [lock](){ return lock->read_relaxed().data() == 0; }); if (Emu.IsStopped()) { @@ -885,6 +1147,8 @@ void sys_spinlock_unlock(vm::ptr> lock) // prx: sync and set 0 lock->exchange(be_t::make(0)); + + g_sys_spinlock_wm.notify(lock.addr()); } Module sysPrxForUser("sysPrxForUser", []() @@ -911,6 +1175,13 @@ Module sysPrxForUser("sysPrxForUser", []() REG_FUNC(sysPrxForUser, sys_lwmutex_trylock); REG_FUNC(sysPrxForUser, sys_lwmutex_unlock); + REG_FUNC(sysPrxForUser, sys_lwcond_create); + REG_FUNC(sysPrxForUser, sys_lwcond_destroy); + REG_FUNC(sysPrxForUser, sys_lwcond_signal); + REG_FUNC(sysPrxForUser, sys_lwcond_signal_all); + REG_FUNC(sysPrxForUser, sys_lwcond_signal_to); + REG_FUNC(sysPrxForUser, sys_lwcond_wait); + REG_FUNC(sysPrxForUser, sys_time_get_system_time); REG_FUNC(sysPrxForUser, sys_process_exit); @@ -957,13 +1228,6 @@ Module sysPrxForUser("sysPrxForUser", []() REG_FUNC(sysPrxForUser, sys_raw_spu_load); REG_FUNC(sysPrxForUser, sys_raw_spu_image_load); - REG_FUNC(sysPrxForUser, sys_lwcond_create); - REG_FUNC(sysPrxForUser, sys_lwcond_destroy); - REG_FUNC(sysPrxForUser, sys_lwcond_signal); - REG_FUNC(sysPrxForUser, sys_lwcond_signal_all); - REG_FUNC(sysPrxForUser, sys_lwcond_signal_to); - REG_FUNC(sysPrxForUser, sys_lwcond_wait); - REG_FUNC(sysPrxForUser, sys_get_random_number); REG_FUNC(sysPrxForUser, sys_spinlock_initialize); diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h index 7a461b06e5..19e166545c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.h @@ -33,3 +33,13 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); + +struct sys_lwcond_t; +struct sys_lwcond_attribute_t; + +s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); +s32 sys_lwcond_destroy(vm::ptr lwcond); +s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr lwcond); +s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr lwcond); +s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr lwcond, u32 ppu_thread_id); +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout); diff --git a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp index a71fa05f55..9ddad0616c 100644 --- a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp +++ b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp @@ -40,10 +40,10 @@ std::string SyncPrimManager::GetSyncPrimName(u32 id, IDType type) { case TYPE_LWCOND: { - std::shared_ptr lw; + std::shared_ptr lw; if (Emu.GetIdManager().GetIDData(id, lw)) { - return std::string((const char*)&lw->queue.name, 8); + return std::string((const char*)&lw->name, 8); } break; } diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index 55dd25915a..1def24c74e 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -9,6 +9,7 @@ #include "lv2/cellFs.h" #include "lv2/sleep_queue.h" #include "lv2/sys_lwmutex.h" +#include "lv2/sys_lwcond.h" #include "lv2/sys_mutex.h" #include "lv2/sys_cond.h" #include "lv2/sys_event.h" @@ -146,12 +147,12 @@ const ppu_func_caller sc_table[1024] = bind_func(sys_cond_signal), //108 (0x06C) bind_func(sys_cond_signal_all), //109 (0x06D) bind_func(sys_cond_signal_to), //110 (0x06E) - null_func,//bind_func(_sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create - null_func,//bind_func(_sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy - null_func,//bind_func(_sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait + bind_func(_sys_lwcond_create), //111 (0x06F) + bind_func(_sys_lwcond_destroy), //112 (0x070) + bind_func(_sys_lwcond_queue_wait), //113 (0x071) bind_func(sys_semaphore_get_value), //114 (0x072) - null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to - null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all + bind_func(_sys_lwcond_signal), //115 (0x073) + bind_func(_sys_lwcond_signal_all), //116 (0x074) null_func,//bind_func(sys_semaphore_...) //117 (0x075) // internal, used by sys_lwmutex_unlock bind_func(sys_event_flag_clear), //118 (0x076) null_func,//bind_func(sys_event_...) //119 (0x077) ROOT diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index 1555846611..42a77d75bd 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -89,7 +89,7 @@ s32 sys_cond_signal(u32 cond_id) { cond->signaled++; cond->waiters--; - cond->mutex->cv.notify_one(); + cond->cv.notify_one(); } return CELL_OK; @@ -111,7 +111,7 @@ s32 sys_cond_signal_all(u32 cond_id) if (cond->waiters) { cond->signaled += cond->waiters.exchange(0); - cond->mutex->cv.notify_all(); + cond->cv.notify_all(); } return CELL_OK; @@ -142,7 +142,8 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) cond->signaled++; cond->waiters--; - cond->mutex->cv.notify_one(); + cond->cv.notify_one(); + return CELL_OK; } @@ -174,7 +175,7 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) // unlock mutex cond->mutex->owner.reset(); - // not sure whether the recursive value is precisely saved + // save recursive value const u32 recursive_value = cond->mutex->recursive_count.exchange(0); while (!cond->mutex->owner.expired() || !cond->signaled) @@ -192,10 +193,11 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) return CELL_OK; } - cond->mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); + // wait on appropriate condition variable + (cond->signaled ? cond->mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1)); } - // restore mutex owner + // reown the mutex and restore recursive value cond->mutex->owner = thread; cond->mutex->recursive_count = recursive_value; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index 979493d97c..0c445f8155 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -20,7 +20,8 @@ struct cond_t const u64 name; const std::shared_ptr mutex; // associated mutex - // TODO: use sleep queue + // TODO: use sleep queue, possibly remove condition variable + std::condition_variable cv; std::atomic waiters; std::atomic signaled; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 5d7d86e196..39bb23bda6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -13,220 +13,63 @@ SysCallBase sys_lwcond("sys_lwcond"); -s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64) +void lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name) { - const u32 addr = vm::get_addr(&lwmutex); + std::shared_ptr lwc(new lwcond_t(name)); - std::shared_ptr lw(new Lwcond(name_u64, addr)); + lwcond.lwcond_queue = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); +} - const u32 id = Emu.GetIdManager().GetNewID(lw, TYPE_LWCOND); +s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5) +{ + sys_lwcond.Warning("_sys_lwcond_create(lwcond_id=*0x%x, lwmutex_id=%d, control=*0x%x, name=0x%llx, arg5=0x%x)", lwcond_id, lwmutex_id, control, name, arg5); - lw->queue.set_full_name(fmt::Format("Lwcond(%d, addr=0x%x)", id, lw->addr)); - lwcond.lwmutex.set(addr); - lwcond.lwcond_queue = id; + std::shared_ptr lwc(new lwcond_t(name)); + + *lwcond_id = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); - sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), addr, id); return CELL_OK; } -s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr) +s32 _sys_lwcond_destroy(u32 lwcond_id) { - sys_lwcond.Log("sys_lwcond_create(lwcond_addr=0x%x, lwmutex_addr=0x%x, attr_addr=0x%x)", - lwcond.addr(), lwmutex.addr(), attr.addr()); + sys_lwcond.Warning("_sys_lwcond_destroy(lwcond_id=%d)", lwcond_id); - return lwcond_create(*lwcond, *lwmutex, attr->name_u64); -} + LV2_LOCK; -s32 sys_lwcond_destroy(vm::ptr lwcond) -{ - sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.addr()); - - u32 id = lwcond->lwcond_queue; - - std::shared_ptr lw; - if (!Emu.GetIdManager().GetIDData(id, lw)) + std::shared_ptr lwc; + if (!Emu.GetIdManager().GetIDData(lwcond_id, lwc)) { return CELL_ESRCH; } - if (lw->queue.count()) // TODO: safely make object unusable + if (lwc->waiters) { return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(id); + Emu.GetIdManager().RemoveID(lwcond_id); + return CELL_OK; } -s32 sys_lwcond_signal(vm::ptr lwcond) +s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode) { - sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.addr()); - - std::shared_ptr lw; - if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) - { - return CELL_ESRCH; - } - - auto mutex = lwcond->lwmutex; - - if (u32 target = lw->queue.signal(mutex->attribute)) - { - if (Emu.IsStopped()) - { - sys_lwcond.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue); - return CELL_OK; - } - } + sys_lwcond.Fatal("_sys_lwcond_signal(lwcond_id=%d, lwmutex_id=%d, ppu_thread_id=%d, mode=%d)", lwcond_id, lwmutex_id, ppu_thread_id, mode); return CELL_OK; } -s32 sys_lwcond_signal_all(vm::ptr lwcond) +s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode) { - sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.addr()); - - std::shared_ptr lw; - if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) - { - return CELL_ESRCH; - } - - auto mutex = lwcond->lwmutex; - - while (u32 target = lw->queue.signal(mutex->attribute)) - { - if (Emu.IsStopped()) - { - sys_lwcond.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue); - return CELL_OK; - } - } + sys_lwcond.Fatal("_sys_lwcond_signal_all(lwcond_id=%d, lwmutex_id=%d, mode=%d)", lwcond_id, lwmutex_id, mode); return CELL_OK; } -s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id) +s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) { - sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.addr(), ppu_thread_id); - - std::shared_ptr lw; - if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) - { - return CELL_ESRCH; - } - - if (!Emu.GetIdManager().CheckID(ppu_thread_id)) - { - return CELL_ESRCH; - } - - if (!lw->queue.signal_selected(ppu_thread_id)) - { - return CELL_EPERM; - } + sys_lwcond.Fatal("_sys_lwcond_queue_wait(lwcond_id=%d, lwmutex_id=%d, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout); return CELL_OK; } - -s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) -{ - sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); - - const u64 start_time = get_system_time(); - - std::shared_ptr lw; - if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) - { - return CELL_ESRCH; - } - - auto mutex = lwcond->lwmutex; - u32 tid_le = CPU.GetId(); - auto tid = be_t::make(tid_le); - - std::shared_ptr sq; - if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq)) - { - sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)", - (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); - return CELL_ESRCH; - } - - if (mutex->owner.read_sync() != tid) - { - return CELL_EPERM; - } - - lw->queue.push(tid_le, mutex->attribute); - - auto old_recursive = mutex->recursive_count; - mutex->recursive_count = 0; - - auto target = be_t::make(sq->signal(mutex->attribute)); - if (!mutex->owner.compare_and_swap_test(tid, target)) - { - assert(!"sys_lwcond_wait(): mutex unlocking failed"); - } - - bool signaled = false; - while (true) - { - if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads - { - s32 res = sys_lwmutex_lock(CPU, mutex, timeout ? get_system_time() - start_time : 0); // this is bad - if (res == CELL_OK) - { - break; - } - - switch (res) - { - case static_cast(CELL_EDEADLK): - { - sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue); - return CELL_OK; // mutex not locked (but already locked in the incorrect way) - } - case static_cast(CELL_ESRCH): - { - sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); - return CELL_ESRCH; // mutex not locked - } - case static_cast(CELL_ETIMEDOUT): - { - return CELL_ETIMEDOUT; // mutex not locked - } - case static_cast(CELL_EINVAL): - { - sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); - return CELL_EINVAL; // mutex not locked - } - default: - { - sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res); - return CELL_EINVAL; // mutex not locked - } - } - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - - if (timeout && get_system_time() - start_time > timeout) - { - if (!lw->queue.invalidate(tid_le, mutex->attribute)) - { - assert(!"sys_lwcond_wait() failed (timeout)"); - } - return CELL_ETIMEDOUT; // mutex not locked - } - - if (Emu.IsStopped()) - { - sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); - return CELL_OK; - } - } - - mutex->recursive_count = old_recursive; - return CELL_OK; -} diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 1c519bca42..8b1a834ce8 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -14,31 +14,31 @@ struct sys_lwcond_attribute_t struct sys_lwcond_t { vm::bptr lwmutex; - be_t lwcond_queue; + be_t lwcond_queue; // lwcond pseudo-id }; -struct Lwcond +struct lwcond_t { - sleep_queue_t queue; + const u64 name; - const u32 addr; + // TODO: use sleep queue + std::condition_variable cv; + std::atomic waiters; - Lwcond(u64 name, u32 addr) - : queue(name) - , addr(addr) + lwcond_t(u64 name) + : name(name) { } }; // Aux -s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64); +void lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name); class PPUThread; // SysCalls -s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwcond_destroy(vm::ptr lwcond); -s32 sys_lwcond_signal(vm::ptr lwcond); -s32 sys_lwcond_signal_all(vm::ptr lwcond); -s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id); -s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout); +s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5); +s32 _sys_lwcond_destroy(u32 lwcond_id); +s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode); +s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode); +s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 43dc044e59..f104a0d709 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -85,7 +85,7 @@ s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout) // protocol is ignored in current implementation mutex->waiters++; assert(mutex->waiters > 0); - while (!mutex->signals) + while (!mutex->signaled) { if (timeout && get_system_time() - start_time > timeout) { @@ -102,7 +102,7 @@ s32 _sys_lwmutex_lock(u32 lwmutex_id, u64 timeout) mutex->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } - mutex->signals--; + mutex->signaled--; mutex->waiters--; assert(mutex->waiters >= 0); @@ -121,12 +121,12 @@ s32 _sys_lwmutex_trylock(u32 lwmutex_id) return CELL_ESRCH; } - if (mutex->waiters || !mutex->signals) + if (mutex->waiters || !mutex->signaled) { return CELL_EBUSY; } - mutex->signals--; + mutex->signaled--; return CELL_OK; } @@ -143,7 +143,7 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id) return CELL_ESRCH; } - mutex->signals++; + mutex->signaled++; mutex->cv.notify_one(); return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 4cf3a0ed3a..d64b5348f3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -72,7 +72,7 @@ struct lwmutex_t const u64 name; // this object is not truly a mutex and its syscall names are wrong, it's probabably sleep queue or something - std::atomic signals; + std::atomic signaled; // TODO: use sleep queue, possibly remove condition variable std::condition_variable cv; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index be0e835658..6209e586cc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -110,10 +110,7 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout) return CELL_EKRESOURCE; } - if (!mutex->recursive_count++) - { - throw __FUNCTION__; - } + mutex->recursive_count++; return CELL_OK; } @@ -142,7 +139,6 @@ s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout) } mutex->owner = thread; - mutex->recursive_count = 1; mutex->waiters--; assert(mutex->waiters >= 0); return CELL_OK; @@ -172,10 +168,7 @@ s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id) return CELL_EKRESOURCE; } - if (!mutex->recursive_count++) - { - throw __FUNCTION__; - } + mutex->recursive_count++; return CELL_OK; } @@ -189,7 +182,6 @@ s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id) } mutex->owner = thread; - mutex->recursive_count = 1; return CELL_OK; } @@ -214,12 +206,16 @@ s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id) return CELL_EPERM; } - if (!mutex->recursive_count || (!mutex->recursive && mutex->recursive_count != 1)) + if (mutex->recursive_count) { - throw __FUNCTION__; + if (!mutex->recursive) + { + throw __FUNCTION__; + } + + mutex->recursive_count--; } - - if (!--mutex->recursive_count) + else { mutex->owner.reset(); mutex->cv.notify_one(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index 29c2dfbb00..282d985b68 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -198,11 +198,13 @@ s32 sys_ppu_thread_create(vm::ptr thread_id, u32 entry, u64 arg, s32 prio, return CELL_OK; } +std::mutex g_once_mutex; + void sys_ppu_thread_once(PPUThread& CPU, vm::ptr> once_ctrl, vm::ptr init) { - sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, init_addr=0x%x)", once_ctrl.addr(), init.addr()); + sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init); - LV2_LOCK; + std::lock_guard lock(g_once_mutex); if (once_ctrl->compare_and_swap_test(be_t::make(SYS_PPU_THREAD_ONCE_INIT), be_t::make(SYS_PPU_THREAD_DONE_INIT))) { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h index 4ad043fccc..5894d5d9c3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.h @@ -8,17 +8,13 @@ enum : u32 SYS_PPU_THREAD_DONE_INIT = 1, }; -enum ppu_thread_flags : u64 +// PPU Thread Flags +enum : u64 { SYS_PPU_THREAD_CREATE_JOINABLE = 0x1, SYS_PPU_THREAD_CREATE_INTERRUPT = 0x2, }; -enum stackSize -{ - SYS_PPU_THREAD_STACK_MIN = 0x4000, -}; - // Aux u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, bool is_joinable, bool is_interrupt, std::string name, std::function task = nullptr); From befc0f62b828e1dc2343648ee80e329eb4a8247c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2015 17:42:08 +0300 Subject: [PATCH 07/18] Lv2 lwcond "true" syscalls --- rpcs3/Emu/CPU/CPUThreadManager.cpp | 2 +- rpcs3/Emu/IdManager.h | 32 ++-- rpcs3/Emu/SysCalls/Modules/cellAdec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellDmux.cpp | 4 +- rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellVdec.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/cellVpost.cpp | 2 +- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 11 +- rpcs3/Emu/SysCalls/lv2/cellFs.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_cond.cpp | 21 ++- rpcs3/Emu/SysCalls/lv2/sys_cond.h | 3 +- rpcs3/Emu/SysCalls/lv2/sys_event.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 164 +++++++++++++++++-- rpcs3/Emu/SysCalls/lv2/sys_lwcond.h | 3 + rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_memory.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_prx.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_spu.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_timer.cpp | 2 +- rpcs3/Emu/SysCalls/lv2/sys_timer.h | 1 + 27 files changed, 212 insertions(+), 71 deletions(-) diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index 575899f5ff..027384f878 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -106,7 +106,7 @@ void CPUThreadManager::RemoveThread(u32 id) } // Removing the ID should trigger the actual deletion of the thread - Emu.GetIdManager().RemoveID(id); + Emu.GetIdManager().RemoveID(id); Emu.CheckStatus(); } diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index f7bfe28db9..da2bc62b2c 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -2,8 +2,6 @@ #define ID_MANAGER_INCLUDED -#define rID_ANY -1 // was wxID_ANY - enum IDType { // Special objects @@ -133,11 +131,13 @@ public: Clear(); } - bool CheckID(const u32 id) + template bool CheckID(const u32 id) { std::lock_guard lock(m_mtx_main); - return m_id_map.find(id) != m_id_map.end(); + auto f = m_id_map.find(id); + + return f != m_id_map.end() && f->second.GetInfo() == typeid(T); } void Clear() @@ -148,12 +148,7 @@ public: m_cur_id = s_first_id; } - template - u32 GetNewID(std::shared_ptr& data = nullptr, const IDType type = TYPE_OTHER) + template u32 GetNewID(std::shared_ptr& data, const IDType type = TYPE_OTHER) { std::lock_guard lock(m_mtx_main); @@ -172,12 +167,12 @@ public: return m_id_map[id]; } - template - bool GetIDData(const u32 id, std::shared_ptr& result) + template bool GetIDData(const u32 id, std::shared_ptr& result) { std::lock_guard lock(m_mtx_main); auto f = m_id_map.find(id); + if (f == m_id_map.end() || f->second.GetInfo() != typeid(T)) { return false; } @@ -189,23 +184,18 @@ public: bool HasID(const u32 id) { - { - std::lock_guard lock(m_mtx_main); + std::lock_guard lock(m_mtx_main); - if(id == rID_ANY) { - return m_id_map.begin() != m_id_map.end(); - } - } - return CheckID(id); + return m_id_map.find(id) != m_id_map.end(); } - bool RemoveID(const u32 id) + template bool RemoveID(const u32 id) { std::lock_guard lock(m_mtx_main); auto item = m_id_map.find(id); - if (item == m_id_map.end()) { + if (item == m_id_map.end() || item->second.GetInfo() != typeid(T)) { return false; } if (item->second.GetType() < TYPE_OTHER) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index f2c2216316..7c3b60c706 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -571,7 +571,7 @@ int cellAdecClose(u32 handle) } if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId()); - Emu.GetIdManager().RemoveID(handle); + Emu.GetIdManager().RemoveID(handle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index dcf6008181..b949c5534e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -710,7 +710,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) } } es.dmux = nullptr; - Emu.GetIdManager().RemoveID(task.es.es); + Emu.GetIdManager().RemoveID(task.es.es); break; } @@ -880,7 +880,7 @@ int cellDmuxClose(u32 demuxerHandle) } if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId()); - Emu.GetIdManager().RemoveID(demuxerHandle); + Emu.GetIdManager().RemoveID(demuxerHandle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp index 6f26cea6c3..cbcb8f397f 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp @@ -266,7 +266,7 @@ int cellGifDecClose(u32 mainHandle, u32 subHandle) return CELL_GIFDEC_ERROR_FATAL; cellFsClose(subHandle_data->fd); - Emu.GetIdManager().RemoveID(subHandle); + Emu.GetIdManager().RemoveID(subHandle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp index a88cbd8921..322b763d9d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp @@ -75,7 +75,7 @@ int cellJpgDecClose(u32 mainHandle, u32 subHandle) return CELL_JPGDEC_ERROR_FATAL; cellFsClose(subHandle_data->fd); - Emu.GetIdManager().RemoveID(subHandle); + Emu.GetIdManager().RemoveID(subHandle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 712eb75e50..7b289e13b0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -615,7 +615,7 @@ int cellVdecClose(u32 handle) } if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId()); - Emu.GetIdManager().RemoveID(handle); + Emu.GetIdManager().RemoveID(handle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp index b2a1adc3b4..910b1c731e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp @@ -67,7 +67,7 @@ int cellVpostClose(u32 handle) return CELL_VPOST_ERROR_C_ARG_HDL_INVALID; } - Emu.GetIdManager().RemoveID(handle); + Emu.GetIdManager().RemoveID(handle); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 517904ae66..842e872044 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -352,9 +352,9 @@ s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmut { sysPrxForUser.Warning("sys_lwcond_create(lwcond=*0x%x, lwmutex=*0x%x, attr=*0x%x)", lwcond, lwmutex, attr); - std::shared_ptr lwc(new lwcond_t(attr->name_u64)); + std::shared_ptr cond(new lwcond_t(attr->name_u64)); - lwcond->lwcond_queue = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); + lwcond->lwcond_queue = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND); lwcond->lwmutex = lwmutex; return CELL_OK; @@ -368,7 +368,7 @@ s32 sys_lwcond_destroy(vm::ptr lwcond) if (res == CELL_OK) { - lwcond->lwcond_queue = lwmutex::dead; + lwcond->lwcond_queue = lwmutex_dead; } return res; @@ -383,6 +383,7 @@ s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr lwcond) if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) { // TODO (protocol ignored) + //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2); } if (lwmutex->owner.read_relaxed() == CPU.GetId()) @@ -440,6 +441,7 @@ s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr lwcond) if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) { // TODO (protocol ignored) + //return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2); } if (lwmutex->owner.read_relaxed() == CPU.GetId()) @@ -496,6 +498,7 @@ s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr lwcond, u32 ppu_t if ((lwmutex->attribute.data() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) == se32(SYS_SYNC_RETRY)) { // TODO (protocol ignored) + //return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2); } if (lwmutex->owner.read_relaxed() == CPU.GetId()) @@ -613,7 +616,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) return CELL_ETIMEDOUT; } - sysPrxForUser.Fatal("sys_lwconde_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res); + sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected syscall result (0x%x)", lwcond, res); return res; } diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index b232a54048..1be4e220bb 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -165,7 +165,7 @@ s32 cellFsClose(u32 fd) { sys_fs.Warning("cellFsClose(fd=0x%x)", fd); - if (!Emu.GetIdManager().RemoveID(fd)) + if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; return CELL_OK; @@ -214,7 +214,7 @@ s32 cellFsClosedir(u32 fd) { sys_fs.Warning("cellFsClosedir(fd=0x%x)", fd); - if (!Emu.GetIdManager().RemoveID(fd)) + if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp index 54db3595ab..cc1ebc702f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue.cpp @@ -125,7 +125,7 @@ u32 sleep_queue_t::signal(u32 protocol) if (m_waiting.size()) { res = m_waiting[0]; - if (!Emu.GetIdManager().CheckID(res)) + if (!Emu.GetIdManager().CheckID(res)) { LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_FIFO) failed: invalid thread (%d)", m_name.c_str(), res); Emu.Pause(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index 42a77d75bd..c7dacd681e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -67,7 +67,7 @@ s32 sys_cond_destroy(u32 cond_id) throw __FUNCTION__; } - Emu.GetIdManager().RemoveID(cond_id); + Emu.GetIdManager().RemoveID(cond_id); return CELL_OK; } @@ -130,7 +130,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_ESRCH; } - if (!Emu.GetIdManager().CheckID(thread_id)) + if (!Emu.GetIdManager().CheckID(thread_id)) { return CELL_ESRCH; } @@ -180,10 +180,16 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) while (!cond->mutex->owner.expired() || !cond->signaled) { - if (!cond->signaled && timeout && get_system_time() - start_time > timeout) + const bool is_timedout = timeout && get_system_time() - start_time > timeout; + + // check timeout only if no thread signaled (the flaw of avoiding sleep queue) + if (is_timedout && cond->mutex->owner.expired() && !cond->signaled) { - // TODO: mutex not locked, timeout is possible only when signaled == 0 + // cancel waiting if the mutex is free, restore its owner and recursive value + cond->mutex->owner = thread; + cond->mutex->recursive_count = recursive_value; cond->waiters--; assert(cond->waiters >= 0); + return CELL_ETIMEDOUT; } @@ -194,14 +200,13 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) } // wait on appropriate condition variable - (cond->signaled ? cond->mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1)); + (cond->signaled || is_timedout ? cond->mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1)); } - // reown the mutex and restore recursive value + // reown the mutex and restore its recursive value cond->mutex->owner = thread; cond->mutex->recursive_count = recursive_value; - - cond->signaled--; assert(cond->signaled >= 0); + cond->signaled--; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index 0c445f8155..fdb43631eb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -20,10 +20,11 @@ struct cond_t const u64 name; const std::shared_ptr mutex; // associated mutex + std::atomic signaled; + // TODO: use sleep queue, possibly remove condition variable std::condition_variable cv; std::atomic waiters; - std::atomic signaled; cond_t(std::shared_ptr& mutex, u64 name) : mutex(mutex) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index 4dc1e73951..e94af91c3f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -100,7 +100,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode) } Emu.GetEventManager().UnregisterKey(queue->key); - Emu.GetIdManager().RemoveID(equeue_id); + Emu.GetIdManager().RemoveID(equeue_id); return CELL_OK; } @@ -274,7 +274,7 @@ s32 sys_event_port_destroy(u32 eport_id) return CELL_EISCONN; } - Emu.GetIdManager().RemoveID(eport_id); + Emu.GetIdManager().RemoveID(eport_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp index 194ccdfa1e..718260f28c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -79,7 +79,7 @@ s32 sys_event_flag_destroy(u32 id) return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(id); + Emu.GetIdManager().RemoveID(id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 39bb23bda6..cbd55b4fc3 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -15,18 +15,18 @@ SysCallBase sys_lwcond("sys_lwcond"); void lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name) { - std::shared_ptr lwc(new lwcond_t(name)); + std::shared_ptr cond(new lwcond_t(name)); - lwcond.lwcond_queue = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); + lwcond.lwcond_queue = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND); } s32 _sys_lwcond_create(vm::ptr lwcond_id, u32 lwmutex_id, vm::ptr control, u64 name, u32 arg5) { sys_lwcond.Warning("_sys_lwcond_create(lwcond_id=*0x%x, lwmutex_id=%d, control=*0x%x, name=0x%llx, arg5=0x%x)", lwcond_id, lwmutex_id, control, name, arg5); - std::shared_ptr lwc(new lwcond_t(name)); + std::shared_ptr cond(new lwcond_t(name)); - *lwcond_id = Emu.GetIdManager().GetNewID(lwc, TYPE_LWCOND); + *lwcond_id = Emu.GetIdManager().GetNewID(cond, TYPE_LWCOND); return CELL_OK; } @@ -37,39 +37,177 @@ s32 _sys_lwcond_destroy(u32 lwcond_id) LV2_LOCK; - std::shared_ptr lwc; - if (!Emu.GetIdManager().GetIDData(lwcond_id, lwc)) + std::shared_ptr cond; + if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) { return CELL_ESRCH; } - if (lwc->waiters) + if (cond->waiters) { return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(lwcond_id); + Emu.GetIdManager().RemoveID(lwcond_id); return CELL_OK; } s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode) { - sys_lwcond.Fatal("_sys_lwcond_signal(lwcond_id=%d, lwmutex_id=%d, ppu_thread_id=%d, mode=%d)", lwcond_id, lwmutex_id, ppu_thread_id, mode); + sys_lwcond.Log("_sys_lwcond_signal(lwcond_id=%d, lwmutex_id=%d, ppu_thread_id=%d, mode=%d)", lwcond_id, lwmutex_id, ppu_thread_id, mode); + + LV2_LOCK; + + std::shared_ptr cond; + if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) + { + return CELL_ESRCH; + } + + // lwmutex_id, ppu_thread_id are ignored in current implementation + + if (mode != 1 && mode != 2 && mode != 3) + { + sys_lwcond.Error("_sys_lwcond_signal(%d): invalid mode (%d)", lwcond_id, mode); + } + + if (~ppu_thread_id) + { + sys_lwcond.Todo("_sys_lwcond_signal(%d): ppu_thread_id (%d)", lwcond_id, ppu_thread_id); + } + + if (mode == 1) + { + // mode 1: lightweight mutex was initially owned by the calling thread + + if (!cond->waiters) + { + return CELL_EPERM; + } + + cond->signaled1++; + } + else if (mode == 2) + { + // mode 2: lightweight mutex was not owned by the calling thread and waiter hasn't been increased + + if (!cond->waiters) + { + return CELL_OK; + } + + cond->signaled2++; + } + else + { + // in mode 3, lightweight mutex was forcefully owned by the calling thread + + if (!cond->waiters) + { + return ~ppu_thread_id ? CELL_ENOENT : CELL_EPERM; + } + + cond->signaled1++; + } + + cond->waiters--; + cond->cv.notify_one(); return CELL_OK; } s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode) { - sys_lwcond.Fatal("_sys_lwcond_signal_all(lwcond_id=%d, lwmutex_id=%d, mode=%d)", lwcond_id, lwmutex_id, mode); + sys_lwcond.Log("_sys_lwcond_signal_all(lwcond_id=%d, lwmutex_id=%d, mode=%d)", lwcond_id, lwmutex_id, mode); - return CELL_OK; + LV2_LOCK; + + std::shared_ptr cond; + if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) + { + return CELL_ESRCH; + } + + // lwmutex_id is ignored in current implementation + + if (mode != 1 && mode != 2) + { + sys_lwcond.Error("_sys_lwcond_signal_all(%d): invalid mode (%d)", lwcond_id, mode); + } + + const s32 count = cond->waiters.exchange(0); + cond->cv.notify_all(); + + if (mode == 1) + { + // in mode 1, lightweight mutex was initially owned by the calling thread + + cond->signaled1 += count; + + return count; + } + else + { + // in mode 2, lightweight mutex was not owned by the calling thread and waiter hasn't been increased + + cond->signaled2 += count; + + return CELL_OK; + } } s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) { - sys_lwcond.Fatal("_sys_lwcond_queue_wait(lwcond_id=%d, lwmutex_id=%d, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout); + sys_lwcond.Log("_sys_lwcond_queue_wait(lwcond_id=%d, lwmutex_id=%d, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout); - return CELL_OK; + const u64 start_time = get_system_time(); + + LV2_LOCK; + + std::shared_ptr cond; + if (!Emu.GetIdManager().GetIDData(lwcond_id, cond)) + { + return CELL_ESRCH; + } + + // lwmutex_id, protocol are ignored in current implementation + cond->waiters++; assert(cond->waiters > 0); + + while (!cond->signaled1 && !cond->signaled2) + { + const bool is_timedout = timeout && get_system_time() - start_time > timeout; + + // check timeout (TODO) + if (is_timedout) + { + sys_lwcond.Fatal("_sys_lwcond_queue_wait(%d): TIMED OUT", lwcond_id); + + // cancel waiting + cond->waiters--; assert(cond->waiters >= 0); + + return CELL_ETIMEDOUT; + } + + if (Emu.IsStopped()) + { + sys_lwcond.Warning("_sys_lwcond_queue_wait(lwcond_id=%d) aborted", lwcond_id); + return CELL_OK; + } + + cond->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); + } + + if (cond->signaled1) + { + cond->signaled1--; + + return CELL_OK; + } + else + { + cond->signaled2--; + + return CELL_EBUSY; + } } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 8b1a834ce8..0f625300f8 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -21,6 +21,9 @@ struct lwcond_t { const u64 name; + std::atomic signaled1; // mode 1 signals + std::atomic signaled2; // mode 2 signals + // TODO: use sleep queue std::condition_variable cv; std::atomic waiters; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index f104a0d709..8786b3836a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -63,7 +63,7 @@ s32 _sys_lwmutex_destroy(u32 lwmutex_id) return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(lwmutex_id); + Emu.GetIdManager().RemoveID(lwmutex_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp index dcacc54f54..3022274177 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp @@ -141,7 +141,7 @@ s32 sys_memory_container_destroy(u32 cid) // Release the allocated memory and remove the ID. Memory.Free(ct->addr); - Emu.GetIdManager().RemoveID(cid); + Emu.GetIdManager().RemoveID(cid); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp index 24ac1b8bfd..bc5a78c60b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp @@ -78,7 +78,7 @@ s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr mem_id) // Generate a new mem ID. std::shared_ptr info(new mmapper_info(size, flags)); - *mem_id = Emu.GetIdManager().GetNewID(info); + *mem_id = Emu.GetIdManager().GetNewID(info, TYPE_MEM); return CELL_OK; } @@ -147,7 +147,7 @@ s32 sys_mmapper_free_memory(u32 mem_id) return CELL_ESRCH; // Release the allocated memory and remove the ID. - Emu.GetIdManager().RemoveID(mem_id); + Emu.GetIdManager().RemoveID(mem_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index 6209e586cc..4eefd74ca0 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -79,7 +79,7 @@ s32 sys_mutex_destroy(u32 mutex_id) return CELL_EPERM; } - Emu.GetIdManager().RemoveID(mutex_id); + Emu.GetIdManager().RemoveID(mutex_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp b/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp index 9e868d1c36..a9da2cf0fb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_prx.cpp @@ -101,7 +101,7 @@ s32 sys_prx_unload_module(s32 id, u64 flags, vm::ptraddress); - Emu.GetIdManager().RemoveID(id); + Emu.GetIdManager().RemoveID(id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp index 42fc1ff297..45998a738a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp @@ -60,7 +60,7 @@ s32 sys_rwlock_destroy(u32 rw_lock_id) return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(rw_lock_id); + Emu.GetIdManager().RemoveID(rw_lock_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index 5f2a8d3f3d..a0366516fa 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -72,7 +72,7 @@ s32 sys_semaphore_destroy(u32 sem) return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(sem); + Emu.GetIdManager().RemoveID(sem); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 66d8f1d0aa..f2f98e2338 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -272,7 +272,7 @@ s32 sys_spu_thread_group_destroy(u32 id) } group->state = SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED; // hack - Emu.GetIdManager().RemoveID(id); + Emu.GetIdManager().RemoveID(id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index 8cb4c8f618..7f86c570a9 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -74,7 +74,7 @@ s32 sys_timer_destroy(u32 timer_id) return CELL_EISCONN; } - Emu.GetIdManager().RemoveID(timer_id); + Emu.GetIdManager().RemoveID(timer_id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.h b/rpcs3/Emu/SysCalls/lv2/sys_timer.h index 3057a38a18..95b0c94793 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.h @@ -15,6 +15,7 @@ struct sys_timer_information_t be_t pad; }; +// "timer_t" conflicts with some definition struct lv2_timer_t { std::weak_ptr port; // event queue From 11b409907e9af69c60e8cf2855fdcea094558835 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2015 19:27:08 +0300 Subject: [PATCH 08/18] atomic_t specializations fixed --- rpcs3/Emu/Memory/atomic.h | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/rpcs3/Emu/Memory/atomic.h b/rpcs3/Emu/Memory/atomic.h index d9dd6e96db..b4436c3de9 100644 --- a/rpcs3/Emu/Memory/atomic.h +++ b/rpcs3/Emu/Memory/atomic.h @@ -197,11 +197,11 @@ public: } }; -__forceinline static u64 operator ++(_atomic_base>& left, int) +template inline static typename std::enable_if::value, T>::type operator ++(_atomic_base>& left, int) { - u64 result; + T result; - left.atomic_op([&result](be_t& value) + left.atomic_op([&result](be_t& value) { result = value++; }); @@ -209,7 +209,7 @@ __forceinline static u64 operator ++(_atomic_base>& left, int) return result; } -__forceinline static u64 operator --(_atomic_base>& left, int) +template inline static typename std::enable_if::value, T>::type operator --(_atomic_base>& left, int) { u64 result; @@ -221,11 +221,11 @@ __forceinline static u64 operator --(_atomic_base>& left, int) return result; } -__forceinline static u64 operator +=(_atomic_base>& left, u64 right) +template inline static typename std::enable_if::value, T>::type operator +=(_atomic_base>& left, T2 right) { - u64 result; + T result; - left.atomic_op([&result, right](be_t& value) + left.atomic_op([&result, right](be_t& value) { result = (value += right); }); @@ -233,6 +233,18 @@ __forceinline static u64 operator +=(_atomic_base>& left, u64 right) return result; } +template inline static typename std::enable_if::value, T>::type operator -=(_atomic_base>& left, T2 right) +{ + T result; + + left.atomic_op([&result, right](be_t& value) + { + result = (value -= right); + }); + + return result; +} + template using atomic_le_t = _atomic_base; template using atomic_be_t = _atomic_base::type>; From a62eeaaecc7f5ffbe13c208fd6b8aaf525ed50c7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Tue, 10 Mar 2015 22:16:31 +0300 Subject: [PATCH 09/18] Bugfix --- rpcs3/Emu/Memory/atomic.h | 4 +-- rpcs3/Emu/SysCalls/Modules/cellSync.cpp | 37 ++++++++++--------------- rpcs3/Emu/SysCalls/Modules/cellSync.h | 16 +++++++---- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/rpcs3/Emu/Memory/atomic.h b/rpcs3/Emu/Memory/atomic.h index b4436c3de9..e6f9995ec6 100644 --- a/rpcs3/Emu/Memory/atomic.h +++ b/rpcs3/Emu/Memory/atomic.h @@ -211,9 +211,9 @@ template inline static typename std::enable_if template inline static typename std::enable_if::value, T>::type operator --(_atomic_base>& left, int) { - u64 result; + T result; - left.atomic_op([&result](be_t& value) + left.atomic_op([&result](be_t& value) { result = value--; }); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index 23cef8ccf4..618653b7d9 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -25,13 +25,13 @@ s32 syncMutexInitialize(vm::ptr mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } + if (mutex.addr() % 4) { return CELL_SYNC_ERROR_ALIGN; } - // prx: set zero and sync - mutex->data.exchange({}); + mutex->sync_var.exchange({}); return CELL_OK; } @@ -51,26 +51,22 @@ s32 cellSyncMutexLock(vm::ptr mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } + if (mutex.addr() % 4) { return CELL_SYNC_ERROR_ALIGN; } - // prx: increase m_acq and remember its old value - be_t order; - mutex->data.atomic_op([&order](CellSyncMutex::data_t& mutex) - { - order = mutex.m_acq++; - }); + // prx: increase acquire_count and remember its old value + const be_t order = be_t::make(mutex->acquire_count++); - // prx: wait until this old value is equal to m_rel + // prx: wait until release_count is equal to old acquire_count g_sync_mutex_wm.wait_op(mutex.addr(), [mutex, order]() { - return order == mutex->data.read_relaxed().m_rel; + return order == mutex->release_count.read_relaxed(); }); - // prx: sync - mutex->data.read_sync(); + mutex->sync_var.read_sync(); return CELL_OK; } @@ -83,19 +79,16 @@ s32 cellSyncMutexTryLock(vm::ptr mutex) { return CELL_SYNC_ERROR_NULL_POINTER; } + if (mutex.addr() % 4) { return CELL_SYNC_ERROR_ALIGN; } - // prx: exit if m_acq and m_rel are not equal, increase m_acq - return mutex->data.atomic_op(CELL_OK, [](CellSyncMutex::data_t& mutex) -> s32 + // prx: lock only if acquire_count and release_count are equal + return mutex->sync_var.atomic_op(CELL_OK, [](CellSyncMutex::sync_t& mutex) -> s32 { - if (mutex.m_acq++ != mutex.m_rel) - { - return CELL_SYNC_ERROR_BUSY; - } - return CELL_OK; + return (mutex.acquire_count++ != mutex.release_count) ? CELL_SYNC_ERROR_BUSY : CELL_OK; }); } @@ -112,10 +105,8 @@ s32 cellSyncMutexUnlock(vm::ptr mutex) return CELL_SYNC_ERROR_ALIGN; } - mutex->data.atomic_op_sync([](CellSyncMutex::data_t& mutex) - { - mutex.m_rel++; - }); + // prx: increase release count + mutex->release_count++; g_sync_mutex_wm.notify(mutex.addr()); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.h b/rpcs3/Emu/SysCalls/Modules/cellSync.h index ba7ab97781..0fb5912579 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.h @@ -29,15 +29,21 @@ enum CELL_SYNC_ERROR_NO_SPU_CONTEXT_STORAGE = 0x80410114, // ??? }; -struct CellSyncMutex +union CellSyncMutex { - struct data_t + struct sync_t { - be_t m_rel; // release order (increased when mutex is unlocked) - be_t m_acq; // acquire order (increased when mutex is locked) + be_t release_count; // increased when mutex is unlocked + be_t acquire_count; // increased when mutex is locked }; - atomic_t data; + struct + { + atomic_t release_count; + atomic_t acquire_count; + }; + + atomic_t sync_var; }; static_assert(sizeof(CellSyncMutex) == 4, "CellSyncMutex: wrong size"); From fe4ab0abbb095b03bda957b65dea087a7dc66df4 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 00:47:13 +0300 Subject: [PATCH 10/18] Bugfix --- rpcs3/Emu/SysCalls/lv2/cellFs.cpp | 5 ---- rpcs3/Emu/SysCalls/lv2/sys_cond.cpp | 1 + rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 42 ++++++++++++++++++++++----- rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h | 2 +- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 1be4e220bb..8a332d3674 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -131,9 +131,6 @@ s32 cellFsRead(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr> nread) if (!Emu.GetIdManager().GetIDData(fd, file)) return CELL_ESRCH; - if (nbytes != (u32)nbytes) - return CELL_ENOMEM; - // TODO: checks const u64 res = nbytes ? file->Read(buf.get_ptr(), nbytes) : 0; @@ -150,8 +147,6 @@ s32 cellFsWrite(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nwrite std::shared_ptr file; if (!Emu.GetIdManager().GetIDData(fd, file)) return CELL_ESRCH; - if (nbytes != (u32)nbytes) return CELL_ENOMEM; - // TODO: checks const u64 res = nbytes ? file->Write(buf.get_ptr(), nbytes) : 0; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index c7dacd681e..31eb558f9f 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -174,6 +174,7 @@ s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) // unlock mutex cond->mutex->owner.reset(); + cond->mutex->cv.notify_one(); // save recursive value const u32 recursive_value = cond->mutex->recursive_count.exchange(0); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index cbd55b4fc3..4297628b77 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -65,7 +65,13 @@ s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mod return CELL_ESRCH; } - // lwmutex_id, ppu_thread_id are ignored in current implementation + std::shared_ptr mutex; + if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + // ppu_thread_id is ignored in current implementation if (mode != 1 && mode != 2 && mode != 3) { @@ -129,7 +135,11 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode) return CELL_ESRCH; } - // lwmutex_id is ignored in current implementation + std::shared_ptr mutex; + if (lwmutex_id && !Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } if (mode != 1 && mode != 2) { @@ -171,22 +181,39 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) return CELL_ESRCH; } - // lwmutex_id, protocol are ignored in current implementation + std::shared_ptr mutex; + if (!Emu.GetIdManager().GetIDData(lwmutex_id, mutex)) + { + return CELL_ESRCH; + } + + // finalize unlocking the mutex + mutex->signaled++; + mutex->cv.notify_one(); + + // protocol is ignored in current implementation cond->waiters++; assert(cond->waiters > 0); - while (!cond->signaled1 && !cond->signaled2) + while (!(cond->signaled1 && mutex->signaled) && !cond->signaled2) { const bool is_timedout = timeout && get_system_time() - start_time > timeout; // check timeout (TODO) if (is_timedout) { - sys_lwcond.Fatal("_sys_lwcond_queue_wait(%d): TIMED OUT", lwcond_id); - // cancel waiting cond->waiters--; assert(cond->waiters >= 0); - return CELL_ETIMEDOUT; + if (mutex->signaled) + { + mutex->signaled--; + + return CELL_EDEADLK; + } + else + { + return CELL_ETIMEDOUT; + } } if (Emu.IsStopped()) @@ -200,6 +227,7 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) if (cond->signaled1) { + mutex->signaled--; cond->signaled1--; return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index d64b5348f3..0b1471bc3c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -82,7 +82,7 @@ struct lwmutex_t : protocol(protocol) , name(name) { - } + } }; // Aux From 116638f3521d4c8e451b804db2b5f81e2c92eeb5 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 01:48:17 +0300 Subject: [PATCH 11/18] Bugfix --- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 842e872044..71cacad9b1 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -311,7 +311,7 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) const be_t tid = be_t::make(CPU.GetId()); // check owner - if (lwmutex->owner.read_relaxed() != tid) + if (lwmutex->owner.read_sync() != tid) { return CELL_EPERM; } From 0a4820f4f8680bb41a1654ba8dca25bc99f31100 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 12:43:36 +0300 Subject: [PATCH 12/18] Some diagnostic message --- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 71cacad9b1..cc53f86f55 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -212,6 +212,11 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout // atomically increment waiter value using 64 bit op lwmutex->all_info++; + if (!lwmutex->waiter.read_relaxed().data()) + { + sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): unexpected waiter", lwmutex); + } + if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) { // locking succeeded @@ -228,7 +233,12 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout if (res == CELL_OK) { // locking succeeded - lwmutex->owner.exchange(tid); + auto old = lwmutex->owner.exchange(tid); + + if (old.data() != se32(lwmutex_reserved)) + { + sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): unexpected owner (0x%x)", lwmutex, old); + } return CELL_OK; } @@ -294,7 +304,12 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) if (res == CELL_OK) { // locking succeeded - lwmutex->owner.exchange(tid); + auto old = lwmutex->owner.exchange(tid); + + if (old.data() != se32(lwmutex_reserved)) + { + sysPrxForUser.Fatal("sys_lwmutex_trylock(lwmutex=*0x%x): unexpected owner (0x%x)", lwmutex, old); + } } return res; From a19a13136c57096cf24555da59f7f41bdf76ad51 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 13:39:54 +0300 Subject: [PATCH 13/18] Bugfix --- rpcs3/Emu/SysCalls/lv2/sys_cond.h | 2 +- rpcs3/Emu/SysCalls/lv2/sys_event_flag.h | 4 ++-- rpcs3/Emu/SysCalls/lv2/sys_lwcond.h | 3 +++ rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp | 5 +++++ rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index fdb43631eb..eb9f3b5d40 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -29,8 +29,8 @@ struct cond_t cond_t(std::shared_ptr& mutex, u64 name) : mutex(mutex) , name(name) - , waiters(0) , signaled(0) + , waiters(0) { } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h index ee63ce8369..a470d6e496 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -29,12 +29,12 @@ struct sys_event_flag_attr struct event_flag_t { - std::atomic flags; - const u32 protocol; const s32 type; const u64 name; + std::atomic flags; + // TODO: use sleep queue, possibly remove condition variable std::condition_variable cv; std::atomic waiters; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 0f625300f8..8236cc2fe6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -30,6 +30,9 @@ struct lwcond_t lwcond_t(u64 name) : name(name) + , signaled1(0) + , signaled2(0) + , waiters(0) { } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 8786b3836a..96d87ab0b4 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -143,6 +143,11 @@ s32 _sys_lwmutex_unlock(u32 lwmutex_id) return CELL_ESRCH; } + if (mutex->signaled) + { + sys_lwmutex.Fatal("_sys_lwmutex_unlock(lwmutex_id=%d): already signaled", lwmutex_id); + } + mutex->signaled++; mutex->cv.notify_one(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 0b1471bc3c..f29e2866d6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -81,6 +81,8 @@ struct lwmutex_t lwmutex_t(u32 protocol, u64 name) : protocol(protocol) , name(name) + , signaled(0) + , waiters(0) { } }; From 03219a9a4e9ee99aecf6a55f15de90c443cd3ed7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 13:41:20 +0300 Subject: [PATCH 14/18] Fix --- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index cc53f86f55..50234b1407 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -326,7 +326,7 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) const be_t tid = be_t::make(CPU.GetId()); // check owner - if (lwmutex->owner.read_sync() != tid) + if (lwmutex->owner.read_relaxed() != tid) { return CELL_EPERM; } From 6e3e2cf0f3f888bafc4c66ac2c8e7076ebc61563 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 14:12:20 +0300 Subject: [PATCH 15/18] Fix --- rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp | 30 +++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 50234b1407..9274ccbdad 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -212,11 +212,6 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout // atomically increment waiter value using 64 bit op lwmutex->all_info++; - if (!lwmutex->waiter.read_relaxed().data()) - { - sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): unexpected waiter", lwmutex); - } - if (lwmutex->owner.compare_and_swap_test(lwmutex::free, tid)) { // locking succeeded @@ -237,7 +232,7 @@ s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout if (old.data() != se32(lwmutex_reserved)) { - sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): unexpected owner (0x%x)", lwmutex, old); + sysPrxForUser.Fatal("sys_lwmutex_lock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old); } return CELL_OK; @@ -308,7 +303,7 @@ s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) if (old.data() != se32(lwmutex_reserved)) { - sysPrxForUser.Fatal("sys_lwmutex_trylock(lwmutex=*0x%x): unexpected owner (0x%x)", lwmutex, old); + sysPrxForUser.Fatal("sys_lwmutex_trylock(lwmutex=*0x%x): locking failed (owner=0x%x)", lwmutex, old); } } @@ -594,9 +589,14 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) } // restore owner and recursive value - lwmutex->owner.exchange(tid); + const auto old = lwmutex->owner.exchange(tid); lwmutex->recursive_count = recursive_value; + if (old.data() != se32(lwmutex_reserved)) + { + sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed (lwmutex->owner=0x%x)", lwcond, old); + } + return res; } @@ -617,17 +617,15 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) if (res == CELL_EDEADLK) { - const auto owner = lwmutex->owner.read_relaxed(); - - if (owner.data() != se32(lwmutex_reserved)) - { - sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): unexpected lwmutex->owner (0x%x)", lwcond, owner); - } - // restore owner and recursive value - lwmutex->owner.exchange(tid); + const auto old = lwmutex->owner.exchange(tid); lwmutex->recursive_count = recursive_value; + if (old.data() != se32(lwmutex_reserved)) + { + sysPrxForUser.Fatal("sys_lwcond_wait(lwcond=*0x%x): locking failed after timeout (lwmutex->owner=0x%x)", lwcond, old); + } + return CELL_ETIMEDOUT; } From 629206c0dc7d93f11ab6ce45c523268af4ba260c Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 14:27:29 +0300 Subject: [PATCH 16/18] Bugfix --- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 4297628b77..77f98c2bbc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -225,7 +225,7 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) cond->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } - if (cond->signaled1) + if (cond->signaled1 && mutex->signaled) { mutex->signaled--; cond->signaled1--; From 6de3a6090ad1e4bd13c2dd8f8d6a7312391cc9a6 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 14:35:23 +0300 Subject: [PATCH 17/18] Bugfix --- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 77f98c2bbc..197289b37e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -222,7 +222,7 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) return CELL_OK; } - cond->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); + (cond->signaled1 ? mutex->cv : cond->cv).wait_for(lv2_lock, std::chrono::milliseconds(1)); } if (cond->signaled1 && mutex->signaled) From daad7d71f9aec066ec5df89ffa69a73bf09a05ba Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Wed, 11 Mar 2015 14:45:58 +0300 Subject: [PATCH 18/18] Bugfix --- rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 197289b37e..9cb791bfb7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -198,8 +198,8 @@ s32 _sys_lwcond_queue_wait(u32 lwcond_id, u32 lwmutex_id, u64 timeout) { const bool is_timedout = timeout && get_system_time() - start_time > timeout; - // check timeout (TODO) - if (is_timedout) + // check timeout only if no thread signaled in mode 1 (the flaw of avoiding sleep queue) + if (is_timedout && !cond->signaled1) { // cancel waiting cond->waiters--; assert(cond->waiters >= 0);