diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index ff7627f579..b511033484 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" +#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -12,18 +13,14 @@ namespace vm { using namespace ps3; } logs::channel sys_cond("sys_cond"); +template<> DECLARE(ipc_manager::g_ipc) {}; + extern u64 get_system_time(); error_code sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr) { sys_cond.warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr); - if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags) - { - sys_cond.error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); - return CELL_EINVAL; - } - auto mutex = idm::get(mutex_id); if (!mutex) @@ -31,13 +28,21 @@ error_code sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr(attr->name_u64, std::move(mutex))) + if (auto error = lv2_obj::create(attr->pshared, attr->ipc_key, attr->flags, [&] { - *cond_id = id; - return CELL_OK; + return std::make_shared( + attr->pshared, + attr->flags, + attr->ipc_key, + attr->name_u64, + std::move(mutex)); + })) + { + return error; } - return CELL_EAGAIN; + *cond_id = idm::last_id(); + return CELL_OK; } error_code sys_cond_destroy(u32 cond_id) @@ -51,7 +56,6 @@ error_code sys_cond_destroy(u32 cond_id) return CELL_EBUSY; } - cond.mutex->cond_count--; return {}; }); diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h index 0bb9e8b8c9..76e1bf3468 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -30,15 +30,20 @@ struct lv2_cond final : lv2_obj atomic_t waiters{0}; std::deque sq; - lv2_cond(u64 name, std::shared_ptr mutex) - : shared(0) - , key(0) - , flags(0) + lv2_cond(u32 shared, s32 flags, u64 key, u64 name, std::shared_ptr mutex) + : shared(shared) + , key(key) + , flags(flags) , name(name) , mutex(std::move(mutex)) { this->mutex->cond_count++; } + + ~lv2_cond() + { + this->mutex->cond_count--; + } }; class ppu_thread; diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index b7f4c1ff4b..229d0b4908 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -99,10 +99,12 @@ error_code sys_event_queue_create(vm::ptr equeue_id, vm::ptr(protocol, type, attr->name_u64, event_queue_key, size); + if (event_queue_key == SYS_EVENT_QUEUE_LOCAL) { // Not an IPC queue - if (const u32 _id = idm::make(protocol, type, attr->name_u64, event_queue_key, size)) + if (const u32 _id = idm::import_existing(std::move(queue))) { *equeue_id = _id; return CELL_OK; @@ -111,25 +113,27 @@ error_code sys_event_queue_create(vm::ptr equeue_id, vm::ptr result; - // Create IPC queue - if (!ipc_manager::add(event_queue_key, [&]() -> const std::shared_ptr& + if (!ipc_manager::add(event_queue_key, [&]() -> std::shared_ptr { - result = idm::make_ptr(protocol, type, attr->name_u64, event_queue_key, size); - return result; + if (const u32 _id = idm::import_existing(queue)) + { + *equeue_id = _id; + return std::move(queue); + } + + return nullptr; })) { return CELL_EEXIST; } - if (result) + if (queue) { - *equeue_id = idm::last_id(); - return CELL_OK; + return CELL_EAGAIN; } - return CELL_EAGAIN; + return CELL_OK; } error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode) diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index 47ad65541d..c042c1f6f2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" +#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -13,6 +14,8 @@ namespace vm { using namespace ps3; } logs::channel sys_event_flag("sys_event_flag"); +template<> DECLARE(ipc_manager::g_ipc) {}; + extern u64 get_system_time(); error_code sys_event_flag_create(vm::ptr id, vm::ptr attr, u64 init) @@ -37,12 +40,6 @@ error_code sys_event_flag_create(vm::ptr id, vm::ptrpshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags) - { - sys_event_flag.error("sys_event_flag_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); - return CELL_EINVAL; - } - const u32 type = attr->type; if (type != SYS_SYNC_WAITER_SINGLE && type != SYS_SYNC_WAITER_MULTIPLE) @@ -51,13 +48,23 @@ error_code sys_event_flag_create(vm::ptr id, vm::ptr(protocol, type, attr->name_u64, init)) + if (auto error = lv2_obj::create(attr->pshared, attr->ipc_key, attr->flags, [&] { - *id = _id; - return CELL_OK; + return std::make_shared( + attr->protocol, + attr->pshared, + attr->ipc_key, + attr->flags, + attr->type, + attr->name_u64, + init); + })) + { + return error; } - return CELL_EAGAIN; + *id = idm::last_id(); + return CELL_OK; } error_code sys_event_flag_destroy(u32 id) diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.h b/rpcs3/Emu/Cell/lv2/sys_event_flag.h index 6002630fe4..fe525ff1f9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.h +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.h @@ -45,11 +45,11 @@ struct lv2_event_flag final : lv2_obj atomic_t pattern; std::deque sq; - lv2_event_flag(u32 protocol, s32 type, u64 name, u64 pattern) + lv2_event_flag(u32 protocol, u32 shared, u64 key, s32 flags, s32 type, u64 name, u64 pattern) : protocol(protocol) - , shared(0) - , key(0) - , flags(0) + , shared(shared) + , key(key) + , flags(flags) , type(type) , name(name) , pattern(pattern) diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index d79402387f..e05e28e576 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" +#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -11,6 +12,8 @@ namespace vm { using namespace ps3; } logs::channel sys_mutex("sys_mutex"); +template<> DECLARE(ipc_manager::g_ipc) {}; + extern u64 get_system_time(); error_code sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) @@ -22,48 +25,53 @@ error_code sys_mutex_create(vm::ptr mutex_id, vm::ptrprotocol; - - switch (protocol) + switch (attr->protocol) { case SYS_SYNC_FIFO: break; case SYS_SYNC_PRIORITY: break; case SYS_SYNC_PRIORITY_INHERIT: - sys_mutex.todo("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT"); + sys_mutex.fatal("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT"); break; default: { - sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", protocol); + sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; } } - const u32 recursive = attr->recursive; - - switch (recursive) + switch (attr->recursive) { case SYS_SYNC_RECURSIVE: break; case SYS_SYNC_NOT_RECURSIVE: break; default: { - sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", recursive); + sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", attr->recursive); return CELL_EINVAL; } } - if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->adaptive != SYS_SYNC_NOT_ADAPTIVE || attr->ipc_key || attr->flags) + if (attr->adaptive != SYS_SYNC_NOT_ADAPTIVE) { - sys_mutex.error("sys_mutex_create(): unknown attributes (pshared=0x%x, adaptive=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->adaptive, attr->ipc_key, attr->flags); - return CELL_EINVAL; + sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", attr->adaptive); } - if (const u32 id = idm::make(protocol, recursive, attr->name_u64)) + if (auto error = lv2_obj::create(attr->pshared, attr->ipc_key, attr->flags, [&]() { - *mutex_id = id; - return CELL_OK; + return std::make_shared( + attr->protocol, + attr->recursive, + attr->pshared, + attr->adaptive, + attr->ipc_key, + attr->flags, + attr->name_u64); + })) + { + return error; } - return CELL_EAGAIN; + *mutex_id = idm::last_id(); + return CELL_OK; } error_code sys_mutex_destroy(u32 mutex_id) diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h index 4d9170019c..13966f2483 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -37,13 +37,13 @@ struct lv2_mutex final : lv2_obj atomic_t cond_count{0}; // Condition Variables std::deque sq; - lv2_mutex(u32 protocol, u32 recursive, u64 name) + lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, s32 flags, u64 name) : protocol(protocol) , recursive(recursive) - , shared(0) - , adaptive(0) - , key(0) - , flags(0) + , shared(shared) + , adaptive(adaptive) + , key(key) + , flags(flags) , name(name) { } diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp index df8e310bc7..fb5899836e 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" +#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -11,6 +12,8 @@ namespace vm { using namespace ps3; } logs::channel sys_rwlock("sys_rwlock"); +template<> DECLARE(ipc_manager::g_ipc) {}; + extern u64 get_system_time(); error_code sys_rwlock_create(vm::ptr rw_lock_id, vm::ptr attr) @@ -33,19 +36,16 @@ error_code sys_rwlock_create(vm::ptr rw_lock_id, vm::ptrpshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags) + if (auto error = lv2_obj::create(attr->pshared, attr->ipc_key, attr->flags, [&] { - sys_rwlock.error("sys_rwlock_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags); - return CELL_EINVAL; + return std::make_shared(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64); + })) + { + return error; } - if (const u32 id = idm::make(protocol, attr->name_u64)) - { - *rw_lock_id = id; - return CELL_OK; - } - - return CELL_EAGAIN; + *rw_lock_id = idm::last_id(); + return CELL_OK; } error_code sys_rwlock_destroy(u32 rw_lock_id) diff --git a/rpcs3/Emu/Cell/lv2/sys_rwlock.h b/rpcs3/Emu/Cell/lv2/sys_rwlock.h index af53cf1819..6847f350db 100644 --- a/rpcs3/Emu/Cell/lv2/sys_rwlock.h +++ b/rpcs3/Emu/Cell/lv2/sys_rwlock.h @@ -32,11 +32,11 @@ struct lv2_rwlock final : lv2_obj std::deque rq; std::deque wq; - lv2_rwlock(u32 protocol, u64 name) + lv2_rwlock(u32 protocol, u32 shared, u64 key, s32 flags, u64 name) : protocol(protocol) - , shared(0) - , key(0) - , flags(0) + , shared(shared) + , key(key) + , flags(flags) , name(name) { } diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 91da75c689..8b74595691 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" +#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -11,6 +12,8 @@ namespace vm { using namespace ps3; } logs::channel sys_semaphore("sys_semaphore"); +template<> DECLARE(ipc_manager::g_ipc) {}; + extern u64 get_system_time(); error_code sys_semaphore_create(vm::ptr sem_id, vm::ptr attr, s32 initial_val, s32 max_val) @@ -39,19 +42,16 @@ error_code sys_semaphore_create(vm::ptr sem_id, vm::ptrpshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags) + if (auto error = lv2_obj::create(attr->pshared, attr->ipc_key, attr->flags, [&] { - 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; + return std::make_shared(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64, max_val, initial_val); + })) + { + return error; } - if (const u32 id = idm::make(protocol, attr->name_u64, max_val, initial_val)) - { - *sem_id = id; - return CELL_OK; - } - - return CELL_EAGAIN; + *sem_id = idm::last_id(); + return CELL_OK; } error_code sys_semaphore_destroy(u32 sem_id) diff --git a/rpcs3/Emu/Cell/lv2/sys_semaphore.h b/rpcs3/Emu/Cell/lv2/sys_semaphore.h index 844a8abbc7..7e02b36309 100644 --- a/rpcs3/Emu/Cell/lv2/sys_semaphore.h +++ b/rpcs3/Emu/Cell/lv2/sys_semaphore.h @@ -32,11 +32,11 @@ struct lv2_sema final : lv2_obj atomic_t val; std::deque sq; - lv2_sema(u32 protocol, u64 name, s32 max, s32 value) + lv2_sema(u32 protocol, u32 shared, u64 key, s32 flags, u64 name, s32 max, s32 value) : protocol(protocol) - , shared(0) - , key(0) - , flags(0) + , shared(shared) + , key(key) + , flags(flags) , name(name) , max(max) , val(value) diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 0943706b2b..61fba830bb 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -7,46 +7,52 @@ #include "Emu/Memory/vm.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/ErrorCodes.h" +#include "Emu/IdManager.h" +#include "Emu/IPC.h" #include // attr_protocol (waiting scheduling policy) enum { - // First In, First Out - SYS_SYNC_FIFO = 1, - // Priority Order - SYS_SYNC_PRIORITY = 2, - // Basic Priority Inheritance Protocol (probably not implemented) - SYS_SYNC_PRIORITY_INHERIT = 3, - // Not selected while unlocking - SYS_SYNC_RETRY = 4, - // - SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, + SYS_SYNC_FIFO = 0x1, // First In, First Out Order + SYS_SYNC_PRIORITY = 0x2, // Priority Order + SYS_SYNC_PRIORITY_INHERIT = 0x3, // Basic Priority Inheritance Protocol + SYS_SYNC_RETRY = 0x4, // Not selected while unlocking + SYS_SYNC_ATTR_PROTOCOL_MASK = 0xf, }; // attr_recursive (recursive locks policy) enum { - // Recursive locks are allowed - SYS_SYNC_RECURSIVE = 0x10, - // Recursive locks are NOT allowed - SYS_SYNC_NOT_RECURSIVE = 0x20, - // - SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? + SYS_SYNC_RECURSIVE = 0x10, + SYS_SYNC_NOT_RECURSIVE = 0x20, + SYS_SYNC_ATTR_RECURSIVE_MASK = 0xf0, }; -// attr_pshared +// attr_pshared (sharing among processes policy) enum { - SYS_SYNC_NOT_PROCESS_SHARED = 0x200, + SYS_SYNC_PROCESS_SHARED = 0x100, + SYS_SYNC_NOT_PROCESS_SHARED = 0x200, + SYS_SYNC_ATTR_PSHARED_MASK = 0xf00, +}; + +// attr_flags (creation policy) +enum +{ + SYS_SYNC_NEWLY_CREATED = 0x1, // Create new object, fails if specified IPC key exists + SYS_SYNC_NOT_CREATE = 0x2, // Reference existing object, fails if IPC key not found + SYS_SYNC_NOT_CARE = 0x3, // Reference existing object, create new one if IPC key not found + SYS_SYNC_ATTR_FLAGS_MASK = 0xf, }; // attr_adaptive enum { - SYS_SYNC_ADAPTIVE = 0x1000, - SYS_SYNC_NOT_ADAPTIVE = 0x2000, + SYS_SYNC_ADAPTIVE = 0x1000, + SYS_SYNC_NOT_ADAPTIVE = 0x2000, + SYS_SYNC_ATTR_ADAPTIVE_MASK = 0xf000, }; // Base class for some kernel objects (shared set of 8192 objects). @@ -126,6 +132,81 @@ struct lv2_obj static void cleanup(); + template + static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make) + { + switch (pshared) + { + case SYS_SYNC_PROCESS_SHARED: + { + switch (flags) + { + case SYS_SYNC_NEWLY_CREATED: + case SYS_SYNC_NOT_CARE: + { + std::shared_ptr result = make(); + + if (!ipc_manager::add(ipc_key, [&] { if (!idm::import_existing(result)) result.reset(); return result; }, &result)) + { + if (flags == SYS_SYNC_NEWLY_CREATED) + { + return CELL_EEXIST; + } + + if (!idm::import_existing(result)) + { + return CELL_EAGAIN; + } + + return CELL_OK; + } + else if (!result) + { + return CELL_EAGAIN; + } + else + { + return CELL_OK; + } + } + case SYS_SYNC_NOT_CREATE: + { + auto result = ipc_manager::get(ipc_key); + + if (!result) + { + return CELL_ESRCH; + } + + if (!idm::import_existing(result)) + { + return CELL_EAGAIN; + } + + return CELL_OK; + } + default: + { + return CELL_EINVAL; + } + } + } + case SYS_SYNC_NOT_PROCESS_SHARED: + { + if (!idm::import(std::forward(make))) + { + return CELL_EAGAIN; + } + + return CELL_OK; + } + default: + { + return CELL_EINVAL; + } + } + } + private: // Scheduler mutex static semaphore<> g_mutex; diff --git a/rpcs3/Emu/IPC.h b/rpcs3/Emu/IPC.h index 5ff926c6e6..d57deea9c6 100644 --- a/rpcs3/Emu/IPC.h +++ b/rpcs3/Emu/IPC.h @@ -7,7 +7,7 @@ // IPC manager for objects of type T and IPC keys of type K. // External declaration of g_ipc is required. -template +template class ipc_manager final { std::unordered_map> m_map; @@ -18,18 +18,27 @@ class ipc_manager final public: // Add new object if specified ipc_key is not used - template - static bool add(const K& ipc_key, F&& provider) + template + static bool add(const K& ipc_key, F&& provider, std::shared_ptr* out = nullptr) { writer_lock lock(g_ipc.m_mutex); // Get object location std::weak_ptr& wptr = g_ipc.m_map[ipc_key]; - if (wptr.expired()) + if ((out && !(*out = wptr.lock())) || wptr.expired()) { // Call a function which must return the object - wptr = provider(); + if (out) + { + *out = provider(); + wptr = *out; + } + else + { + wptr = provider(); + } + return true; }