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.
This commit is contained in:
Eladash 2019-11-28 12:17:16 +02:00 committed by Ivan
parent 224a0e4b1a
commit 3265772ae4
5 changed files with 44 additions and 17 deletions

View File

@ -60,6 +60,7 @@ public:
static const u32 id_base = 0x01000000; // TODO (used to determine thread type) static const u32 id_base = 0x01000000; // TODO (used to determine thread type)
static const u32 id_step = 1; static const u32 id_step = 1;
static const u32 id_count = 2048; static const u32 id_count = 2048;
static constexpr std::pair<u32, u32> id_invl_range = {12, 12};
virtual std::string dump_all() const override; virtual std::string dump_all() const override;
virtual std::string dump_regs() const override; virtual std::string dump_regs() const override;

View File

@ -260,6 +260,7 @@ struct lv2_spu_group
static const u32 id_base = 0x04000100; static const u32 id_base = 0x04000100;
static const u32 id_step = 0x100; static const u32 id_step = 0x100;
static const u32 id_count = 255; static const u32 id_count = 255;
static constexpr std::pair<u32, u32> id_invl_range = {0, 8};
const std::string name; const std::string name;
const u32 id; const u32 id;

View File

@ -66,6 +66,7 @@ struct lv2_obj
static const u32 id_step = 0x100; static const u32 id_step = 0x100;
static const u32 id_count = 8192; static const u32 id_count = 8192;
static constexpr std::pair<u32, u32> id_invl_range = {0, 8};
private: private:
enum thread_cmd : s32 enum thread_cmd : s32

View File

@ -1,4 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "IdManager.h" #include "IdManager.h"
#include "Utilities/Thread.h" #include "Utilities/Thread.h"
@ -7,7 +7,7 @@ shared_mutex id_manager::g_mutex;
thread_local DECLARE(idm::g_id); thread_local DECLARE(idm::g_id);
DECLARE(idm::g_map); 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<u32, u32> invl_range)
{ {
// Base type id is stored in value // Base type id is stored in value
auto& vec = g_map[info.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 // Look for free ID
if (!ptr->second) if (!ptr->second)
{ {
g_id = next; // Incremenet ID invalidation counter
ptr->first = id_manager::id_key(next, info.type()); 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; return ptr;
} }
} }

View File

@ -18,22 +18,39 @@ namespace id_manager
{ {
static_assert(sizeof(T) == 0, "ID object must specify: id_base, id_step, id_count"); 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 constexpr u32 base = 1; // First ID (N = 0)
static const u32 step = 1; // Any ID: N * id_step + id_base static constexpr u32 step = 1; // Any ID: N * id_step + id_base
static const u32 count = 65535; // Limit: N < id_count static constexpr u32 count = 65535; // Limit: N < id_count
static const u32 invalid = 0; static constexpr u32 invalid = 0;
static constexpr std::pair<u32, u32> invl_range{0, 0};
};
template <typename T, typename = void>
struct invl_range_extract_impl
{
static constexpr std::pair<u32, u32> invl_range{0, 0};
};
template <typename T>
struct invl_range_extract_impl<T, std::void_t<decltype(&T::id_invl_range)>>
{
static constexpr std::pair<u32, u32> invl_range = T::id_invl_range;
}; };
template <typename T> template <typename T>
struct id_traits<T, std::void_t<decltype(&T::id_base), decltype(&T::id_step), decltype(&T::id_count)>> struct id_traits<T, std::void_t<decltype(&T::id_base), decltype(&T::id_step), decltype(&T::id_count)>>
{ {
static const u32 base = T::id_base; static constexpr u32 base = T::id_base;
static const u32 step = T::id_step; static constexpr u32 step = T::id_step;
static const u32 count = T::id_count; static constexpr u32 count = T::id_count;
static const u32 invalid = -+!base; static constexpr u32 invalid = -+!base;
static constexpr std::pair<u32, u32> invl_range = invl_range_extract_impl<T>::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"); 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 // Correct usage testing
@ -138,8 +155,10 @@ class idm
{ {
using traits = id_manager::id_traits<T>; using traits = id_manager::id_traits<T>;
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 // 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) if (diff % traits::step)
{ {
@ -230,7 +249,7 @@ class idm
}; };
// Prepare new ID (returns nullptr if out of resources) // 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<u32, u32> invl_range);
// Find ID (additionally check type if types are not equal) // Find ID (additionally check type if types are not equal)
template <typename T, typename Type> template <typename T, typename Type>
@ -257,10 +276,13 @@ class idm
if (data.second) if (data.second)
{ {
if (std::is_same<T, Type>::value || data.first.type() == get_type<Type>()) if (std::is_same<T, Type>::value || data.first.type() == get_type<Type>())
{
if (!id_manager::id_traits<Type>::invl_range.second || data.first.value() == id)
{ {
return &data; return &data;
} }
} }
}
return nullptr; return nullptr;
} }
@ -280,7 +302,7 @@ class idm
// Allocate new id // Allocate new id
std::lock_guard lock(id_manager::g_mutex); 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 // Get object, store it
place->second = provider(); place->second = provider();