mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 14:08:37 +00:00
Some things improved
shared_mutex_t implemented GUI Emu Callbacks rewritten fxm::import, fxm::import_always implemented cellMsgDialog rewritten Emu.CallAfter improved (returns std::future)
This commit is contained in:
parent
9d68c16c62
commit
8ae3401ffa
77 changed files with 1814 additions and 1831 deletions
|
|
@ -1,355 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
template<typename T, size_t size = sizeof(T)> struct _to_atomic_subtype
|
||||
{
|
||||
static_assert(size == 1 || size == 2 || size == 4 || size == 8 || size == 16, "Invalid atomic type");
|
||||
};
|
||||
|
||||
template<typename T> struct _to_atomic_subtype<T, 1>
|
||||
{
|
||||
using type = u8;
|
||||
};
|
||||
|
||||
template<typename T> struct _to_atomic_subtype<T, 2>
|
||||
{
|
||||
using type = u16;
|
||||
};
|
||||
|
||||
template<typename T> struct _to_atomic_subtype<T, 4>
|
||||
{
|
||||
using type = u32;
|
||||
};
|
||||
|
||||
template<typename T> struct _to_atomic_subtype<T, 8>
|
||||
{
|
||||
using type = u64;
|
||||
};
|
||||
|
||||
template<typename T> struct _to_atomic_subtype<T, 16>
|
||||
{
|
||||
using type = u128;
|
||||
};
|
||||
|
||||
template<typename T> using atomic_subtype_t = typename _to_atomic_subtype<T>::type;
|
||||
|
||||
// result wrapper to deal with void result type
|
||||
template<typename T, typename RT, typename VT> struct atomic_op_result_t
|
||||
{
|
||||
RT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
|
||||
: result(std::move(func(var, std::forward<Args>(args)...)))
|
||||
{
|
||||
}
|
||||
|
||||
inline RT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
// void specialization: result is the initial value of the first arg
|
||||
template<typename T, typename VT> struct atomic_op_result_t<T, void, VT>
|
||||
{
|
||||
VT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(T func, VT& var, Args&&... args)
|
||||
: result(var)
|
||||
{
|
||||
func(var, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline VT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
// member function specialization
|
||||
template<typename CT, typename... FArgs, typename RT, typename VT> struct atomic_op_result_t<RT(CT::*)(FArgs...), RT, VT>
|
||||
{
|
||||
RT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
: result(std::move((var.*func)(std::forward<Args>(args)...)))
|
||||
{
|
||||
}
|
||||
|
||||
inline RT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
// member function void specialization
|
||||
template<typename CT, typename... FArgs, typename VT> struct atomic_op_result_t<void(CT::*)(FArgs...), void, VT>
|
||||
{
|
||||
VT result;
|
||||
|
||||
template<typename... Args> inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args)
|
||||
: result(var)
|
||||
{
|
||||
(var.*func)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
inline VT move()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> union _atomic_base
|
||||
{
|
||||
using type = std::remove_cv_t<T>;
|
||||
using subtype = atomic_subtype_t<type>;
|
||||
|
||||
type data; // unsafe direct access
|
||||
subtype sub_data; // unsafe direct access to substitute type
|
||||
|
||||
force_inline static const subtype to_subtype(const type& value)
|
||||
{
|
||||
return reinterpret_cast<const subtype&>(value);
|
||||
}
|
||||
|
||||
force_inline static const type from_subtype(const subtype value)
|
||||
{
|
||||
return reinterpret_cast<const type&>(value);
|
||||
}
|
||||
|
||||
force_inline static type& to_type(subtype& value)
|
||||
{
|
||||
return reinterpret_cast<type&>(value);
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename T2> force_inline static void write_relaxed(volatile T2& data, const T2& value)
|
||||
{
|
||||
data = value;
|
||||
}
|
||||
|
||||
force_inline static void write_relaxed(volatile u128& data, const u128& value)
|
||||
{
|
||||
sync_lock_test_and_set(&data, value);
|
||||
}
|
||||
|
||||
template<typename T2> force_inline static T2 read_relaxed(const volatile T2& data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
force_inline static u128 read_relaxed(const volatile u128& value)
|
||||
{
|
||||
return sync_val_compare_and_swap(const_cast<volatile u128*>(&value), u128{0}, u128{0});
|
||||
}
|
||||
|
||||
public:
|
||||
// atomically compare data with cmp, replace with exch if equal, return previous data value anyway
|
||||
force_inline const type compare_and_swap(const type& cmp, const type& exch) volatile
|
||||
{
|
||||
return from_subtype(sync_val_compare_and_swap(&sub_data, to_subtype(cmp), to_subtype(exch)));
|
||||
}
|
||||
|
||||
// atomically compare data with cmp, replace with exch if equal, return true if data was replaced
|
||||
force_inline bool compare_and_swap_test(const type& cmp, const type& exch) volatile
|
||||
{
|
||||
return sync_bool_compare_and_swap(&sub_data, to_subtype(cmp), to_subtype(exch));
|
||||
}
|
||||
|
||||
// read data with memory barrier
|
||||
force_inline const type load_sync() const volatile
|
||||
{
|
||||
const subtype zero = {};
|
||||
return from_subtype(sync_val_compare_and_swap(const_cast<subtype*>(&sub_data), zero, zero));
|
||||
}
|
||||
|
||||
// atomically replace data with exch, return previous data value
|
||||
force_inline const type exchange(const type& exch) volatile
|
||||
{
|
||||
return from_subtype(sync_lock_test_and_set(&sub_data, to_subtype(exch)));
|
||||
}
|
||||
|
||||
// read data without memory barrier (works as load_sync() for 128 bit)
|
||||
force_inline const type load() const volatile
|
||||
{
|
||||
return from_subtype(read_relaxed(sub_data));
|
||||
}
|
||||
|
||||
// write data without memory barrier (works as exchange() for 128 bit, discarding result)
|
||||
force_inline void store(const type& value) volatile
|
||||
{
|
||||
write_relaxed(sub_data, to_subtype(value));
|
||||
}
|
||||
|
||||
// perform an atomic operation on data (func is either pointer to member function or callable object with a T& first arg);
|
||||
// returns the result of the callable object call or previous (old) value of the atomic variable if the return type is void
|
||||
template<typename F, typename... Args, typename RT = std::result_of_t<F(T&, Args...)>> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t<F, RT, T>::result)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// read the old value from memory
|
||||
const subtype old = read_relaxed(sub_data);
|
||||
|
||||
// copy the old value
|
||||
subtype _new = old;
|
||||
|
||||
// call atomic op for the local copy of the old value and save the return value of the function
|
||||
atomic_op_result_t<F, RT, T> result(func, to_type(_new), args...);
|
||||
|
||||
// atomically compare value with `old`, replace with `_new` and return on success
|
||||
if (sync_bool_compare_and_swap(&sub_data, old, _new)) return result.move();
|
||||
}
|
||||
}
|
||||
|
||||
// atomic bitwise OR, returns previous data
|
||||
force_inline const type _or(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_or(&sub_data, to_subtype(right)));
|
||||
}
|
||||
|
||||
// atomic bitwise AND, returns previous data
|
||||
force_inline const type _and(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_and(&sub_data, to_subtype(right)));
|
||||
}
|
||||
|
||||
// atomic bitwise AND NOT (inverts right argument), returns previous data
|
||||
force_inline const type _and_not(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_and(&sub_data, ~to_subtype(right)));
|
||||
}
|
||||
|
||||
// atomic bitwise XOR, returns previous data
|
||||
force_inline const type _xor(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_xor(&sub_data, to_subtype(right)));
|
||||
}
|
||||
|
||||
force_inline const type operator |=(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_or(&sub_data, to_subtype(right)) | to_subtype(right));
|
||||
}
|
||||
|
||||
force_inline const type operator &=(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_and(&sub_data, to_subtype(right)) & to_subtype(right));
|
||||
}
|
||||
|
||||
force_inline const type operator ^=(const type& right) volatile
|
||||
{
|
||||
return from_subtype(sync_fetch_and_xor(&sub_data, to_subtype(right)) ^ to_subtype(right));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline T operator ++(_atomic_base<T>& left)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1) + 1);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline T operator --(_atomic_base<T>& left)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1) - 1);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline T operator ++(_atomic_base<T>& left, int)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1));
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline T operator --(_atomic_base<T>& left, int)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1));
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<T>& left, T2 right) -> decltype(std::declval<T>() + std::declval<T2>())
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, right) + right);
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<T>& left, T2 right) -> decltype(std::declval<T>() - std::declval<T2>())
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, right) - right);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator ++(_atomic_base<le_t<T>>& left)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1) + 1);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator --(_atomic_base<le_t<T>>& left)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1) - 1);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator ++(_atomic_base<le_t<T>>& left, int)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, 1));
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline le_t<T> operator --(_atomic_base<le_t<T>>& left, int)
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, 1));
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<le_t<T>>& left, T2 right) -> decltype(std::declval<T>() + std::declval<T2>())
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_add(&left.sub_data, right) + right);
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<le_t<T>>& left, T2 right) -> decltype(std::declval<T>() - std::declval<T2>())
|
||||
{
|
||||
return left.from_subtype(sync_fetch_and_sub(&left.sub_data, right) - right);
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator ++(_atomic_base<be_t<T>>& left)
|
||||
{
|
||||
return left.atomic_op([](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return ++value;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator --(_atomic_base<be_t<T>>& left)
|
||||
{
|
||||
return left.atomic_op([](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return --value;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator ++(_atomic_base<be_t<T>>& left, int)
|
||||
{
|
||||
return left.atomic_op([](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return value++;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename = if_integral_t<T>> inline be_t<T> operator --(_atomic_base<be_t<T>>& left, int)
|
||||
{
|
||||
return left.atomic_op([](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return value--;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator +=(_atomic_base<be_t<T>>& left, T2 right) -> be_t<decltype(std::declval<T>() + std::declval<T2>())>
|
||||
{
|
||||
return left.atomic_op([right](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return value += right;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename T2, typename = if_integral_t<T>> inline auto operator -=(_atomic_base<be_t<T>>& left, T2 right) -> be_t<decltype(std::declval<T>() - std::declval<T2>())>
|
||||
{
|
||||
return left.atomic_op([right](be_t<T>& value) -> be_t<T>
|
||||
{
|
||||
return value -= right;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T> using atomic_t = _atomic_base<T>; // Atomic Type with native endianness (for emulator memory)
|
||||
|
||||
template<typename T> using atomic_be_t = _atomic_base<to_be_t<T>>; // Atomic BE Type (for PS3 virtual memory)
|
||||
|
||||
template<typename T> using atomic_le_t = _atomic_base<to_le_t<T>>; // Atomic LE Type (for PSV virtual memory)
|
||||
|
|
@ -77,7 +77,7 @@ namespace vm
|
|||
void* const g_base_addr = (atexit(finalize), initialize());
|
||||
void* g_priv_addr;
|
||||
|
||||
std::array<atomic_t<u8>, 0x100000000ull / 4096> g_pages = {}; // information about every page
|
||||
std::array<atomic_t<u8>, 0x100000000ull / 4096> g_pages{}; // information about every page
|
||||
|
||||
const thread_ctrl_t* const INVALID_THREAD = reinterpret_cast<const thread_ctrl_t*>(~0ull);
|
||||
|
||||
|
|
@ -85,16 +85,11 @@ namespace vm
|
|||
|
||||
class reservation_mutex_t
|
||||
{
|
||||
atomic_t<const thread_ctrl_t*> m_owner;
|
||||
atomic_t<const thread_ctrl_t*> m_owner{ INVALID_THREAD };
|
||||
std::condition_variable m_cv;
|
||||
std::mutex m_mutex;
|
||||
|
||||
public:
|
||||
reservation_mutex_t()
|
||||
{
|
||||
m_owner.store(INVALID_THREAD);
|
||||
}
|
||||
|
||||
bool do_notify = false;
|
||||
|
||||
never_inline void lock()
|
||||
|
|
@ -105,7 +100,7 @@ namespace vm
|
|||
|
||||
while (!m_owner.compare_and_swap_test(INVALID_THREAD, owner))
|
||||
{
|
||||
if (m_owner.load() == owner)
|
||||
if (m_owner == owner)
|
||||
{
|
||||
throw EXCEPTION("Deadlock");
|
||||
}
|
||||
|
|
@ -423,7 +418,7 @@ namespace vm
|
|||
throw EXCEPTION("Invalid arguments (addr=0x%x, size=0x%x)", addr, size);
|
||||
}
|
||||
|
||||
const u8 flags = g_pages[addr >> 12].load();
|
||||
const u8 flags = g_pages[addr >> 12];
|
||||
|
||||
if (!(flags & page_writable) || !(flags & page_allocated) || (flags & page_no_reservations))
|
||||
{
|
||||
|
|
@ -587,7 +582,7 @@ namespace vm
|
|||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
if (g_pages[i].load())
|
||||
if (g_pages[i])
|
||||
{
|
||||
throw EXCEPTION("Memory already mapped (addr=0x%x, size=0x%x, flags=0x%x, current_addr=0x%x)", addr, size, flags, i * 4096);
|
||||
}
|
||||
|
|
@ -630,7 +625,7 @@ namespace vm
|
|||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
if ((g_pages[i].load() & flags_test) != (flags_test | page_allocated))
|
||||
if ((g_pages[i] & flags_test) != (flags_test | page_allocated))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -677,7 +672,7 @@ namespace vm
|
|||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
if (!(g_pages[i].load() & page_allocated))
|
||||
if ((g_pages[i] & page_allocated) == 0)
|
||||
{
|
||||
throw EXCEPTION("Memory not mapped (addr=0x%x, size=0x%x, current_addr=0x%x)", addr, size, i * 4096);
|
||||
}
|
||||
|
|
@ -719,7 +714,7 @@ namespace vm
|
|||
|
||||
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
||||
{
|
||||
if ((g_pages[i].load() & page_allocated) != page_allocated)
|
||||
if ((g_pages[i] & page_allocated) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -788,7 +783,7 @@ namespace vm
|
|||
// check if memory area is already mapped
|
||||
for (u32 i = addr / 4096; i <= (addr + size - 1) / 4096; i++)
|
||||
{
|
||||
if (g_pages[i].load())
|
||||
if (g_pages[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -862,7 +857,7 @@ namespace vm
|
|||
return addr;
|
||||
}
|
||||
|
||||
if (used.load() + size > this->size)
|
||||
if (used + size > this->size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -941,7 +936,7 @@ namespace vm
|
|||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
{
|
||||
if (g_pages[i].load())
|
||||
if (g_pages[i])
|
||||
{
|
||||
throw EXCEPTION("Unexpected pages allocated (current_addr=0x%x)", i * 4096);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,19 +269,11 @@ namespace vm
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T> struct cast_ptr<be_t<T>>
|
||||
template<typename T, bool Se> struct cast_ptr<se_t<T, Se>>
|
||||
{
|
||||
force_inline static u32 cast(const be_t<T>& addr, const char* file, int line, const char* func)
|
||||
force_inline static u32 cast(const se_t<T, Se>& addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return cast_ptr<T>::cast(addr.value(), file, line, func);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct cast_ptr<le_t<T>>
|
||||
{
|
||||
force_inline static u32 cast(const le_t<T>& addr, const char* file, int line, const char* func)
|
||||
{
|
||||
return cast_ptr<T>::cast(addr.value(), file, line, func);
|
||||
return cast_ptr<T>::cast(addr, file, line, func);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue