diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index dfe4424579..db16ea8337 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -88,7 +88,7 @@ error_code sys_memory_allocate_from_container(u32 size, u32 cid, u64 flags, vm:: error_code result{}; - const auto ct = idm::get(cid, [&](u32, lv2_memory_container& ct) + const auto ct = idm::get(cid, [&](lv2_memory_container& ct) { // Try to get "physical memory" if (!ct.take(size)) @@ -208,7 +208,7 @@ error_code sys_memory_container_destroy(u32 cid) error_code result{}; - const auto ct = idm::withdraw(cid, [&](u32, lv2_memory_container& ct) + const auto ct = idm::withdraw(cid, [&](lv2_memory_container& ct) { // Check if some memory is not deallocated (the container cannot be destroyed in this case) if (!ct.used.compare_and_swap_test(0, ct.size)) diff --git a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index 5db37d58da..e612310a82 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -143,7 +143,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, error_code result{}; - const auto ct = idm::get(cid, [&](u32, lv2_memory_container& ct) + const auto ct = idm::get(cid, [&](lv2_memory_container& ct) { // Try to get "physical memory" if (!ct.take(size)) @@ -166,7 +166,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container(u64 unk, u32 size, } // Generate a new mem ID - *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, ct); + *mem_id = idm::make(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, ct.ptr); return CELL_OK; } @@ -205,7 +205,7 @@ error_code sys_mmapper_free_shared_memory(u32 mem_id) error_code result{}; // Conditionally remove memory ID - const auto mem = idm::withdraw(mem_id, [&](u32, lv2_memory& mem) + const auto mem = idm::withdraw(mem_id, [&](lv2_memory& mem) { if (mem.addr.compare_and_swap_test(0, -1)) { diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 7bb8961dad..bf919dd6f8 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -206,32 +206,68 @@ class idm template struct function_traits { - using second_type = A2; - using return_type = R; + using object_type = A2; + using result_type = R; + }; + + template + struct function_traits + { + using object_type = A2; + using result_type = R; + }; + + template + struct function_traits + { + using object_type = A2; + using void_type = void; + }; + + template + struct function_traits + { + using object_type = A2; + using void_type = void; }; // Helper - template - struct bool_if_void + template + struct return_pair { - friend bool operator ,(bool lhs, const bool_if_void&) + std::shared_ptr ptr; + RT value; + + explicit operator bool() const { - return lhs; + return ptr.operator bool(); } - operator bool() const + auto operator->() const { - return Value; + return ptr.get(); } }; - // Prepares new ID, returns nullptr if out of resources + template + struct return_pair + { + bool result; + RT value; + + explicit operator bool() const + { + return result; + } + }; + + // Prepare new ID (returns nullptr if out of resources) static id_manager::id_map::pointer allocate_id(u32 tag, u32 type, u32 min, u32 max); // Deallocate ID, returns object static std::shared_ptr deallocate_id(u32 tag, u32 id); - // Allocate new ID and construct it from the provider() + // Allocate new ID and assign the object from the provider() template static id_manager::id_map::pointer create_id(F&& provider) { @@ -265,7 +301,7 @@ class idm // Get ID (internal) static id_manager::id_map::pointer find_id(u32 type, u32 true_type, u32 id); - // Remove ID and return object + // Remove ID and return the object static std::shared_ptr delete_id(u32 type, u32 true_type, u32 tag, u32 id); public: @@ -331,16 +367,53 @@ public: return nullptr; } - // Check whether the ID exists + // Check the ID template - static inline bool check(u32 id) + static inline explicit_bool_t check(u32 id) { reader_lock lock(g_mutex); return find_id(get_type(), get_type(), id) != nullptr; } - // Get the ID + // Check the ID, access object under shared lock + template, typename = std::enable_if_t::value>> + static inline explicit_bool_t check(u32 id, F&& func, int = 0) + { + using pointer_type = std::conditional_t::value, T, Get>; + + reader_lock lock(g_mutex); + + const auto found = find_id(get_type(), get_type(), id); + + if (UNLIKELY(found == nullptr)) + { + return false; + } + + func(*static_cast(found->second.get())); + return true; + } + + // Check the ID, access object under reader lock, propagate return value + template, typename = std::enable_if_t::value>> + static inline return_pair check(u32 id, F&& func) + { + using pointer_type = std::conditional_t::value, T, Get>; + + reader_lock lock(g_mutex); + + const auto found = find_id(get_type(), get_type(), id); + + if (UNLIKELY(found == nullptr)) + { + return {false}; + } + + return {true, func(*static_cast(found->second.get()))}; + } + + // Get the object template::value, T, Get>> static inline std::shared_ptr get(u32 id) { @@ -353,14 +426,15 @@ public: return nullptr; } - return{ found->second, static_cast(found->second.get()) }; + return {found->second, static_cast(found->second.get())}; } - // Conditionally get the ID, almost similar to select() but for the single object only. - template::second_type> - static inline auto get(u32 id, F&& pred) + // Get the object, access object under reader lock + template, typename = std::enable_if_t::value>> + static inline auto get(u32 id, F&& func, int = 0) { - using result_type = std::conditional_t::return_type>::value, void, std::shared_ptr>; + using pointer_type = std::conditional_t::value, T, Get>; + using result_type = std::shared_ptr; reader_lock lock(g_mutex); @@ -368,22 +442,63 @@ public: if (UNLIKELY(found == nullptr)) { - return static_cast(nullptr); + return result_type{nullptr}; } - if (pred(id, *static_cast(found->second.get())), bool_if_void()) - { - return static_cast(std::static_pointer_cast(found->second)); - } + const auto ptr = static_cast(found->second.get()); - return static_cast(nullptr); + func(*ptr); + + return result_type{found->second, ptr}; } - // Execute for all IDs (unsorted), may return void. If the result evaluates to true, the loop stops and returns the object. - template::second_type> - static inline auto select(F&& pred) + // Get the object, access object under reader lock, propagate return value + template, typename = std::enable_if_t::value>> + static inline auto get(u32 id, F&& func) { - using result_type = std::conditional_t::return_type>::value, void, std::shared_ptr>; + using pointer_type = std::conditional_t::value, T, Get>; + using result_type = return_pair; + + reader_lock lock(g_mutex); + + const auto found = find_id(get_type(), get_type(), id); + + if (UNLIKELY(found == nullptr)) + { + return result_type{nullptr}; + } + + const auto ptr = static_cast(found->second.get()); + + return result_type{{found->second, ptr}, func(*ptr)}; + } + + // Access all objects of specified types under reader lock (use lambda or callable object), return the number of objects processed + template::operator()), typename FRT = typename function_traits::void_type> + static inline u32 select(F&& func, int = 0) + { + reader_lock lock(g_mutex); + + u32 result = 0; + + for (u32 type : { get_type()... }) + { + for (auto& id : g_map[type]) + { + func(id.first.id(), *static_cast::object_type*>(id.second.get())); + result++; + } + } + + return result; + } + + // Access all objects of specified types under reader lock (use lambda or callable object), if return value evaluates to true, stop and return the object and the value + template::operator()), typename FRT = typename function_traits::result_type> + static inline auto select(F&& func) + { + using object_type = typename function_traits::object_type; + using result_type = return_pair; reader_lock lock(g_mutex); @@ -391,14 +506,14 @@ public: { for (auto& id : g_map[type]) { - if (pred(id.first.id(), *static_cast(id.second.get())), bool_if_void()) + if (FRT result = func(id.first.id(), *static_cast(id.second.get()))) { - return static_cast(std::static_pointer_cast(id.second)); + return result_type{{id.second, static_cast(id.second.get())}, std::move(result)}; } } } - return static_cast(nullptr); + return result_type{nullptr}; } // Get count of objects @@ -427,9 +542,9 @@ public: // Remove the ID template - static inline bool remove(u32 id) + static inline explicit_bool_t remove(u32 id) { - auto&& ptr = delete_id(get_type(), get_type(), get_tag(), id); + auto ptr = delete_id(get_type(), get_type(), get_tag(), id); if (LIKELY(ptr)) { @@ -439,33 +554,76 @@ public: return ptr.operator bool(); } - // Remove the ID and return it + // Remove the ID and return the object template::value, T, Get>> static inline std::shared_ptr withdraw(u32 id) { - auto&& ptr = delete_id(get_type(), get_type(), get_tag(), id); + auto ptr = delete_id(get_type(), get_type(), get_tag(), id); if (LIKELY(ptr)) { id_manager::on_stop::func(static_cast(ptr.get())); } - return{ ptr, static_cast(ptr.get()) }; + return {ptr, static_cast(ptr.get())}; } - // Conditionally remove the ID and return it. - template::value, T, Get>, typename F> - static inline std::shared_ptr withdraw(u32 id, F&& pred) + // Remove the ID after accessing the object under writer lock, return the object and propagate return value + template, typename = std::enable_if_t::value>> + static inline auto withdraw(u32 id, F&& func, int = 0) { + using pointer_type = std::conditional_t::value, T, Get>; + using result_type = std::shared_ptr; + std::shared_ptr ptr; { writer_lock lock(g_mutex); const auto found = find_id(get_type(), get_type(), id); - if (UNLIKELY(found == nullptr || !pred(id, *static_cast(found->second.get())))) + if (UNLIKELY(found == nullptr)) { - return nullptr; + return result_type{nullptr}; + } + + func(*static_cast(found->second.get())); + + ptr = deallocate_id(get_tag(), id); + + g_map[get_type()].erase(id); + } + + id_manager::on_stop::func(static_cast(ptr.get())); + + return result_type{ptr, static_cast(ptr.get())}; + } + + // Conditionally remove the ID (if return value evaluates to false) after accessing the object under writer lock, return the object and propagate return value + template, typename = std::enable_if_t::value>> + static inline auto withdraw(u32 id, F&& func) + { + using pointer_type = std::conditional_t::value, T, Get>; + using result_type = return_pair; + + std::shared_ptr ptr; + FRT ret; + { + writer_lock lock(g_mutex); + + const auto found = find_id(get_type(), get_type(), id); + + if (UNLIKELY(found == nullptr)) + { + return result_type{nullptr}; + } + + const auto _ptr = static_cast(found->second.get()); + + ret = func(*_ptr); + + if (ret) + { + return result_type{{found->second, _ptr}, std::move(ret)}; } ptr = deallocate_id(get_tag(), id); @@ -475,7 +633,7 @@ public: id_manager::on_stop::func(static_cast(ptr.get())); - return{ ptr, static_cast(ptr.get()) }; + return result_type{{ptr, static_cast(ptr.get())}, std::move(ret)}; } }; @@ -637,7 +795,7 @@ public: // Check whether the object exists template - static inline bool check() + static inline explicit_bool_t check() { reader_lock lock(g_mutex); @@ -657,9 +815,9 @@ public: // Delete the object template - static inline bool remove() + static inline explicit_bool_t remove() { - auto&& ptr = remove(get_type()); + auto ptr = remove(get_type()); if (ptr) { @@ -673,7 +831,7 @@ public: template static inline std::shared_ptr withdraw() { - auto&& ptr = remove(get_type()); + auto ptr = remove(get_type()); if (ptr) { diff --git a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp index 5aa0054b09..469cc49286 100644 --- a/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/PSP2/Modules/sceLibKernel.cpp @@ -909,7 +909,7 @@ struct psp2_event_flag final case task::signal: { - idm::get(cmd.arg, [&](u32, ARMv7Thread& cpu) + idm::get(cmd.arg, [&](ARMv7Thread& cpu) { cpu.state += cpu_flag::signal; cpu.lock_notify(); @@ -954,7 +954,7 @@ private: // Check condition void op_wait(u32 thread_id) { - idm::get(thread_id, [&](u32, ARMv7Thread& cpu) + idm::get(thread_id, [&](ARMv7Thread& cpu) { const u32 pattern = ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state) -> u32 { @@ -987,7 +987,7 @@ private: // Check condition void op_poll(u32 thread_id) { - idm::get(thread_id, [&](u32, ARMv7Thread& cpu) + idm::get(thread_id, [&](ARMv7Thread& cpu) { cpu.GPR[1] = ctrl.atomic_op([&](psp2_event_flag::ctrl_t& state) -> u32 { @@ -1043,7 +1043,7 @@ private: } else { - idm::get(new_state.waiters, [&](u32 id, ARMv7Thread& cpu) + idm::get(new_state.waiters, [&](ARMv7Thread& cpu) { if (cpu->lock_if([&] { return cpu.owner == this && pat_test(new_state.pattern, cpu.GPR[1], cpu.GPR[0]); })) {