mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 11:36:13 +00:00
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:
parent
224a0e4b1a
commit
3265772ae4
5 changed files with 44 additions and 17 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Add table
Reference in a new issue