error_code sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex) { sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); if (g_cfg.core.hle_lwmutex) { return sys_mutex_unlock(ppu, lwmutex->sleep_queue); } const be_t<u32> tid(ppu.id); // check owner if (lwmutex->vars.owner.load() != tid) { return CELL_EPERM; } if (lwmutex->recursive_count) { // recursive unlocking succeeded lwmutex->recursive_count--; return CELL_OK; } // ensure that waiter is zero if (lwmutex->lock_var.compare_and_swap_test({ tid, 0 }, { lwmutex_free, 0 })) { // unlocking succeeded return CELL_OK; } if (lwmutex->attribute & SYS_SYNC_RETRY) { lwmutex->vars.owner.release(lwmutex_free); // Call the alternative syscall if (_sys_lwmutex_unlock2(lwmutex->sleep_queue) == CELL_ESRCH) { return CELL_ESRCH; } return CELL_OK; } // set special value lwmutex->vars.owner.release(lwmutex_reserved); // call the syscall if (_sys_lwmutex_unlock(ppu, lwmutex->sleep_queue) == CELL_ESRCH) { return CELL_ESRCH; } return CELL_OK; }
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex) { sysPrxForUser.Log("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex); const be_t<u32> tid = be_t<u32>::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) } // set special value lwmutex->owner.exchange(lwmutex::reserved); // call the syscall if (_sys_lwmutex_unlock(lwmutex->sleep_queue) == CELL_ESRCH) { return CELL_ESRCH; } return CELL_OK; }