From 3265772ae4d5dc32fcd499c276f20f110c3bedd1 Mon Sep 17 00:00:00 2001 From: Eladash Date: Thu, 28 Nov 2019 12:17:16 +0200 Subject: [PATCH] idm: Implement creation/destruction invalidation counter * "Ensures" newely created IDs won't have the same ID as old destroyed objects for lv2_obj. (256 tries cycle) Similar to how the kernel implements it. --- rpcs3/Emu/Cell/PPUThread.h | 1 + rpcs3/Emu/Cell/lv2/sys_spu.h | 1 + rpcs3/Emu/Cell/lv2/sys_sync.h | 1 + rpcs3/Emu/IdManager.cpp | 10 +++++--- rpcs3/Emu/IdManager.h | 48 +++++++++++++++++++++++++---------- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index a14bd452a0..a2bd28b31a 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -60,6 +60,7 @@ public: static const u32 id_base = 0x01000000; // TODO (used to determine thread type) static const u32 id_step = 1; static const u32 id_count = 2048; + static constexpr std::pair id_invl_range = {12, 12}; virtual std::string dump_all() const override; virtual std::string dump_regs() const override; diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 50b29895eb..1d0e604bcf 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -260,6 +260,7 @@ struct lv2_spu_group static const u32 id_base = 0x04000100; static const u32 id_step = 0x100; static const u32 id_count = 255; + static constexpr std::pair id_invl_range = {0, 8}; const std::string name; const u32 id; diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index 262a5d4fd6..c49186cfae 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -66,6 +66,7 @@ struct lv2_obj static const u32 id_step = 0x100; static const u32 id_count = 8192; + static constexpr std::pair id_invl_range = {0, 8}; private: enum thread_cmd : s32 diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index cf5d0bee14..8dfbdec3f6 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "IdManager.h" #include "Utilities/Thread.h" @@ -7,7 +7,7 @@ shared_mutex id_manager::g_mutex; thread_local DECLARE(idm::g_id); DECLARE(idm::g_map); -id_manager::id_map::pointer idm::allocate_id(const id_manager::id_key& info, u32 base, u32 step, u32 count) +id_manager::id_map::pointer idm::allocate_id(const id_manager::id_key& info, u32 base, u32 step, u32 count, std::pair invl_range) { // Base type id is stored in value auto& vec = g_map[info.value()]; @@ -32,8 +32,10 @@ id_manager::id_map::pointer idm::allocate_id(const id_manager::id_key& info, u32 // Look for free ID if (!ptr->second) { - g_id = next; - ptr->first = id_manager::id_key(next, info.type()); + // Incremenet ID invalidation counter + const u32 id = next | ((ptr->first + (1u << invl_range.first)) & (invl_range.second ? (((1u << invl_range.second) - 1) << invl_range.first) : 0)); + g_id = id; + ptr->first = id_manager::id_key(id, info.type()); return ptr; } } diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index ebf36eb263..548daa5c75 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -18,22 +18,39 @@ namespace id_manager { static_assert(sizeof(T) == 0, "ID object must specify: id_base, id_step, id_count"); - static const u32 base = 1; // First ID (N = 0) - static const u32 step = 1; // Any ID: N * id_step + id_base - static const u32 count = 65535; // Limit: N < id_count - static const u32 invalid = 0; + static constexpr u32 base = 1; // First ID (N = 0) + static constexpr u32 step = 1; // Any ID: N * id_step + id_base + static constexpr u32 count = 65535; // Limit: N < id_count + static constexpr u32 invalid = 0; + static constexpr std::pair invl_range{0, 0}; + }; + + template + struct invl_range_extract_impl + { + static constexpr std::pair invl_range{0, 0}; + }; + + template + struct invl_range_extract_impl> + { + static constexpr std::pair invl_range = T::id_invl_range; }; template struct id_traits> { - static const u32 base = T::id_base; - static const u32 step = T::id_step; - static const u32 count = T::id_count; - static const u32 invalid = -+!base; + static constexpr u32 base = T::id_base; + static constexpr u32 step = T::id_step; + static constexpr u32 count = T::id_count; + static constexpr u32 invalid = -+!base; + + static constexpr std::pair invl_range = invl_range_extract_impl::invl_range; - // Note: full 32 bits range cannot be used at current implementation static_assert(count && step && u64{step} * (count - 1) + base < u64{UINT32_MAX} + (base != 0 ? 1 : 0), "ID traits: invalid object range"); + + // TODO: Add more conditions + static_assert(!invl_range.second || (u64{invl_range.second} + invl_range.first <= 32 /*....*/ )); }; // Correct usage testing @@ -138,8 +155,10 @@ class idm { using traits = id_manager::id_traits; + constexpr u32 mask_out = ((1u << traits::invl_range.second) - 1) << traits::invl_range.first; + // Note: if id is lower than base, diff / step will be higher than count - u32 diff = id - traits::base; + u32 diff = (id & ~mask_out) - traits::base; if (diff % traits::step) { @@ -230,7 +249,7 @@ class idm }; // Prepare new ID (returns nullptr if out of resources) - static id_manager::id_map::pointer allocate_id(const id_manager::id_key& info, u32 base, u32 step, u32 count); + static id_manager::id_map::pointer allocate_id(const id_manager::id_key& info, u32 base, u32 step, u32 count, std::pair invl_range); // Find ID (additionally check type if types are not equal) template @@ -258,7 +277,10 @@ class idm { if (std::is_same::value || data.first.type() == get_type()) { - return &data; + if (!id_manager::id_traits::invl_range.second || data.first.value() == id) + { + return &data; + } } } @@ -280,7 +302,7 @@ class idm // Allocate new id std::lock_guard lock(id_manager::g_mutex); - if (auto* place = allocate_id(info, traits::base, traits::step, traits::count)) + if (auto* place = allocate_id(info, traits::base, traits::step, traits::count, traits::invl_range)) { // Get object, store it place->second = provider();