From 0f233beff91330d1895d454a203307632ede5de4 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Sun, 8 Mar 2015 06:37:07 +0300 Subject: [PATCH] Lv2 Semaphore rewritten --- rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp | 4 +- rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp | 201 +++++++------------ rpcs3/Emu/SysCalls/lv2/sys_semaphore.h | 47 +++-- 3 files changed, 100 insertions(+), 152 deletions(-) diff --git a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp index 32994abd06..a71fa05f55 100644 --- a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp +++ b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp @@ -14,13 +14,13 @@ SemaphoreAttributes SyncPrimManager::GetSemaphoreData(u32 id) { - std::shared_ptr sem; + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(id, sem)) { return{}; } - return{ std::string((const char*)&sem->name, 8), sem->value.read_sync(), sem->max }; + return{ std::string((const char*)&sem->name, 8), sem->value, sem->max }; } LwMutexAttributes SyncPrimManager::GetLwMutexData(u32 id) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index bff274c574..5f2a8d3f3d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -12,181 +12,141 @@ SysCallBase sys_semaphore("sys_semaphore"); -u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64) +u32 semaphore_create(s32 initial_val, s32 max_val, u32 protocol, u64 name_u64) { - std::shared_ptr sem(new Semaphore(initial_count, max_count, protocol, name_u64)); + std::shared_ptr sem(new semaphore_t(protocol, max_val, name_u64, initial_val)); - const u32 id = Emu.GetIdManager().GetNewID(sem, TYPE_SEMAPHORE); - sem->queue.set_full_name(fmt::Format("Semaphore(%d)", id)); - - sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol, id); - return id; + return Emu.GetIdManager().GetNewID(sem, TYPE_SEMAPHORE); } -s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr, s32 initial_count, s32 max_count) +s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr, s32 initial_val, s32 max_val) { - sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)", - sem.addr(), attr.addr(), initial_count, max_count); + sys_semaphore.Warning("sys_semaphore_create(sem=*0x%x, attr=*0x%x, initial_val=%d, max_val=%d)", sem, attr, initial_val, max_val); - if (!sem) + if (!sem || !attr) { - sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr()); return CELL_EFAULT; } - if (!attr) + if (max_val <= 0 || initial_val > max_val || initial_val < 0) { - sys_semaphore.Error("sys_semaphore_create(): An invalid argument value is specified (attr_addr=0x%x)", attr.addr()); - return CELL_EFAULT; - } - - if (max_count <= 0 || initial_count > max_count || initial_count < 0) - { - sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count); + sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_val=%d, max_val=%d)", initial_val, max_val); return CELL_EINVAL; } - switch (attr->protocol.data()) + const u32 protocol = attr->protocol; + + switch (protocol) { - case se32(SYS_SYNC_FIFO): break; - case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_PRIORITY_INHERIT): break; - default: sys_semaphore.Error("Unknown protocol attribute (0x%x)", attr->protocol); return CELL_EINVAL; + case SYS_SYNC_FIFO: break; + case SYS_SYNC_PRIORITY: break; + case SYS_SYNC_PRIORITY_INHERIT: break; + default: sys_semaphore.Error("sys_semaphore_create(): unknown protocol (0x%x)", protocol); return CELL_EINVAL; } - if (attr->pshared.data() != se32(0x200)) + if (attr->pshared.data() != se32(0x200) || attr->ipc_key.data() || attr->flags.data()) { - sys_semaphore.Error("Unknown pshared attribute (0x%x)", attr->pshared); + sys_semaphore.Error("sys_semaphore_create(): unknown attributes (pshared=0x%x, ipc_key=0x%x, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); return CELL_EINVAL; } - *sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64); + *sem = semaphore_create(initial_val, max_val, protocol, attr->name_u64); + return CELL_OK; } -s32 sys_semaphore_destroy(u32 sem_id) +s32 sys_semaphore_destroy(u32 sem) { - sys_semaphore.Warning("sys_semaphore_destroy(sem_id=%d)", sem_id); + sys_semaphore.Warning("sys_semaphore_destroy(sem=%d)", sem); - std::shared_ptr sem; - if (!Emu.GetIdManager().GetIDData(sem_id, sem)) + LV2_LOCK; + + std::shared_ptr semaphore; + if (!Emu.GetIdManager().GetIDData(sem, semaphore)) { return CELL_ESRCH; } - if (sem->queue.count()) // TODO: safely make object unusable + if (semaphore->waiters) { return CELL_EBUSY; } - Emu.GetIdManager().RemoveID(sem_id); + Emu.GetIdManager().RemoveID(sem); + return CELL_OK; } -s32 sys_semaphore_wait(u32 sem_id, u64 timeout) +s32 sys_semaphore_wait(u32 sem, u64 timeout) { - sys_semaphore.Log("sys_semaphore_wait(sem_id=%d, timeout=%lld)", sem_id, timeout); + sys_semaphore.Log("sys_semaphore_wait(sem=%d, timeout=0x%llx)", sem, timeout); const u64 start_time = get_system_time(); - std::shared_ptr sem; - if (!Emu.GetIdManager().GetIDData(sem_id, sem)) + LV2_LOCK; + + std::shared_ptr semaphore; + if (!Emu.GetIdManager().GetIDData(sem, semaphore)) { return CELL_ESRCH; } - const u32 tid = GetCurrentPPUThread().GetId(); - s32 old_value; + // protocol is ignored in current implementation + semaphore->waiters++; assert(semaphore->waiters > 0); + while (semaphore->value <= 0) { - sem->value.atomic_op_sync([&old_value](s32& value) - { - old_value = value; - if (value > 0) - { - value--; - } - }); - - if (old_value > 0) - { - return CELL_OK; - } - - sem->queue.push(tid, sem->protocol); - } - - - while (true) - { - if (sem->queue.pop(tid, sem->protocol)) - { - break; - } - - assert(!sem->value.read_sync()); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (timeout && get_system_time() - start_time > timeout) { - if (!sem->queue.invalidate(tid, sem->protocol)) - { - if (sem->queue.pop(tid, sem->protocol)) - { - return CELL_OK; - } - assert(!"sys_semaphore_wait() failed (timeout)"); - } + semaphore->waiters--; assert(semaphore->waiters >= 0); return CELL_ETIMEDOUT; } if (Emu.IsStopped()) { - sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem_id); + sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem); return CELL_OK; } + + semaphore->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } + semaphore->value--; + semaphore->waiters--; assert(semaphore->waiters >= 0); + return CELL_OK; } -s32 sys_semaphore_trywait(u32 sem_id) +s32 sys_semaphore_trywait(u32 sem) { - sys_semaphore.Log("sys_semaphore_trywait(sem_id=%d)", sem_id); + sys_semaphore.Log("sys_semaphore_trywait(sem=%d)", sem); - std::shared_ptr sem; - if (!Emu.GetIdManager().GetIDData(sem_id, sem)) + LV2_LOCK; + + std::shared_ptr semaphore; + if (!Emu.GetIdManager().GetIDData(sem, semaphore)) { return CELL_ESRCH; } - s32 old_value; - - sem->value.atomic_op_sync([&old_value](s32& value) - { - old_value = value; - if (value > 0) - { - value--; - } - }); - - if (old_value > 0) - { - return CELL_OK; - } - else + if (semaphore->value <= 0 || semaphore->waiters) { return CELL_EBUSY; } + + semaphore->value--; + + return CELL_OK; } -s32 sys_semaphore_post(u32 sem_id, s32 count) +s32 sys_semaphore_post(u32 sem, s32 count) { - sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count); + sys_semaphore.Log("sys_semaphore_post(sem=%d, count=%d)", sem, count); - std::shared_ptr sem; - if (!Emu.GetIdManager().GetIDData(sem_id, sem)) + LV2_LOCK; + + std::shared_ptr semaphore; + if (!Emu.GetIdManager().GetIDData(sem, semaphore)) { return CELL_ESRCH; } @@ -196,52 +156,35 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) return CELL_EINVAL; } - if (count + sem->value.read_sync() - (s32)sem->queue.count() > sem->max) + if (semaphore->value + count > semaphore->max + semaphore->waiters) { return CELL_EBUSY; } - while (count > 0) - { - if (Emu.IsStopped()) - { - sys_semaphore.Warning("sys_semaphore_post(%d) aborted", sem_id); - return CELL_OK; - } - - if (u32 target = sem->queue.signal(sem->protocol)) - { - count--; - } - else - { - sem->value.atomic_op([count](s32& value) - { - value += count; - }); - count = 0; - } - } + semaphore->value += count; assert(semaphore->value >= 0); + semaphore->cv.notify_all(); return CELL_OK; } -s32 sys_semaphore_get_value(u32 sem_id, vm::ptr count) +s32 sys_semaphore_get_value(u32 sem, vm::ptr count) { - sys_semaphore.Log("sys_semaphore_get_value(sem_id=%d, count_addr=0x%x)", sem_id, count.addr()); + sys_semaphore.Log("sys_semaphore_get_value(sem=%d, count=*0x%x)", sem, count); if (!count) { - sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (addr=0x%x)", count.addr()); return CELL_EFAULT; } - std::shared_ptr sem; - if (!Emu.GetIdManager().GetIDData(sem_id, sem)) + LV2_LOCK; + + std::shared_ptr semaphore; + if (!Emu.GetIdManager().GetIDData(sem, semaphore)) { return CELL_ESRCH; } - *count = sem->value.read_sync(); + *count = std::max(0, semaphore->value - semaphore->waiters); + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h index 7c3ac68c4e..674b2d94a8 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h @@ -1,12 +1,13 @@ #pragma once -struct sys_semaphore_attribute +struct sys_semaphore_attribute_t { be_t protocol; - be_t pshared; // undefined - be_t ipc_key; // undefined - be_t flags; // undefined - be_t pad; // not used + be_t pshared; + be_t ipc_key; + be_t flags; + be_t pad; + union { char name[8]; @@ -14,31 +15,35 @@ struct sys_semaphore_attribute }; }; -struct Semaphore +struct semaphore_t { - sleep_queue_t queue; - atomic_le_t value; - - const s32 max; const u32 protocol; + const s32 max; const u64 name; - Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name) - : max(max_count) - , protocol(protocol) + std::atomic value; + + // TODO: use sleep queue, possibly remove condition variable + std::condition_variable cv; + std::atomic waiters; + + semaphore_t(u32 protocol, s32 max, u64 name, s32 value) + : protocol(protocol) + , max(max) , name(name) + , value(value) + , waiters(0) { - value.write_relaxed(initial_count); } }; // Aux -u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64); +u32 semaphore_create(s32 initial_val, s32 max_val, u32 protocol, u64 name_u64); // SysCalls -s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr, s32 initial_count, s32 max_count); -s32 sys_semaphore_destroy(u32 sem_id); -s32 sys_semaphore_wait(u32 sem_id, u64 timeout); -s32 sys_semaphore_trywait(u32 sem_id); -s32 sys_semaphore_post(u32 sem_id, s32 count); -s32 sys_semaphore_get_value(u32 sem_id, vm::ptr count); +s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr, s32 initial_val, s32 max_val); +s32 sys_semaphore_destroy(u32 sem); +s32 sys_semaphore_wait(u32 sem, u64 timeout); +s32 sys_semaphore_trywait(u32 sem); +s32 sys_semaphore_post(u32 sem, s32 count); +s32 sys_semaphore_get_value(u32 sem, vm::ptr count);