#pragma once #include "sys_sync.h" #include "Emu/Memory/vm_ptr.h" struct sys_lwmutex_attribute_t { be_t protocol; be_t recursive; union { nse_t name_u64; char name[sizeof(u64)]; }; }; enum : u32 { lwmutex_free = 0xffffffffu, lwmutex_dead = 0xfffffffeu, lwmutex_reserved = 0xfffffffdu, }; struct sys_lwmutex_t { struct alignas(8) sync_var_t { be_t owner; be_t waiter; }; union { atomic_t lock_var; struct { atomic_be_t owner; atomic_be_t waiter; } vars; atomic_be_t all_info; }; be_t attribute; be_t recursive_count; be_t sleep_queue; // lwmutex pseudo-id be_t pad; }; struct lv2_lwmutex final : lv2_obj { static const u32 id_base = 0x95000000; const lv2_protocol protocol; const vm::ptr control; const be_t name; shared_mutex mutex; atomic_t signaled{0}; std::deque sq; atomic_t lwcond_waiters{0}; lv2_lwmutex(u32 protocol, vm::ptr control, u64 name) : protocol{protocol} , control(control) , name(std::bit_cast>(name)) { } // Try to add a waiter bool add_waiter(cpu_thread* cpu) { if (const auto old = lwcond_waiters.fetch_op([](s32& val) { if (val + 0u <= 1u << 31) { // Value was either positive or INT32_MIN return false; } // lwmutex was set to be destroyed, but there are lwcond waiters // Turn off the "destroying" bit as we are adding an lwmutex waiter val &= 0x7fff'ffff; return true; }).first; old != INT32_MIN) { sq.emplace_back(cpu); if (old < 0) { // Notify lwmutex destroyer (may cause EBUSY to be returned for it) lwcond_waiters.notify_all(); } return true; } // Failed - lwmutex was set to be destroyed and all lwcond waiters quit return false; } }; // Aux class ppu_thread; // Syscalls error_code _sys_lwmutex_create(ppu_thread& ppu, vm::ptr lwmutex_id, u32 protocol, vm::ptr control, s32 has_name, u64 name); error_code _sys_lwmutex_destroy(ppu_thread& ppu, u32 lwmutex_id); error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout); error_code _sys_lwmutex_trylock(ppu_thread& ppu, u32 lwmutex_id); error_code _sys_lwmutex_unlock(ppu_thread& ppu, u32 lwmutex_id); error_code _sys_lwmutex_unlock2(ppu_thread& ppu, u32 lwmutex_id);