1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

IdManager sugar

This commit is contained in:
Nekotekina 2017-01-25 03:45:36 +03:00 committed by Ivan
parent 9232ddf0ab
commit a06223b844
4 changed files with 214 additions and 56 deletions

View File

@ -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<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
const auto ct = idm::get<lv2_memory_container>(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<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
const auto ct = idm::withdraw<lv2_memory_container>(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))

View File

@ -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<lv2_memory_container>(cid, [&](u32, lv2_memory_container& ct)
const auto ct = idm::get<lv2_memory_container>(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<lv2_memory>(size, flags & SYS_MEMORY_PAGE_SIZE_1M ? 0x100000 : 0x10000, flags, ct);
*mem_id = idm::make<lv2_memory>(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<lv2_memory>(mem_id, [&](u32, lv2_memory& mem)
const auto mem = idm::withdraw<lv2_memory>(mem_id, [&](lv2_memory& mem)
{
if (mem.addr.compare_and_swap_test(0, -1))
{

View File

@ -206,32 +206,68 @@ class idm
template<typename F, typename R, typename A1, typename A2>
struct function_traits<R(F::*)(A1, A2&) const>
{
using second_type = A2;
using return_type = R;
using object_type = A2;
using result_type = R;
};
template<typename F, typename R, typename A1, typename A2>
struct function_traits<R(F::*)(A1, A2&)>
{
using object_type = A2;
using result_type = R;
};
template<typename F, typename A1, typename A2>
struct function_traits<void(F::*)(A1, A2&) const>
{
using object_type = A2;
using void_type = void;
};
template<typename F, typename A1, typename A2>
struct function_traits<void(F::*)(A1, A2&)>
{
using object_type = A2;
using void_type = void;
};
// Helper
template<bool Value>
struct bool_if_void
template<typename T, typename RT>
struct return_pair
{
friend bool operator ,(bool lhs, const bool_if_void&)
std::shared_ptr<T> 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<typename RT>
struct return_pair<bool, RT>
{
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<void> 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<typename T, typename Set, typename F>
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<void> 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<typename T, typename Get = void>
static inline bool check(u32 id)
static inline explicit_bool_t check(u32 id)
{
reader_lock lock(g_mutex);
return find_id(get_type<T>(), get_type<Get>(), id) != nullptr;
}
// Get the ID
// Check the ID, access object under shared lock
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline explicit_bool_t check(u32 id, F&& func, int = 0)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return false;
}
func(*static_cast<pointer_type*>(found->second.get()));
return true;
}
// Check the ID, access object under reader lock, propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline return_pair<bool, FRT> check(u32 id, F&& func)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return {false};
}
return {true, func(*static_cast<pointer_type*>(found->second.get()))};
}
// Get the object
template<typename T, typename Get = void, typename Made = std::conditional_t<std::is_void<Get>::value, T, Get>>
static inline std::shared_ptr<Made> get(u32 id)
{
@ -353,14 +426,15 @@ public:
return nullptr;
}
return{ found->second, static_cast<Made*>(found->second.get()) };
return {found->second, static_cast<Made*>(found->second.get())};
}
// Conditionally get the ID, almost similar to select() but for the single object only.
template<typename T, typename Get = void, typename F, typename FT = decltype(&F::operator()), typename A2 = typename function_traits<FT>::second_type>
static inline auto get(u32 id, F&& pred)
// Get the object, access object under reader lock
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline auto get(u32 id, F&& func, int = 0)
{
using result_type = std::conditional_t<std::is_void<typename function_traits<FT>::return_type>::value, void, std::shared_ptr<A2>>;
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = std::shared_ptr<pointer_type>;
reader_lock lock(g_mutex);
@ -368,22 +442,63 @@ public:
if (UNLIKELY(found == nullptr))
{
return static_cast<result_type>(nullptr);
return result_type{nullptr};
}
if (pred(id, *static_cast<A2*>(found->second.get())), bool_if_void<false>())
{
return static_cast<result_type>(std::static_pointer_cast<A2>(found->second));
}
const auto ptr = static_cast<pointer_type*>(found->second.get());
return static_cast<result_type>(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<typename... Types, typename F, typename FT = decltype(&F::operator()), typename A2 = typename function_traits<FT>::second_type>
static inline auto select(F&& pred)
// Get the object, access object under reader lock, propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline auto get(u32 id, F&& func)
{
using result_type = std::conditional_t<std::is_void<typename function_traits<FT>::return_type>::value, void, std::shared_ptr<A2>>;
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = return_pair<pointer_type, FRT>;
reader_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return result_type{nullptr};
}
const auto ptr = static_cast<pointer_type*>(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<typename... Types, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::void_type>
static inline u32 select(F&& func, int = 0)
{
reader_lock lock(g_mutex);
u32 result = 0;
for (u32 type : { get_type<Types>()... })
{
for (auto& id : g_map[type])
{
func(id.first.id(), *static_cast<typename function_traits<FT>::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<typename... Types, typename F, typename FT = decltype(&std::decay_t<F>::operator()), typename FRT = typename function_traits<FT>::result_type>
static inline auto select(F&& func)
{
using object_type = typename function_traits<FT>::object_type;
using result_type = return_pair<object_type, FRT>;
reader_lock lock(g_mutex);
@ -391,14 +506,14 @@ public:
{
for (auto& id : g_map[type])
{
if (pred(id.first.id(), *static_cast<A2*>(id.second.get())), bool_if_void<false>())
if (FRT result = func(id.first.id(), *static_cast<object_type*>(id.second.get())))
{
return static_cast<result_type>(std::static_pointer_cast<A2>(id.second));
return result_type{{id.second, static_cast<object_type*>(id.second.get())}, std::move(result)};
}
}
}
return static_cast<result_type>(nullptr);
return result_type{nullptr};
}
// Get count of objects
@ -427,9 +542,9 @@ public:
// Remove the ID
template<typename T, typename Get = void>
static inline bool remove(u32 id)
static inline explicit_bool_t remove(u32 id)
{
auto&& ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), id);
auto ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), 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<typename T, typename Get = void, typename Made = std::conditional_t<std::is_void<Get>::value, T, Get>>
static inline std::shared_ptr<Made> withdraw(u32 id)
{
auto&& ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), id);
auto ptr = delete_id(get_type<T>(), get_type<Get>(), get_tag<T>(), id);
if (LIKELY(ptr))
{
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
}
return{ ptr, static_cast<Made*>(ptr.get()) };
return {ptr, static_cast<Made*>(ptr.get())};
}
// Conditionally remove the ID and return it.
template<typename T, typename Get = void, typename Made = std::conditional_t<std::is_void<Get>::value, T, Get>, typename F>
static inline std::shared_ptr<Made> withdraw(u32 id, F&& pred)
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
template<typename T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<std::is_void<FRT>::value>>
static inline auto withdraw(u32 id, F&& func, int = 0)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = std::shared_ptr<pointer_type>;
std::shared_ptr<void> ptr;
{
writer_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr || !pred(id, *static_cast<T*>(found->second.get()))))
if (UNLIKELY(found == nullptr))
{
return nullptr;
return result_type{nullptr};
}
func(*static_cast<pointer_type*>(found->second.get()));
ptr = deallocate_id(get_tag<T>(), id);
g_map[get_type<T>()].erase(id);
}
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
return result_type{ptr, static_cast<pointer_type*>(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 T, typename Get = void, typename F, typename FRT = std::result_of_t<F(T&)>, typename = std::enable_if_t<!std::is_void<FRT>::value>>
static inline auto withdraw(u32 id, F&& func)
{
using pointer_type = std::conditional_t<std::is_void<Get>::value, T, Get>;
using result_type = return_pair<pointer_type, FRT>;
std::shared_ptr<void> ptr;
FRT ret;
{
writer_lock lock(g_mutex);
const auto found = find_id(get_type<T>(), get_type<Get>(), id);
if (UNLIKELY(found == nullptr))
{
return result_type{nullptr};
}
const auto _ptr = static_cast<pointer_type*>(found->second.get());
ret = func(*_ptr);
if (ret)
{
return result_type{{found->second, _ptr}, std::move(ret)};
}
ptr = deallocate_id(get_tag<T>(), id);
@ -475,7 +633,7 @@ public:
id_manager::on_stop<T>::func(static_cast<T*>(ptr.get()));
return{ ptr, static_cast<Made*>(ptr.get()) };
return result_type{{ptr, static_cast<pointer_type*>(ptr.get())}, std::move(ret)};
}
};
@ -637,7 +795,7 @@ public:
// Check whether the object exists
template<typename T>
static inline bool check()
static inline explicit_bool_t check()
{
reader_lock lock(g_mutex);
@ -657,9 +815,9 @@ public:
// Delete the object
template<typename T>
static inline bool remove()
static inline explicit_bool_t remove()
{
auto&& ptr = remove(get_type<T>());
auto ptr = remove(get_type<T>());
if (ptr)
{
@ -673,7 +831,7 @@ public:
template<typename T>
static inline std::shared_ptr<T> withdraw()
{
auto&& ptr = remove(get_type<T>());
auto ptr = remove(get_type<T>());
if (ptr)
{

View File

@ -909,7 +909,7 @@ struct psp2_event_flag final
case task::signal:
{
idm::get<ARMv7Thread>(cmd.arg, [&](u32, ARMv7Thread& cpu)
idm::get<ARMv7Thread>(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<ARMv7Thread>(thread_id, [&](u32, ARMv7Thread& cpu)
idm::get<ARMv7Thread>(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<ARMv7Thread>(thread_id, [&](u32, ARMv7Thread& cpu)
idm::get<ARMv7Thread>(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<ARMv7Thread>(new_state.waiters, [&](u32 id, ARMv7Thread& cpu)
idm::get<ARMv7Thread>(new_state.waiters, [&](ARMv7Thread& cpu)
{
if (cpu->lock_if([&] { return cpu.owner == this && pat_test(new_state.pattern, cpu.GPR[1], cpu.GPR[0]); }))
{