diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/rpcs3/Emu/Cell/lv2/sys_cond.cpp index 5776b3500d..7a0a82e70d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -59,7 +59,7 @@ error_code sys_cond_destroy(ppu_thread& ppu, u32 cond_id) return CELL_EBUSY; } - cond.mutex->cond_count--; + cond.mutex->obj_count.atomic_op([](typename lv2_mutex::count_info& info){ info.cond_count--; }); return {}; }); diff --git a/rpcs3/Emu/Cell/lv2/sys_cond.h b/rpcs3/Emu/Cell/lv2/sys_cond.h index 6337086d93..16537f897d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_cond.h +++ b/rpcs3/Emu/Cell/lv2/sys_cond.h @@ -40,7 +40,22 @@ struct lv2_cond final : lv2_obj , mtx_id(mtx_id) , mutex(std::move(mutex)) { - this->mutex->cond_count++; + } + + CellError on_id_create() + { + if (!mutex->obj_count.fetch_op([](typename lv2_mutex::count_info& info) + { + if (info.mutex_count) + return info.cond_count++, true; + return false; + }).second) + { + // Mutex has been destroyed, cannot create conditional variable + return CELL_ESRCH; + } + + return {}; } }; diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index 8e1e92014f..b85b96154d 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -88,7 +88,17 @@ error_code sys_mutex_destroy(ppu_thread& ppu, u32 mutex_id) return CELL_EBUSY; } - if (mutex.cond_count) + if (!mutex.obj_count.fetch_op([](typename lv2_mutex::count_info& info) + { + if (info.cond_count) + { + return false; + } + + // Decrement mutex copies count + info.mutex_count--; + return true; + }).second) { return CELL_EPERM; } diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.h b/rpcs3/Emu/Cell/lv2/sys_mutex.h index 238a594fc1..149831832b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.h +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.h @@ -33,10 +33,16 @@ struct lv2_mutex final : lv2_obj const u64 name; const s32 flags; + struct alignas(8) count_info + { + u32 mutex_count; // Mutex copies count (0 means doesn't exist anymore) + u32 cond_count; // Condition Variables + }; + shared_mutex mutex; - atomic_t owner{0}; // Owner Thread ID + atomic_t owner{0}; atomic_t lock_count{0}; // Recursive Locks - atomic_t cond_count{0}; // Condition Variables + atomic_t obj_count{}; std::deque sq; lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, s32 flags, u64 name) @@ -50,6 +56,12 @@ struct lv2_mutex final : lv2_obj { } + CellError on_id_create() + { + obj_count.atomic_op([](count_info& info){ info.mutex_count++; }); + return {}; + } + CellError try_lock(u32 id) { const u32 value = owner; diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 34efca47b2..43b7b952af 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -75,6 +75,12 @@ private: enqueue_cmd, }; + // Function executed under IDM mutex, error will make the object creation fail and the error will be returned + CellError on_id_create() + { + return {}; + } + public: static std::string name64(u64 name_u64) @@ -205,23 +211,45 @@ public: { std::shared_ptr result = make(); - if (!ipc_manager::add(ipc_key, [&] { if (!idm::import_existing(result)) result.reset(); return result; }, &result)) + CellError error{}; + + if (!ipc_manager::add(ipc_key, [&]() { + if (!idm::import([&]() + { + if (result && (error = result->on_id_create())) + result.reset(); + return result; + })) + { + result.reset(); + } + + return result; + }, &result)) + { + if (error) + { + return error; + } + if (flags == SYS_SYNC_NEWLY_CREATED) { return CELL_EEXIST; } - if (!idm::import_existing(result)) + error = CELL_EAGAIN; + + if (!idm::import([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); })) { - return CELL_EAGAIN; + return error; } return CELL_OK; } else if (!result) { - return CELL_EAGAIN; + return error ? CELL_EAGAIN : error; } else { @@ -237,9 +265,11 @@ public: return CELL_ESRCH; } - if (!idm::import_existing(result)) + CellError error = CELL_EAGAIN; + + if (!idm::import([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); })) { - return CELL_EAGAIN; + return error; } return CELL_OK; @@ -252,9 +282,13 @@ public: } case SYS_SYNC_NOT_PROCESS_SHARED: { - if (!idm::import(std::forward(make))) + std::shared_ptr result = make(); + + CellError error = CELL_EAGAIN; + + if (!idm::import([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); })) { - return CELL_EAGAIN; + return error; } return CELL_OK; diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index 8414dcbd51..4c9c88ed55 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -292,7 +292,7 @@ void kernel_explorer::Update() { auto& mutex = static_cast(obj); add_leaf(node, qstr(fmt::format(u8"Mutex 0x%08x: ā€œ%sā€, %s,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u, Wq: %zu", id, lv2_obj::name64(mutex.name), mutex.protocol, - mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, +mutex.cond_count, mutex.sq.size()))); + mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, mutex.obj_count.load().cond_count, mutex.sq.size()))); break; } case SYS_COND_OBJECT: