diff --git a/Utilities/Atomic.h b/Utilities/Atomic.h new file mode 100644 index 0000000000..e0656b674b --- /dev/null +++ b/Utilities/Atomic.h @@ -0,0 +1,717 @@ +#pragma once + +#if defined(__GNUG__) + +template inline std::enable_if_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +{ + return __sync_val_compare_and_swap(dest, comp, exch); +} + +template inline std::enable_if_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) +{ + return __sync_bool_compare_and_swap(dest, comp, exch); +} + +template inline std::enable_if_t sync_lock_test_and_set(volatile T* dest, T2 value) +{ + return __sync_lock_test_and_set(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_add(volatile T* dest, T2 value) +{ + return __sync_fetch_and_add(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_sub(volatile T* dest, T2 value) +{ + return __sync_fetch_and_sub(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_or(volatile T* dest, T2 value) +{ + return __sync_fetch_and_or(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_and(volatile T* dest, T2 value) +{ + return __sync_fetch_and_and(dest, value); +} + +template inline std::enable_if_t sync_fetch_and_xor(volatile T* dest, T2 value) +{ + return __sync_fetch_and_xor(dest, value); +} + +#elif defined(_MSC_VER) + +// atomic compare and swap functions + +inline u8 sync_val_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) +{ + return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); +} + +inline u16 sync_val_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) +{ + return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); +} + +inline u32 sync_val_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) +{ + return _InterlockedCompareExchange((volatile long*)dest, exch, comp); +} + +inline u64 sync_val_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) +{ + return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); +} + +inline u128 sync_val_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) +{ + _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); + return comp; +} + +inline bool sync_bool_compare_and_swap(volatile u8* dest, u8 comp, u8 exch) +{ + return (u8)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u16* dest, u16 comp, u16 exch) +{ + return (u16)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u32* dest, u32 comp, u32 exch) +{ + return (u32)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u64* dest, u64 comp, u64 exch) +{ + return (u64)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; +} + +inline bool sync_bool_compare_and_swap(volatile u128* dest, u128 comp, u128 exch) +{ + return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; +} + +// atomic exchange functions + +inline u8 sync_lock_test_and_set(volatile u8* dest, u8 value) +{ + return _InterlockedExchange8((volatile char*)dest, value); +} + +inline u16 sync_lock_test_and_set(volatile u16* dest, u16 value) +{ + return _InterlockedExchange16((volatile short*)dest, value); +} + +inline u32 sync_lock_test_and_set(volatile u32* dest, u32 value) +{ + return _InterlockedExchange((volatile long*)dest, value); +} + +inline u64 sync_lock_test_and_set(volatile u64* dest, u64 value) +{ + return _InterlockedExchange64((volatile long long*)dest, value); +} + +inline u128 sync_lock_test_and_set(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + if (sync_bool_compare_and_swap(dest, old, value)) return old; + } +} + +// atomic add functions + +inline u8 sync_fetch_and_add(volatile u8* dest, u8 value) +{ + return _InterlockedExchangeAdd8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_add(volatile u16* dest, u16 value) +{ + return _InterlockedExchangeAdd16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_add(volatile u32* dest, u32 value) +{ + return _InterlockedExchangeAdd((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_add(volatile u64* dest, u64 value) +{ + return _InterlockedExchangeAdd64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_add(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo + value.lo; + _new.hi = old.hi + value.hi + (_new.lo < value.lo); + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic sub functions + +inline u8 sync_fetch_and_sub(volatile u8* dest, u8 value) +{ + return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); +} + +inline u16 sync_fetch_and_sub(volatile u16* dest, u16 value) +{ + return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); +} + +inline u32 sync_fetch_and_sub(volatile u32* dest, u32 value) +{ + return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); +} + +inline u64 sync_fetch_and_sub(volatile u64* dest, u64 value) +{ + return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); +} + +inline u128 sync_fetch_and_sub(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo - value.lo; + _new.hi = old.hi - value.hi - (old.lo < value.lo); + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise or` functions + +inline u8 sync_fetch_and_or(volatile u8* dest, u8 value) +{ + return _InterlockedOr8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_or(volatile u16* dest, u16 value) +{ + return _InterlockedOr16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_or(volatile u32* dest, u32 value) +{ + return _InterlockedOr((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_or(volatile u64* dest, u64 value) +{ + return _InterlockedOr64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_or(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo | value.lo; + _new.hi = old.hi | value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise and` functions + +inline u8 sync_fetch_and_and(volatile u8* dest, u8 value) +{ + return _InterlockedAnd8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_and(volatile u16* dest, u16 value) +{ + return _InterlockedAnd16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_and(volatile u32* dest, u32 value) +{ + return _InterlockedAnd((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_and(volatile u64* dest, u64 value) +{ + return _InterlockedAnd64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_and(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo & value.lo; + _new.hi = old.hi & value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +// atomic `bitwise xor` functions + +inline u8 sync_fetch_and_xor(volatile u8* dest, u8 value) +{ + return _InterlockedXor8((volatile char*)dest, value); +} + +inline u16 sync_fetch_and_xor(volatile u16* dest, u16 value) +{ + return _InterlockedXor16((volatile short*)dest, value); +} + +inline u32 sync_fetch_and_xor(volatile u32* dest, u32 value) +{ + return _InterlockedXor((volatile long*)dest, value); +} + +inline u64 sync_fetch_and_xor(volatile u64* dest, u64 value) +{ + return _InterlockedXor64((volatile long long*)dest, value); +} + +inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value) +{ + while (true) + { + u128 old; + old.lo = dest->lo; + old.hi = dest->hi; + + u128 _new; + _new.lo = old.lo ^ value.lo; + _new.hi = old.hi ^ value.hi; + + if (sync_bool_compare_and_swap(dest, old, _new)) return old; + } +} + +#endif /* _MSC_VER */ + +template struct atomic_storage +{ + static_assert(!Size, "Invalid atomic type"); +}; + +template struct atomic_storage +{ + using type = u8; +}; + +template struct atomic_storage +{ + using type = u16; +}; + +template struct atomic_storage +{ + using type = u32; +}; + +template struct atomic_storage +{ + using type = u64; +}; + +template struct atomic_storage +{ + using type = u128; +}; + +template using atomic_storage_t = typename atomic_storage::type; + +// result wrapper to deal with void result type +template struct atomic_op_result_t +{ + RT result; + + template inline atomic_op_result_t(T func, VT& var, Args&&... args) + : result(std::move(func(var, std::forward(args)...))) + { + } + + inline RT move() + { + return std::move(result); + } +}; + +// void specialization: result is the initial value of the first arg +template struct atomic_op_result_t +{ + VT result; + + template inline atomic_op_result_t(T func, VT& var, Args&&... args) + : result(var) + { + func(var, std::forward(args)...); + } + + inline VT move() + { + return std::move(result); + } +}; + +// member function specialization +template struct atomic_op_result_t +{ + RT result; + + template inline atomic_op_result_t(RT(CT::*func)(FArgs...), VT& var, Args&&... args) + : result(std::move((var.*func)(std::forward(args)...))) + { + } + + inline RT move() + { + return std::move(result); + } +}; + +// member function void specialization +template struct atomic_op_result_t +{ + VT result; + + template inline atomic_op_result_t(void(CT::*func)(FArgs...), VT& var, Args&&... args) + : result(var) + { + (var.*func)(std::forward(args)...); + } + + inline VT move() + { + return std::move(result); + } +}; + +template class atomic_t +{ + using type = std::remove_cv_t; + using stype = atomic_storage_t; + using storage = atomic_storage; + + static_assert(alignof(type) <= alignof(stype), "atomic_t<> error: unexpected alignment"); + + stype m_data; + + template static inline void write_relaxed(volatile T2& data, const T2& value) + { + data = value; + } + + static inline void write_relaxed(volatile u128& data, const u128& value) + { + sync_lock_test_and_set(&data, value); + } + + template static inline T2 read_relaxed(const volatile T2& data) + { + return data; + } + + static inline u128 read_relaxed(const volatile u128& value) + { + return sync_val_compare_and_swap(const_cast(&value), u128{0}, u128{0}); + } + +public: + static inline const stype to_subtype(const type& value) + { + return reinterpret_cast(value); + } + + static inline const type from_subtype(const stype value) + { + return reinterpret_cast(value); + } + + atomic_t() = default; + + atomic_t(const atomic_t&) = delete; + + atomic_t(atomic_t&&) = delete; + + inline atomic_t(type value) + : m_data(to_subtype(value)) + { + } + + atomic_t& operator =(const atomic_t&) = delete; + + atomic_t& operator =(atomic_t&&) = delete; + + inline atomic_t& operator =(type value) + { + return write_relaxed(m_data, to_subtype(value)), *this; + } + + operator type() const volatile + { + return from_subtype(read_relaxed(m_data)); + } + + // Unsafe direct access + stype* raw_data() + { + return reinterpret_cast(&m_data); + } + + // Unsafe direct access + type& raw() + { + return reinterpret_cast(m_data); + } + + // Atomically compare data with cmp, replace with exch if equal, return previous data value anyway + inline const type compare_and_swap(const type& cmp, const type& exch) volatile + { + return from_subtype(sync_val_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch))); + } + + // Atomically compare data with cmp, replace with exch if equal, return true if data was replaced + inline bool compare_and_swap_test(const type& cmp, const type& exch) volatile + { + return sync_bool_compare_and_swap(&m_data, to_subtype(cmp), to_subtype(exch)); + } + + // Atomically replace data with exch, return previous data value + inline const type exchange(const type& exch) volatile + { + return from_subtype(sync_lock_test_and_set(&m_data, to_subtype(exch))); + } + + // Atomically read data, possibly without memory barrier (not for 128 bit) + inline const type load() const volatile + { + return from_subtype(read_relaxed(m_data)); + } + + // Atomically write data, possibly without memory barrier (not for 128 bit) + inline void store(const type& value) volatile + { + write_relaxed(m_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> auto atomic_op(F func, Args&&... args) volatile -> decltype(atomic_op_result_t::result) + { + while (true) + { + // Read the old value from memory + const stype old = read_relaxed(m_data); + + // Copy the old value + stype _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 result(func, reinterpret_cast(_new), args...); + + // Atomically compare value with `old`, replace with `_new` and return on success + if (sync_bool_compare_and_swap(&m_data, old, _new)) return result.move(); + } + } + + // Atomic bitwise OR, returns previous data + inline const type _or(const type& right) volatile + { + return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right))); + } + + // Atomic bitwise AND, returns previous data + inline const type _and(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right))); + } + + // Atomic bitwise AND NOT (inverts right argument), returns previous data + inline const type _and_not(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, ~to_subtype(right))); + } + + // Atomic bitwise XOR, returns previous data + inline const type _xor(const type& right) volatile + { + return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right))); + } + + inline const type operator |=(const type& right) volatile + { + return from_subtype(sync_fetch_and_or(&m_data, to_subtype(right)) | to_subtype(right)); + } + + inline const type operator &=(const type& right) volatile + { + return from_subtype(sync_fetch_and_and(&m_data, to_subtype(right)) & to_subtype(right)); + } + + inline const type operator ^=(const type& right) volatile + { + return from_subtype(sync_fetch_and_xor(&m_data, to_subtype(right)) ^ to_subtype(right)); + } +}; + +template inline std::enable_if_t operator ++(atomic_t& left) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); +} + +template inline std::enable_if_t operator --(atomic_t& left) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); +} + +template inline std::enable_if_t operator ++(atomic_t& left, int) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); +} + +template inline std::enable_if_t operator --(atomic_t& left, int) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); +} + +template inline std::enable_if_t::value, T> operator +=(atomic_t& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); +} + +template inline std::enable_if_t::value, T> operator -=(atomic_t& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1) + 1); +} + +template inline std::enable_if_t> operator --(atomic_t>& left) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1) - 1); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left, int) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), 1)); +} + +template inline std::enable_if_t> operator --(atomic_t>& left, int) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), 1)); +} + +template inline std::enable_if_t::value, nse_t> operator +=(atomic_t>& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_add(left.raw_data(), right) + right); +} + +template inline std::enable_if_t::value, nse_t> operator -=(atomic_t>& left, const T2& right) +{ + return left.from_subtype(sync_fetch_and_sub(left.raw_data(), right) - right); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return ++value; + }); +} + +template inline std::enable_if_t> operator --(atomic_t>& left) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return --value; + }); +} + +template inline std::enable_if_t> operator ++(atomic_t>& left, int) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return value++; + }); +} + +template inline std::enable_if_t> operator --(atomic_t>& left, int) +{ + return left.atomic_op([](se_t& value) -> se_t + { + return value--; + }); +} + +template inline std::enable_if_t::value, se_t> operator +=(atomic_t>& left, const T2& right) +{ + return left.atomic_op([&](se_t& value) -> se_t + { + return value += right; + }); +} + +template inline std::enable_if_t::value, se_t> operator -=(atomic_t>& left, const T2& right) +{ + return left.atomic_op([&](se_t& value) -> se_t + { + return value -= right; + }); +} + +template using atomic_be_t = atomic_t>; // Atomic BE Type (for PS3 virtual memory) + +template using atomic_le_t = atomic_t>; // Atomic LE Type (for PSV virtual memory) + +// Algorithm for std::atomic; similar to atomic_t::atomic_op() +template> auto atomic_op(std::atomic& var, F func, Args&&... args) -> decltype(atomic_op_result_t::result) +{ + auto old = var.load(); + + while (true) + { + auto _new = old; + + atomic_op_result_t result(func, _new, args...); + + if (var.compare_exchange_strong(old, _new)) return result.move(); + } +} diff --git a/Utilities/BEType.h b/Utilities/BEType.h index e317bee226..916b52eb64 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -374,9 +374,6 @@ inline v128 operator ~(const v128& other) return v128::from64(~other._u64[0], ~other._u64[1]); } -#define IS_INTEGER(t) (std::is_integral::value || std::is_enum::value) -#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2)) - template struct se_storage { static_assert(!Size, "Bad se_storage<> type"); @@ -386,7 +383,7 @@ template struct se_storage { using type = u16; - static constexpr u16 swap(u16 src) + [[deprecated]] static constexpr u16 swap(u16 src) // for reference { return (src >> 8) | (src << 8); } @@ -407,7 +404,7 @@ template struct se_storage { using type = u32; - static constexpr u32 swap(u32 src) + [[deprecated]] static constexpr u32 swap(u32 src) // for reference { return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000); } @@ -428,7 +425,7 @@ template struct se_storage { using type = u64; - static constexpr u64 swap(u64 src) + [[deprecated]] static constexpr u64 swap(u64 src) // for reference { return (src >> 56) | (src << 56) | ((src >> 40) & 0x000000000000ff00) | @@ -491,7 +488,10 @@ template struct se_convert static struct se_raw_tag_t {} const se_raw{}; -template class se_t +template class se_t; + +// se_t with switched endianness +template class se_t { using type = std::remove_cv_t; using stype = se_storage_t; @@ -506,16 +506,32 @@ template class se_t static_assert(!std::is_enum::value, "se_t<> error: invalid type (enumeration), use integral type instead"); static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment"); + template::value> struct bool_converter + { + static inline bool to_bool(const se_t& value) + { + return static_cast(value.value()); + } + }; + + template struct bool_converter + { + static inline bool to_bool(const se_t& value) + { + return value.m_data != 0; + } + }; + public: se_t() = default; se_t(const se_t& right) = default; - template::value && !std::is_same, std::decay_t>::value>> inline se_t(const CT& value) + inline se_t(type value) : m_data(storage::to(value)) { } - + // construct directly from raw data (don't use) inline se_t(const stype& raw_value, const se_raw_tag_t&) : m_data(raw_value) @@ -528,29 +544,27 @@ public: } // access underlying raw data (don't use) - inline const stype& raw_data() const + inline const stype& raw_data() const noexcept { return m_data; } se_t& operator =(const se_t&) = default; - template inline std::enable_if_t::value && !std::is_same, std::decay_t>::value, se_t&> operator =(const CT& value) + inline se_t& operator =(type value) { return m_data = storage::to(value), *this; } inline operator type() const { - return value(); + return storage::from(m_data); } // optimization explicit inline operator bool() const { - static_assert(std::is_convertible::value, "Illegal conversion to bool"); - - return m_data != 0; + return bool_converter::to_bool(*this); } // optimization @@ -560,7 +574,7 @@ public: } // optimization - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator &=(CT right) { return m_data &= storage::to(right), *this; } @@ -572,7 +586,7 @@ public: } // optimization - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator |=(CT right) { return m_data |= storage::to(right), *this; } @@ -584,12 +598,13 @@ public: } // optimization - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator ^=(CT right) { return m_data ^= storage::to(right), *this; } }; +// se_t with native endianness template class se_t { using type = std::remove_cv_t; @@ -607,8 +622,8 @@ public: se_t(const se_t&) = default; - template::value && !std::is_same, std::decay_t>::value>> inline se_t(CT&& value) - : m_data(std::forward(value)) + inline se_t(type value) + : m_data(value) { } @@ -619,32 +634,35 @@ public: se_t& operator =(const se_t& value) = default; - template inline std::enable_if_t::value && !std::is_same, std::decay_t>::value, se_t&> operator =(const CT& value) + inline se_t& operator =(type value) { return m_data = value, *this; } inline operator type() const { - return value(); + return m_data; } - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator &=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator &=(const CT& right) { return m_data &= right, *this; } - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator |=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator |=(const CT& right) { return m_data |= right, *this; } - template inline std::enable_if_t::value && std::is_convertible::value, se_t&> operator ^=(const CT& right) + template inline std::enable_if_t::value, se_t&> operator ^=(const CT& right) { return m_data ^= right, *this; } }; +// se_t with native endianness (alias) +template using nse_t = se_t; + template inline se_t& operator +=(se_t& left, const T1& right) { auto value = left.value(); @@ -722,15 +740,15 @@ template inline std::enable_if_t inline std::enable_if_t operator ==(const se_t& left, const T2& right) +template inline std::enable_if_t= sizeof(T2), bool> operator ==(const se_t& left, T2 right) { - return left.raw_data() == se_storage::to(right); + return left.raw_data() == se_storage::to(right); } // optimization -template inline std::enable_if_t operator ==(const T1& left, const se_t& right) +template inline std::enable_if_t operator ==(T1 left, const se_t& right) { - return se_storage::to(left) == right.raw_data(); + return se_storage::to(left) == right.raw_data(); } // optimization @@ -740,75 +758,75 @@ template inline std::enable_if_t inline std::enable_if_t operator !=(const se_t& left, const T2& right) +template inline std::enable_if_t= sizeof(T2), bool> operator !=(const se_t& left, T2 right) { - return left.raw_data() != se_storage::to(right); + return left.raw_data() != se_storage::to(right); } // optimization -template inline std::enable_if_t operator !=(const T1& left, const se_t& right) +template inline std::enable_if_t operator !=(T1 left, const se_t& right) { - return se_storage::to(left) != right.raw_data(); + return se_storage::to(left) != right.raw_data(); } // optimization template inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const se_t& right) { - return{ static_cast>(left.raw_data() & right.raw_data()), se_raw }; + return{ left.raw_data() & right.raw_data(), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator &(const se_t& left, const T2& right) +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator &(const se_t& left, T2 right) { - return{ static_cast>(left.raw_data() & se_storage::to(right)), se_raw }; + return{ left.raw_data() & se_storage::to(right), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator &(const T1& left, const se_t& right) +template inline std::enable_if_t= 4, se_t> operator &(T1 left, const se_t& right) { - return{ static_cast>(se_storage::to(left) & right.raw_data()), se_raw }; + return{ se_storage::to(left) & right.raw_data(), se_raw }; } // optimization template inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const se_t& right) { - return{ static_cast>(left.raw_data() | right.raw_data()), se_raw }; + return{ left.raw_data() | right.raw_data(), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator |(const se_t& left, const T2& right) +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator |(const se_t& left, T2 right) { - return{ static_cast>(left.raw_data() | se_storage::to(right)), se_raw }; + return{ left.raw_data() | se_storage::to(right), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator |(const T1& left, const se_t& right) +template inline std::enable_if_t= 4, se_t> operator |(T1 left, const se_t& right) { - return{ static_cast>(se_storage::to(left) | right.raw_data()), se_raw }; + return{ se_storage::to(left) | right.raw_data(), se_raw }; } // optimization template inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const se_t& right) { - return{ static_cast>(left.raw_data() ^ right.raw_data()), se_raw }; + return{ left.raw_data() ^ right.raw_data(), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator ^(const se_t& left, const T2& right) +template inline std::enable_if_t= sizeof(T2) && sizeof(T1) >= 4, se_t> operator ^(const se_t& left, T2 right) { - return{ static_cast>(left.raw_data() ^ se_storage::to(right)), se_raw }; + return{ left.raw_data() ^ se_storage::to(right), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator ^(const T1& left, const se_t& right) +template inline std::enable_if_t= 4, se_t> operator ^(T1 left, const se_t& right) { - return{ static_cast>(se_storage::to(left) ^ right.raw_data()), se_raw }; + return{ se_storage::to(left) ^ right.raw_data(), se_raw }; } // optimization -template inline std::enable_if_t= 4, se_t> operator ~(const se_t& right) +template inline std::enable_if_t= 4, se_t> operator ~(const se_t& right) { - return{ static_cast>(~right.raw_data()), se_raw }; + return{ ~right.raw_data(), se_raw }; } #ifdef IS_LE_MACHINE diff --git a/Utilities/GNU.h b/Utilities/GNU.h index 04bcbce45b..c8d5c74cb4 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -232,334 +232,6 @@ struct alignas(16) uint128_t using __uint128_t = uint128_t; #endif -// SFINAE Helper type -template using if_integral_t = std::enable_if_t::value || std::is_same, __uint128_t>::value, TT>; - -#if defined(__GNUG__) - -template inline if_integral_t sync_val_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_val_compare_and_swap(dest, comp, exch); -} - -template inline if_integral_t sync_bool_compare_and_swap(volatile T* dest, T2 comp, T2 exch) -{ - return __sync_bool_compare_and_swap(dest, comp, exch); -} - -template inline if_integral_t sync_lock_test_and_set(volatile T* dest, T2 value) -{ - return __sync_lock_test_and_set(dest, value); -} - -template inline if_integral_t sync_fetch_and_add(volatile T* dest, T2 value) -{ - return __sync_fetch_and_add(dest, value); -} - -template inline if_integral_t sync_fetch_and_sub(volatile T* dest, T2 value) -{ - return __sync_fetch_and_sub(dest, value); -} - -template inline if_integral_t sync_fetch_and_or(volatile T* dest, T2 value) -{ - return __sync_fetch_and_or(dest, value); -} - -template inline if_integral_t sync_fetch_and_and(volatile T* dest, T2 value) -{ - return __sync_fetch_and_and(dest, value); -} - -template inline if_integral_t sync_fetch_and_xor(volatile T* dest, T2 value) -{ - return __sync_fetch_and_xor(dest, value); -} - -#endif /* __GNUG__ */ - -#if defined(_MSC_VER) - -// atomic compare and swap functions - -inline uint8_t sync_val_compare_and_swap(volatile uint8_t* dest, uint8_t comp, uint8_t exch) -{ - return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); -} - -inline uint16_t sync_val_compare_and_swap(volatile uint16_t* dest, uint16_t comp, uint16_t exch) -{ - return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); -} - -inline uint32_t sync_val_compare_and_swap(volatile uint32_t* dest, uint32_t comp, uint32_t exch) -{ - return _InterlockedCompareExchange((volatile long*)dest, exch, comp); -} - -inline uint64_t sync_val_compare_and_swap(volatile uint64_t* dest, uint64_t comp, uint64_t exch) -{ - return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); -} - -inline uint128_t sync_val_compare_and_swap(volatile uint128_t* dest, uint128_t comp, uint128_t exch) -{ - _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp); - return comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint8_t* dest, uint8_t comp, uint8_t exch) -{ - return (uint8_t)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint16_t* dest, uint16_t comp, uint16_t exch) -{ - return (uint16_t)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint32_t* dest, uint32_t comp, uint32_t exch) -{ - return (uint32_t)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint64_t* dest, uint64_t comp, uint64_t exch) -{ - return (uint64_t)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; -} - -inline bool sync_bool_compare_and_swap(volatile uint128_t* dest, uint128_t comp, uint128_t exch) -{ - return _InterlockedCompareExchange128((volatile long long*)dest, exch.hi, exch.lo, (long long*)&comp) != 0; -} - -// atomic exchange functions - -inline uint8_t sync_lock_test_and_set(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchange8((volatile char*)dest, value); -} - -inline uint16_t sync_lock_test_and_set(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchange16((volatile short*)dest, value); -} - -inline uint32_t sync_lock_test_and_set(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchange((volatile long*)dest, value); -} - -inline uint64_t sync_lock_test_and_set(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchange64((volatile long long*)dest, value); -} - -inline uint128_t sync_lock_test_and_set(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - if (sync_bool_compare_and_swap(dest, old, value)) return old; - } -} - -// atomic add functions - -inline uint8_t sync_fetch_and_add(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_add(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_add(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_add(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_add(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo + value.lo; - _new.hi = old.hi + value.hi + (_new.lo < value.lo); - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic sub functions - -inline uint8_t sync_fetch_and_sub(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedExchangeAdd8((volatile char*)dest, -(char)value); -} - -inline uint16_t sync_fetch_and_sub(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedExchangeAdd16((volatile short*)dest, -(short)value); -} - -inline uint32_t sync_fetch_and_sub(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedExchangeAdd((volatile long*)dest, -(long)value); -} - -inline uint64_t sync_fetch_and_sub(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedExchangeAdd64((volatile long long*)dest, -(long long)value); -} - -inline uint128_t sync_fetch_and_sub(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo - value.lo; - _new.hi = old.hi - value.hi - (old.lo < value.lo); - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise or` functions - -inline uint8_t sync_fetch_and_or(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedOr8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_or(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedOr16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_or(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedOr((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_or(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedOr64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_or(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo | value.lo; - _new.hi = old.hi | value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise and` functions - -inline uint8_t sync_fetch_and_and(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedAnd8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_and(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedAnd16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_and(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedAnd((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_and(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedAnd64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_and(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo & value.lo; - _new.hi = old.hi & value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -// atomic `bitwise xor` functions - -inline uint8_t sync_fetch_and_xor(volatile uint8_t* dest, uint8_t value) -{ - return _InterlockedXor8((volatile char*)dest, value); -} - -inline uint16_t sync_fetch_and_xor(volatile uint16_t* dest, uint16_t value) -{ - return _InterlockedXor16((volatile short*)dest, value); -} - -inline uint32_t sync_fetch_and_xor(volatile uint32_t* dest, uint32_t value) -{ - return _InterlockedXor((volatile long*)dest, value); -} - -inline uint64_t sync_fetch_and_xor(volatile uint64_t* dest, uint64_t value) -{ - return _InterlockedXor64((volatile long long*)dest, value); -} - -inline uint128_t sync_fetch_and_xor(volatile uint128_t* dest, uint128_t value) -{ - while (true) - { - uint128_t old; - old.lo = dest->lo; - old.hi = dest->hi; - - uint128_t _new; - _new.lo = old.lo ^ value.lo; - _new.hi = old.hi ^ value.hi; - - if (sync_bool_compare_and_swap(dest, old, _new)) return old; - } -} - -#endif /* _MSC_VER */ - inline uint32_t cntlz32(uint32_t arg) { #if defined(_MSC_VER) diff --git a/Utilities/Semaphore.h b/Utilities/Semaphore.h index 03d3a77168..8ed96f4275 100644 --- a/Utilities/Semaphore.h +++ b/Utilities/Semaphore.h @@ -22,7 +22,7 @@ public: const u32 max_value; semaphore_t(u32 max_value = 1, u32 value = 0) - : m_var({ value, 0 }) + : m_var(sync_var_t{ value, 0 }) , max_value(max_value) { } diff --git a/Utilities/SharedMutex.cpp b/Utilities/SharedMutex.cpp new file mode 100644 index 0000000000..9394fde020 --- /dev/null +++ b/Utilities/SharedMutex.cpp @@ -0,0 +1,152 @@ +#include "stdafx.h" +#include "SharedMutex.h" + +static const u32 MAX_READERS = 0x7fffffff; // 2^31-1 + +inline bool shared_mutex_t::try_lock_shared() +{ + return m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.readers < MAX_READERS && !info.writers && !info.waiting_readers && !info.waiting_writers) + { + info.readers++; + return true; + } + + return false; + }); +} + +void shared_mutex_t::lock_shared() +{ + if (!try_lock_shared()) + { + std::unique_lock lock(m_mutex); + + m_wrcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.waiting_readers < UINT16_MAX) + { + info.waiting_readers++; + return true; + } + + return false; + }))); + + m_rcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (!info.writers && !info.waiting_writers && info.readers < MAX_READERS) + { + info.readers++; + return true; + } + + return false; + }))); + + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.waiting_readers--) + { + throw EXCEPTION("Invalid value"); + } + }); + + if (info.waiting_readers == UINT16_MAX) + { + m_wrcv.notify_one(); + } + } +} + +void shared_mutex_t::unlock_shared() +{ + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.readers--) + { + throw EXCEPTION("Not locked"); + } + }); + + const bool notify_writers = info.readers == 1 && info.writers; + const bool notify_readers = info.readers == UINT32_MAX && info.waiting_readers; + + if (notify_writers || notify_readers) + { + std::lock_guard lock(m_mutex); + + if (notify_writers) m_wcv.notify_one(); + if (notify_readers) m_rcv.notify_one(); + } +} + +inline bool shared_mutex_t::try_lock() +{ + return m_info.compare_and_swap_test({ 0, 0, 0, 0 }, { 0, 1, 0, 0 }); +} + +void shared_mutex_t::lock() +{ + if (!try_lock()) + { + std::unique_lock lock(m_mutex); + + m_wwcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (info.waiting_writers < UINT16_MAX) + { + info.waiting_writers++; + return true; + } + + return false; + }))); + + m_wcv.wait(lock, WRAP_EXPR(m_info.atomic_op([](ownership_info_t& info) -> bool + { + if (!info.writers) + { + info.writers++; + return true; + } + + return false; + }))); + + m_wcv.wait(lock, WRAP_EXPR(m_info.load().readers == 0)); + + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.waiting_writers--) + { + throw EXCEPTION("Invalid value"); + } + }); + + if (info.waiting_writers == UINT16_MAX) + { + m_wwcv.notify_one(); + } + } +} + +void shared_mutex_t::unlock() +{ + const auto info = m_info.atomic_op([](ownership_info_t& info) + { + if (!info.writers--) + { + throw EXCEPTION("Not locked"); + } + }); + + if (info.waiting_writers || info.waiting_readers) + { + std::lock_guard lock(m_mutex); + + if (info.waiting_writers) m_wcv.notify_one(); + else if (info.waiting_readers) m_rcv.notify_all(); + } +} diff --git a/Utilities/SharedMutex.h b/Utilities/SharedMutex.h new file mode 100644 index 0000000000..82d38c1ee7 --- /dev/null +++ b/Utilities/SharedMutex.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +// An attempt to create lock-free (in optimistic case) implementation similar to std::shared_mutex; +// MSVC implementation of std::shared_timed_mutex is not lock-free and thus may be slow, and std::shared_mutex is not available. +class shared_mutex_t +{ + struct ownership_info_t + { + u32 readers : 31; + u32 writers : 1; + u16 waiting_readers; + u16 waiting_writers; + }; + + atomic_t m_info{}; + + std::mutex m_mutex; + + std::condition_variable m_rcv; + std::condition_variable m_wcv; + std::condition_variable m_wrcv; + std::condition_variable m_wwcv; + +public: + shared_mutex_t() = default; + + // Lock in shared mode + void lock_shared(); + + // Try to lock in shared mode + bool try_lock_shared(); + + // Unlock in shared mode + void unlock_shared(); + + // Lock exclusively + void lock(); + + // Try to lock exclusively + bool try_lock(); + + // Unlock exclusively + void unlock(); +}; diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 8465ad0612..02111b9db2 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -145,8 +145,7 @@ namespace fmt std::string to_udec(u64 value); std::string to_sdec(s64 value); - template::value> - struct unveil + template::value> struct unveil { using result_type = T; @@ -156,8 +155,7 @@ namespace fmt } }; - template<> - struct unveil + template<> struct unveil { using result_type = const char*; @@ -167,8 +165,7 @@ namespace fmt } }; - template - struct unveil + template struct unveil { using result_type = const char*; @@ -178,8 +175,7 @@ namespace fmt } }; - template<> - struct unveil + template<> struct unveil { using result_type = const char*; @@ -189,8 +185,7 @@ namespace fmt } }; - template - struct unveil + template struct unveil { using result_type = std::underlying_type_t; @@ -200,25 +195,13 @@ namespace fmt } }; - template - struct unveil, false> + template struct unveil, false> { using result_type = typename unveil::result_type; - force_inline static result_type get_value(const be_t& arg) + force_inline static result_type get_value(const se_t& arg) { - return unveil::get_value(arg.value()); - } - }; - - template - struct unveil, false> - { - using result_type = typename unveil::result_type; - - force_inline static result_type get_value(const le_t& arg) - { - return unveil::get_value(arg.value()); + return unveil::get_value(arg); } }; @@ -270,11 +253,11 @@ namespace fmt } } - struct exception + struct exception : public std::exception { std::unique_ptr message; - template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) + template never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept { const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func); @@ -283,16 +266,16 @@ namespace fmt std::memcpy(message.get(), data.c_str(), data.size() + 1); } - exception(const exception& other) + exception(const exception& other) noexcept { - const std::size_t size = std::strlen(other); + const std::size_t size = std::strlen(other.message.get()); message.reset(new char[size + 1]); - std::memcpy(message.get(), other, size + 1); + std::memcpy(message.get(), other.message.get(), size + 1); } - operator const char*() const + virtual const char* what() const noexcept override { return message.get(); } diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index bdc740374a..100bf3d7e4 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1121,6 +1121,8 @@ void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) { throw EXCEPTION("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64); } + + //__int2c(); // if it crashed there, check the callstack for the actual source of the crash } const PVOID exception_handler = (atexit([]{ RemoveVectoredExceptionHandler(exception_handler); }), AddVectoredExceptionHandler(1, [](PEXCEPTION_POINTERS pExp) -> LONG @@ -1281,14 +1283,9 @@ void named_thread_t::start(std::function name, std::function& test_exit) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 3f72c08dcd..fd9c4ba632 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -28,7 +28,7 @@ void armv7_init_tls() for (auto& v : g_armv7_tls_owners) { - v.store(0, std::memory_order_relaxed); + v = 0; } } @@ -53,8 +53,8 @@ u32 armv7_get_tls(u32 thread) if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread)) { const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address - memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image - memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros + std::memcpy(vm::get_ptr(addr), vm::get_ptr(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image + std::memset(vm::get_ptr(addr + Emu.GetTLSFilesz()), 0, Emu.GetTLSMemsz() - Emu.GetTLSFilesz()); // fill the rest with zeros return addr; } } @@ -195,15 +195,13 @@ void ARMv7Thread::task() { if (custom_task) { - if (m_state.load() && check_status()) return; + if (check_status()) return; return custom_task(*this); } - while (true) + while (!m_state || !check_status()) { - if (m_state.load() && check_status()) break; - // decode instruction using specified decoder PC += m_dec->DecodeMemory(PC); } diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index d97165b960..eb403ddf9f 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -116,12 +116,7 @@ s32 sceKernelExitDeleteThread(ARMv7Thread& context, s32 exitStatus) context.stop(); // current thread should be deleted - const u32 id = context.get_id(); - - CallAfter([id]() - { - idm::remove(id); - }); + idm::remove(context.get_id()); return SCE_OK; } @@ -494,7 +489,7 @@ s32 sceKernelWaitEventFlag(ARMv7Thread& context, s32 evfId, u32 bitPattern, u32 if (passed >= timeout) { context.GPR[0] = SCE_KERNEL_ERROR_WAIT_TIMEOUT; - context.GPR[1] = evf->pattern.load(); + context.GPR[1] = evf->pattern; break; } @@ -629,7 +624,7 @@ s32 sceKernelCancelEventFlag(s32 evfId, u32 setPattern, vm::ptr pNumWaitThr *pNumWaitThreads = static_cast(evf->sq.size()); - evf->pattern.store(setPattern); + evf->pattern = setPattern; evf->sq.clear(); return SCE_OK; @@ -655,7 +650,7 @@ s32 sceKernelGetEventFlagInfo(s32 evfId, vm::ptr pInfo) pInfo->attr = evf->attr; pInfo->initPattern = evf->init; - pInfo->currentPattern = evf->pattern.load(); + pInfo->currentPattern = evf->pattern; pInfo->numWaitThreads = static_cast(evf->sq.size()); return SCE_OK; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h index 05e7968852..1ba6f3a4ca 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.h @@ -464,8 +464,8 @@ struct psv_event_flag_t : name(name) , attr(attr) , init(pattern) + , pattern(pattern) { - this->pattern.store(pattern); } // Wakeup all waiters to return SCE_KERNEL_ERROR_WAIT_DELETE @@ -473,7 +473,7 @@ struct psv_event_flag_t { std::lock_guard lock(mutex); - const u32 pattern = this->pattern.load(); + const u32 pattern = this->pattern; for (auto& thread : sq) { @@ -550,8 +550,8 @@ struct psv_semaphore_t : name(name) , attr(attr) , max(max) + , count(count) { - this->count.store(count); } }; @@ -588,8 +588,8 @@ struct psv_mutex_t psv_mutex_t(const char* name, u32 attr, s32 count) : name(name) , attr(attr) + , count(count) { - this->count.store(count); } }; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 274824bba4..bac1572107 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -188,7 +188,7 @@ namespace sce_libc_func sceLibc.Success("Process finished"); - CallAfter([]() + Emu.CallAfter([]() { Emu.Stop(); }); diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 035c911382..7cc5ba39e5 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -4,20 +4,18 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/DbgCommand.h" #include "CPUDecoder.h" #include "CPUThread.h" CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function thread_name) - : m_state({ CPU_STATE_STOPPED }) - , m_id(idm::get_last_id()) + : m_id(idm::get_last_id()) , m_type(type) , m_name(name) { start(std::move(thread_name), [this] { - SendDbgCommand(DID_CREATE_THREAD, this); + Emu.SendDbgCommand(DID_CREATE_THREAD, this); std::unique_lock lock(mutex); @@ -71,12 +69,12 @@ CPUThread::CPUThread(CPUThreadType type, const std::string& name, std::function< CPUThread::~CPUThread() { - SendDbgCommand(DID_REMOVE_THREAD, this); + Emu.SendDbgCommand(DID_REMOVE_THREAD, this); } bool CPUThread::is_paused() const { - return (m_state.load() & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); + return (m_state & CPU_STATE_PAUSED) != 0 || Emu.IsPaused(); } void CPUThread::dump_info() const @@ -89,27 +87,27 @@ void CPUThread::dump_info() const void CPUThread::run() { - SendDbgCommand(DID_START_THREAD, this); + Emu.SendDbgCommand(DID_START_THREAD, this); init_stack(); init_regs(); do_run(); - SendDbgCommand(DID_STARTED_THREAD, this); + Emu.SendDbgCommand(DID_STARTED_THREAD, this); } void CPUThread::pause() { - SendDbgCommand(DID_PAUSE_THREAD, this); + Emu.SendDbgCommand(DID_PAUSE_THREAD, this); m_state |= CPU_STATE_PAUSED; - SendDbgCommand(DID_PAUSED_THREAD, this); + Emu.SendDbgCommand(DID_PAUSED_THREAD, this); } void CPUThread::resume() { - SendDbgCommand(DID_RESUME_THREAD, this); + Emu.SendDbgCommand(DID_RESUME_THREAD, this); { // lock for reliable notification @@ -120,12 +118,12 @@ void CPUThread::resume() cv.notify_one(); } - SendDbgCommand(DID_RESUMED_THREAD, this); + Emu.SendDbgCommand(DID_RESUMED_THREAD, this); } void CPUThread::stop() { - SendDbgCommand(DID_STOP_THREAD, this); + Emu.SendDbgCommand(DID_STOP_THREAD, this); if (is_current()) { @@ -141,12 +139,12 @@ void CPUThread::stop() cv.notify_one(); } - SendDbgCommand(DID_STOPED_THREAD, this); + Emu.SendDbgCommand(DID_STOPED_THREAD, this); } void CPUThread::exec() { - SendDbgCommand(DID_EXEC_THREAD, this); + Emu.SendDbgCommand(DID_EXEC_THREAD, this); { // lock for reliable notification @@ -258,7 +256,7 @@ bool CPUThread::check_status() { CHECK_EMU_STATUS; // check at least once - if (!is_paused() && (m_state.load() & CPU_STATE_INTR) == 0) + if (!is_paused() && (m_state & CPU_STATE_INTR) == 0) { break; } @@ -269,7 +267,7 @@ bool CPUThread::check_status() continue; } - if (!is_paused() && (m_state.load() & CPU_STATE_INTR) != 0 && handle_interrupt()) + if (!is_paused() && (m_state & CPU_STATE_INTR) != 0 && handle_interrupt()) { continue; } @@ -277,12 +275,12 @@ bool CPUThread::check_status() cv.wait(lock); } - if (m_state.load() & CPU_STATE_RETURN || is_stopped()) + if (m_state & CPU_STATE_RETURN || is_stopped()) { return true; } - if (m_state.load() & CPU_STATE_STEP) + if (m_state & CPU_STATE_STEP) { // set PAUSE, but allow to execute once m_state |= CPU_STATE_PAUSED; diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 57d821e01a..079da43f16 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -45,7 +45,7 @@ protected: using named_thread_t::join; using named_thread_t::joinable; - atomic_t m_state; // thread state flags + atomic_t m_state{ CPU_STATE_STOPPED }; // thread state flags std::unique_ptr m_dec; @@ -62,8 +62,8 @@ public: CPUThreadType get_type() const { return m_type; } std::string get_name() const { return m_name; } - bool is_alive() const { return (m_state.load() & CPU_STATE_DEAD) == 0; } - bool is_stopped() const { return (m_state.load() & CPU_STATE_STOPPED) != 0; } + bool is_alive() const { return (m_state & CPU_STATE_DEAD) == 0; } + bool is_stopped() const { return (m_state & CPU_STATE_STOPPED) != 0; } virtual bool is_paused() const; virtual void dump_info() const; diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index efad193d15..e02f653c0e 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/DbgCommand.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" @@ -82,7 +81,7 @@ std::shared_ptr CPUThreadManager::NewRawSPUThread() break; } } - + return result; } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 884f58c9fd..106f0bf923 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -293,7 +293,7 @@ void PPUThread::task() { while (true) { - if (m_state.load() && check_status()) break; + if (m_state && check_status()) break; // decode instruction using specified decoder m_dec->DecodeMemory(PC); @@ -310,7 +310,7 @@ void PPUThread::task() const auto func = exec_map[PC / 4]; // check status - if (!m_state.load()) + if (!m_state) { // call interpreter function func(*this, { vm::ps3::read32(PC) }); diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 1ad595d2d9..c7c844721e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -67,7 +67,7 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value) case SPU_Status_offs: { - value = status.load(); + value = status; return true; } } @@ -201,7 +201,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) break; } - run_ctrl.store(value); + run_ctrl = value; return true; } @@ -212,7 +212,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) break; } - npc.store(value); + npc = value; return true; } @@ -245,5 +245,5 @@ void RawSPUThread::task() SPUThread::task(); // save next PC and current SPU Interrupt status - npc.store(pc | u32{ (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0 }); + npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); } diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index c53ed35363..71d7631589 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -272,7 +272,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->m_state.load() && _spu->check_status()) + if (_spu->m_state && _spu->check_status()) { return 0x2000000 | _spu->pc; } @@ -343,12 +343,12 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->m_state.load() || !_spu->check_status()) + while (!_spu->m_state || !_spu->check_status()) { // Call override function directly since the type is known static_cast(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); - if (_spu->m_state.load() & CPU_STATE_RETURN) + if (_spu->m_state & CPU_STATE_RETURN) { break; } diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index 27ab0954bd..a6dcbb5051 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -40,8 +40,6 @@ SPUDatabase::~SPUDatabase() std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 entry, u32 max_limit) { - std::lock_guard lock(m_mutex); - // Check arguments (bounds and alignment) if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4) { @@ -51,7 +49,19 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Key for multimap const u64 key = entry | u64{ ls[entry / 4] } << 32; - // Try to find existing function in the database + { + std::shared_lock lock(m_mutex); + + // Try to find existing function in the database + if (auto func = find(ls + entry / 4, key, max_limit - entry)) + { + return func; + } + } + + std::lock_guard lock(m_mutex); + + // Double-check if (auto func = find(ls + entry / 4, key, max_limit - entry)) { return func; diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index b252911aa9..eb695520f3 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/Cell/SPUOpcodes.h" +#include "Utilities/SharedMutex.h" class SPUThread; @@ -258,7 +259,7 @@ struct spu_function_t // SPU Function Database (must be global or PS3 process-local) class SPUDatabase final { - std::mutex m_mutex; + shared_mutex_t m_mutex; // All registered functions (uses addr and first instruction as a key) std::unordered_multimap> m_db; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 48780b9dc2..252e95cf02 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -29,7 +29,7 @@ thread_local bool spu_channel_t::notification_required; void spu_int_ctrl_t::set(u64 ints) { // leave only enabled interrupts - ints &= mask.load(); + ints &= mask; // notify if at least 1 bit was set if (ints && ~stat._or(ints) & ints && tag) @@ -118,7 +118,7 @@ void SPUThread::task() while (true) { - if (!m_state.load()) + if (!m_state) { // read opcode const u32 opcode = base[pc / 4]; @@ -146,7 +146,7 @@ void SPUThread::task() return custom_task(*this); } - while (!m_state.load() || !check_status()) + while (!m_state || !check_status()) { // decode instruction using specified decoder pc += m_dec->DecodeMemory(pc + offset); @@ -162,32 +162,34 @@ void SPUThread::init_regs() mfc_queue.clear(); ch_tag_mask = 0; - ch_tag_stat = {}; - ch_stall_stat = {}; - ch_atomic_stat = {}; + ch_tag_stat.data.store({}); + ch_stall_stat.data.store({}); + ch_atomic_stat.data.store({}); ch_in_mbox.clear(); - ch_out_mbox = {}; - ch_out_intr_mbox = {}; + ch_out_mbox.data.store({}); + ch_out_intr_mbox.data.store({}); snr_config = 0; - ch_snr1 = {}; - ch_snr2 = {}; + ch_snr1.data.store({}); + ch_snr2.data.store({}); - ch_event_mask = {}; - ch_event_stat = {}; + ch_event_mask = 0; + ch_event_stat = 0; last_raddr = 0; ch_dec_start_timestamp = get_timebased_time(); // ??? ch_dec_value = 0; - run_ctrl = {}; - status = {}; - npc = {}; + run_ctrl = 0; + status = 0; + npc = 0; - int_ctrl = {}; + int_ctrl[0].clear(); + int_ctrl[1].clear(); + int_ctrl[2].clear(); gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } @@ -511,7 +513,7 @@ u32 SPUThread::get_events(bool waiting) // polling with atomically set/removed SPU_EVENT_WAITING flag return ch_event_stat.atomic_op([this](u32& stat) -> u32 { - if (u32 res = stat & ch_event_mask.load()) + if (u32 res = stat & ch_event_mask) { stat &= ~SPU_EVENT_WAITING; return res; @@ -525,7 +527,7 @@ u32 SPUThread::get_events(bool waiting) } // simple polling - return ch_event_stat.load() & ch_event_mask.load(); + return ch_event_stat & ch_event_mask; } void SPUThread::set_events(u32 mask) @@ -543,7 +545,7 @@ void SPUThread::set_events(u32 mask) { std::lock_guard lock(mutex); - if (ch_event_stat.load() & SPU_EVENT_WAITING) + if (ch_event_stat & SPU_EVENT_WAITING) { cv.notify_one(); } @@ -555,7 +557,7 @@ void SPUThread::set_interrupt_status(bool enable) if (enable) { // detect enabling interrupts with events masked - if (u32 mask = ch_event_mask.load()) + if (u32 mask = ch_event_mask) { throw EXCEPTION("SPU Interrupts not implemented (mask=0x%x)", mask); } @@ -710,7 +712,7 @@ u32 SPUThread::get_ch_value(u32 ch) case SPU_RdEventMask: { - return ch_event_mask.load(); + return ch_event_mask; } case SPU_RdEventStat: @@ -723,7 +725,7 @@ u32 SPUThread::get_ch_value(u32 ch) return res; } - if (ch_event_mask.load() & SPU_EVENT_LR) + if (ch_event_mask & SPU_EVENT_LR) { // register waiter if polling reservation status is required vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped())); @@ -752,7 +754,7 @@ u32 SPUThread::get_ch_value(u32 ch) { // HACK: "Not isolated" status // Return SPU Interrupt status in LSB - return (ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) != 0; + return (ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0; } } @@ -1120,7 +1122,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) case SPU_WrEventMask: { // detect masking events with enabled interrupt status - if (value && ch_event_stat.load() & SPU_EVENT_INTR_ENABLED) + if (value && ch_event_stat & SPU_EVENT_INTR_ENABLED) { throw EXCEPTION("SPU Interrupts not implemented (mask=0x%x)", value); } @@ -1131,7 +1133,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) break; } - ch_event_mask.store(value); + ch_event_mask = value; return; } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index ced3748d78..726ad61ad1 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -147,13 +147,13 @@ struct spu_channel_t u32 value; }; - atomic_t sync_var; + atomic_t data; public: // returns true on success bool try_push(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { if ((data.wait = data.count) == false) { @@ -168,7 +168,7 @@ public: // push performing bitwise OR with previous value, may require notification void push_or(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -181,7 +181,7 @@ public: // push unconditionally (overwriting previous value), may require notification void push(u32 value) { - const auto old = sync_var.atomic_op([=](sync_var_t& data) + const auto old = data.atomic_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -194,7 +194,7 @@ public: // returns true on success and loaded value std::tuple try_pop() { - const auto old = sync_var.atomic_op([](sync_var_t& data) + const auto old = data.atomic_op([](sync_var_t& data) { data.wait = !data.count; data.count = false; @@ -207,7 +207,7 @@ public: // pop unconditionally (loading last value), may require notification u32 pop() { - const auto old = sync_var.atomic_op([](sync_var_t& data) + const auto old = data.atomic_op([](sync_var_t& data) { data.wait = false; data.count = false; @@ -221,17 +221,17 @@ public: void set_value(u32 value, bool count = true) { - sync_var.store({ count, false, value }); + data.store({ count, false, value }); } - u32 get_value() volatile + u32 get_value() { - return sync_var.data.value; + return data.load().value; } - u32 get_count() volatile + u32 get_count() { - return sync_var.data.count; + return data.load().count; } }; @@ -250,22 +250,22 @@ struct spu_channel_4_t u32 value2; }; - atomic_t sync_var; + atomic_t values; atomic_t value3; public: void clear() { - sync_var = {}; - value3 = {}; + values = sync_var_t{}; + value3 = 0; } // push unconditionally (overwriting latest value), returns true if needs signaling bool push(u32 value) { - value3.exchange(value); + value3 = value; _mm_sfence(); - return sync_var.atomic_op([=](sync_var_t& data) -> bool + return values.atomic_op([=](sync_var_t& data) -> bool { switch (data.count++) { @@ -289,7 +289,7 @@ public: // returns true on success and two u32 values: data and count after removing the first element std::tuple try_pop() { - return sync_var.atomic_op([this](sync_var_t& data) + return values.atomic_op([this](sync_var_t& data) { const auto result = std::make_tuple(data.count != 0, u32{ data.value0 }, u32{ data.count - 1u }); @@ -300,7 +300,8 @@ public: data.value0 = data.value1; data.value1 = data.value2; - data.value2 = value3.load_sync(); + _mm_lfence(); + data.value2 = this->value3; } else { @@ -311,19 +312,15 @@ public: }); } - u32 get_count() volatile + u32 get_count() { - return sync_var.data.count; + return values.raw().count; } void set_values(u32 count, u32 value0, u32 value1 = 0, u32 value2 = 0, u32 value3 = 0) { - sync_var.data.waiting = 0; - sync_var.data.count = count; - sync_var.data.value0 = value0; - sync_var.data.value1 = value1; - sync_var.data.value2 = value2; - this->value3.store(value3); + this->values.raw() = { 0, count, value0, value1, value2 }; + this->value3 = value3; } }; @@ -337,6 +334,13 @@ struct spu_int_ctrl_t void set(u64 ints); void clear(u64 ints); + + void clear() + { + mask = 0; + stat = 0; + tag = nullptr; + } }; struct spu_imm_table_t diff --git a/rpcs3/Emu/DbgCommand.cpp b/rpcs3/Emu/DbgCommand.cpp deleted file mode 100644 index 8be005e73c..0000000000 --- a/rpcs3/Emu/DbgCommand.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "stdafx.h" -#include "DbgCommand.h" - -SendDbgCommandCb SendDbgCommandFunc = nullptr; - -void SendDbgCommand(DbgCommand id, CPUThread* t) -{ - SendDbgCommandFunc(id, t); -} - -void SetSendDbgCommandCallback(SendDbgCommandCb cb) -{ - SendDbgCommandFunc = cb; -} \ No newline at end of file diff --git a/rpcs3/Emu/DbgCommand.h b/rpcs3/Emu/DbgCommand.h index 2973079729..4009aaa988 100644 --- a/rpcs3/Emu/DbgCommand.h +++ b/rpcs3/Emu/DbgCommand.h @@ -1,7 +1,5 @@ #pragma once -class CPUThread; - enum DbgCommand { DID_FIRST_COMMAND = 0x500, @@ -35,9 +33,3 @@ enum DbgCommand DID_LAST_COMMAND, }; - -typedef void(*SendDbgCommandCb)(DbgCommand id, CPUThread* t); - -void SetSendDbgCommandCallback(SendDbgCommandCb value); - -void SendDbgCommand(DbgCommand id, CPUThread* thr = nullptr); \ No newline at end of file diff --git a/rpcs3/Emu/IdManager.cpp b/rpcs3/Emu/IdManager.cpp index 46b597d9ea..d9e2d6720d 100644 --- a/rpcs3/Emu/IdManager.cpp +++ b/rpcs3/Emu/IdManager.cpp @@ -1,35 +1,14 @@ #include "stdafx.h" #include "IdManager.h" -namespace idm -{ - std::mutex g_id_mutex; +std::mutex idm::g_mutex; - std::unordered_map g_id_map; +std::unordered_map idm::g_map; - thread_local u32 g_tls_last_id = 0xdeadbeef; +u32 idm::g_last_raw_id = 0; - u32 g_last_raw_id = 0; +thread_local u32 idm::g_tls_last_id = 0xdeadbeef; - void clear() - { - std::lock_guard lock(g_id_mutex); +std::mutex fxm::g_mutex; - g_id_map.clear(); - g_last_raw_id = 0; - } -} - -namespace fxm -{ - std::mutex g_fx_mutex; - - std::unordered_map> g_fx_map; - - void clear() - { - std::lock_guard lock(g_fx_mutex); - - g_fx_map.clear(); - } -} +std::unordered_map> fxm::g_map; diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index 3ee541c583..f35e01a7c8 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -2,6 +2,15 @@ #define ID_MANAGER_INCLUDED +template struct type_info_t { static char value; }; + +template char type_info_t::value = 42; + +template constexpr inline const void* get_type_index() +{ + return &type_info_t::value; +} + // default traits for any arbitrary type template struct id_traits { @@ -15,24 +24,16 @@ template struct id_traits static u32 out_id(u32 raw_id) { return raw_id; } }; -class id_data_t final +struct id_data_t final { -public: - const std::shared_ptr data; - const std::type_info& info; - const std::size_t hash; + std::shared_ptr data; + const std::type_info* info; + const void* type_index; - template force_inline id_data_t(std::shared_ptr data) + template inline id_data_t(std::shared_ptr data) : data(std::move(data)) - , info(typeid(T)) - , hash(typeid(T).hash_code()) - { - } - - id_data_t(id_data_t&& right) - : data(std::move(const_cast&>(right.data))) - , info(right.info) - , hash(right.hash) + , info(&typeid(T)) + , type_index(get_type_index()) { } }; @@ -43,64 +44,63 @@ public: // 0x80000000+ : reserved (may be used through id_traits specializations) namespace idm { - // can be called from the constructor called through make() or make_ptr() to get the ID of currently created object - inline u32 get_last_id() - { - thread_local extern u32 g_tls_last_id; + extern std::mutex g_mutex; + extern std::unordered_map g_map; + + extern u32 g_last_raw_id; + + thread_local extern u32 g_tls_last_id; + + // can be called from the constructor called through make() or make_ptr() to get the ID of the object being created + inline static u32 get_last_id() + { return g_tls_last_id; } // reinitialize ID manager - void clear(); + static void clear() + { + std::lock_guard lock(g_mutex); + + g_map.clear(); + g_last_raw_id = 0; + } // check if ID of specified type exists - template bool check(u32 id) + template static bool check(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); + + const auto found = g_map.find(id_traits::in_id(id)); - std::lock_guard lock(g_id_mutex); - - const auto found = g_id_map.find(id_traits::in_id(id)); - - return found != g_id_map.end() && found->second.info == typeid(T); + return found != g_map.end() && found->second.type_index == get_type_index(); } // check if ID exists and return its type or nullptr - inline const std::type_info* get_type(u32 raw_id) + inline static const std::type_info* get_type(u32 raw_id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(raw_id); - const auto found = g_id_map.find(raw_id); - - return found == g_id_map.end() ? nullptr : &found->second.info; + return found == g_map.end() ? nullptr : found->second.info; } // add new ID of specified type with specified constructor arguments (returns object or nullptr) - template std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) + template static std::enable_if_t::value, std::shared_ptr> make_ptr(Args&&... args) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); auto ptr = std::make_shared(std::forward(args)...); - g_id_map.emplace(raw_id, id_data_t(ptr)); + g_map.emplace(raw_id, id_data_t(ptr)); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -111,24 +111,17 @@ namespace idm } // add new ID of specified type with specified constructor arguments (returns id) - template std::enable_if_t::value, u32> make(Args&&... args) + template static std::enable_if_t::value, u32> make(Args&&... args) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); - g_id_map.emplace(raw_id, id_data_t(std::make_shared(std::forward(args)...))); + g_map.emplace(raw_id, id_data_t(std::make_shared(std::forward(args)...))); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -139,24 +132,17 @@ namespace idm } // add new ID for an existing object provided (don't use for initial object creation) - template u32 import(const std::shared_ptr& ptr) + template static u32 import(const std::shared_ptr& ptr) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - extern u32 g_last_raw_id; - thread_local extern u32 g_tls_last_id; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); - - u32 raw_id = g_last_raw_id; - - while ((raw_id = id_traits::next_id(raw_id))) + for (u32 raw_id = g_last_raw_id; (raw_id = id_traits::next_id(raw_id)); /**/) { - if (g_id_map.find(raw_id) != g_id_map.end()) continue; + if (g_map.find(raw_id) != g_map.end()) continue; g_tls_last_id = id_traits::out_id(raw_id); - g_id_map.emplace(raw_id, id_data_t(ptr)); + g_map.emplace(raw_id, id_data_t(ptr)); if (raw_id < 0x80000000) g_last_raw_id = raw_id; @@ -167,16 +153,13 @@ namespace idm } // get ID of specified type - template std::shared_ptr get(u32 id) + template static std::shared_ptr get(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return nullptr; } @@ -185,20 +168,17 @@ namespace idm } // get all IDs of specified type T (unsorted) - template std::vector> get_all() + template static std::vector> get_all() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::vector> result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result.emplace_back(std::static_pointer_cast(v.second.data)); } @@ -208,61 +188,52 @@ namespace idm } // remove ID created with type T - template bool remove(u32 id) + template static bool remove(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return false; } - g_id_map.erase(found); + g_map.erase(found); return true; } // remove ID created with type T and return the object - template std::shared_ptr withdraw(u32 id) + template static std::shared_ptr withdraw(u32 id) { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_id_mutex); + const auto found = g_map.find(id_traits::in_id(id)); - const auto found = g_id_map.find(id_traits::in_id(id)); - - if (found == g_id_map.end() || found->second.info != typeid(T)) + if (found == g_map.end() || found->second.type_index != get_type_index()) { return nullptr; } auto ptr = std::static_pointer_cast(found->second.data); - g_id_map.erase(found); + g_map.erase(found); return ptr; } - template u32 get_count() + template static u32 get_count() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); u32 result = 0; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result++; } @@ -272,20 +243,17 @@ namespace idm } // get sorted ID list of specified type - template std::set get_set() + template static std::set get_set() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::set result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result.insert(id_traits::out_id(v.first)); } @@ -295,20 +263,17 @@ namespace idm } // get sorted ID map (ID value -> ID data) of specified type - template std::map> get_map() + template static std::map> get_map() { - extern std::mutex g_id_mutex; - extern std::unordered_map g_id_map; - - std::lock_guard lock(g_id_mutex); + std::lock_guard lock(g_mutex); std::map> result; - const std::size_t hash = typeid(T).hash_code(); + const auto type = get_type_index(); - for (auto& v : g_id_map) + for (auto& v : g_map) { - if (v.second.hash == hash && v.second.info == typeid(T)) + if (v.second.type_index == type) { result[id_traits::out_id(v.first)] = std::static_pointer_cast(v.second.data); } @@ -316,69 +281,102 @@ namespace idm return result; } -} +}; // Fixed Object Manager // allows to manage shared objects of any specified type, but only one object per type; // object are deleted when the emulation is stopped namespace fxm { + extern std::mutex g_mutex; + + extern std::unordered_map> g_map; + // reinitialize - void clear(); + static void clear() + { + std::lock_guard lock(g_mutex); + + g_map.clear(); + } // add fixed object of specified type only if it doesn't exist (one unique object per type may exist) - template std::enable_if_t::value, std::shared_ptr> make(Args&&... args) + template static std::enable_if_t::value, std::shared_ptr> make(Args&&... args) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto index = get_type_index(); - const auto found = g_fx_map.find(typeid(T)); + const auto found = g_map.find(index); // only if object of this type doesn't exist - if (found == g_fx_map.end()) + if (found == g_map.end()) { auto ptr = std::make_shared(std::forward(args)...); - g_fx_map.emplace(typeid(T), ptr); + g_map.emplace(index, ptr); - return std::move(ptr); + return ptr; } return nullptr; } // add fixed object of specified type, replacing previous one if it exists - template std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) + template static std::enable_if_t::value, std::shared_ptr> make_always(Args&&... args) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; - - std::lock_guard lock(g_fx_mutex); + std::lock_guard lock(g_mutex); auto ptr = std::make_shared(std::forward(args)...); - g_fx_map[typeid(T)] = ptr; + g_map[get_type_index()] = ptr; + + return ptr; + } + + // import existing fixed object of specified type only if it doesn't exist (don't use) + template static std::shared_ptr import(std::shared_ptr&& ptr) + { + std::lock_guard lock(g_mutex); + + const auto index = get_type_index(); + + const auto found = g_map.find(index); + + if (found == g_map.end()) + { + g_map.emplace(index, ptr); + + return ptr; + } + + return nullptr; + } + + // import existing fixed object of specified type, replacing previous one if it exists (don't use) + template static std::shared_ptr import_always(std::shared_ptr&& ptr) + { + std::lock_guard lock(g_mutex); + + g_map[get_type_index()] = ptr; return ptr; } // get fixed object of specified type (always returns an object, it's created if it doesn't exist) - template std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) + template static std::enable_if_t::value, std::shared_ptr> get_always(Args&&... args) { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto index = get_type_index(); - const auto found = g_fx_map.find(typeid(T)); + const auto found = g_map.find(index); - if (found == g_fx_map.end()) + if (found == g_map.end()) { auto ptr = std::make_shared(std::forward(args)...); - g_fx_map[typeid(T)] = ptr; + g_map[index] = ptr; return ptr; } @@ -387,27 +385,21 @@ namespace fxm } // check whether the object exists - template bool check() + template static bool check() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); - - return g_fx_map.find(typeid(T)) != g_fx_map.end(); + return g_map.find(get_type_index()) != g_map.end(); } // get fixed object of specified type (returns nullptr if it doesn't exist) - template std::shared_ptr get() + template static std::shared_ptr get() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return nullptr; } @@ -416,40 +408,34 @@ namespace fxm } // remove fixed object created with type T - template bool remove() + template static bool remove() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return false; } - return g_fx_map.erase(found), true; + return g_map.erase(found), true; } // remove fixed object created with type T and return it - template std::shared_ptr withdraw() + template static std::shared_ptr withdraw() { - extern std::mutex g_fx_mutex; - extern std::unordered_map> g_fx_map; + std::lock_guard lock(g_mutex); - std::lock_guard lock(g_fx_mutex); + const auto found = g_map.find(get_type_index()); - const auto found = g_fx_map.find(typeid(T)); - - if (found == g_fx_map.end()) + if (found == g_map.end()) { return nullptr; } auto ptr = std::static_pointer_cast(std::move(found->second)); - return g_fx_map.erase(found), ptr; + return g_map.erase(found), ptr; } -} +}; diff --git a/rpcs3/Emu/Io/Keyboard.cpp b/rpcs3/Emu/Io/Keyboard.cpp index e23f325b87..052cb2d843 100644 --- a/rpcs3/Emu/Io/Keyboard.cpp +++ b/rpcs3/Emu/Io/Keyboard.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullKeyboardHandler.h" +#include "Emu/System.h" + #include "Keyboard.h" -GetKeyboardHandlerCountCb GetKeyboardHandlerCount = []() +void KeyboardManager::Init(u32 max_connect) { - return 1; -}; - -GetKeyboardHandlerCb GetKeyboardHandler = [](int i) -> KeyboardHandlerBase* -{ - return new NullKeyboardHandler; -}; - -void SetGetKeyboardHandlerCountCallback(GetKeyboardHandlerCountCb cb) -{ - GetKeyboardHandlerCount = cb; -} - -void SetGetKeyboardHandlerCallback(GetKeyboardHandlerCb cb) -{ - GetKeyboardHandler = cb; -} - -KeyboardManager::KeyboardManager() - : m_keyboard_handler(nullptr) - , m_inited(false) -{ -} - -KeyboardManager::~KeyboardManager() -{ -} - -void KeyboardManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 comes out. - int numHandlers = GetKeyboardHandlerCount(); - int selectedHandler = Ini.KeyboardHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_keyboard_handler.reset(GetKeyboardHandler(selectedHandler)); - + m_keyboard_handler = Emu.GetCallbacks().get_kb_handler(); m_keyboard_handler->Init(max_connect); - m_inited = true; } void KeyboardManager::Close() { - if(m_keyboard_handler) m_keyboard_handler->Close(); - m_keyboard_handler = nullptr; - - m_inited = false; + m_keyboard_handler.reset(); } diff --git a/rpcs3/Emu/Io/Keyboard.h b/rpcs3/Emu/Io/Keyboard.h index 140c06ed4a..c61916dc3b 100644 --- a/rpcs3/Emu/Io/Keyboard.h +++ b/rpcs3/Emu/Io/Keyboard.h @@ -1,16 +1,13 @@ #pragma once + #include "KeyboardHandler.h" class KeyboardManager { - bool m_inited = false; std::unique_ptr m_keyboard_handler; public: - KeyboardManager(); - ~KeyboardManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetKeyboards() { return m_keyboard_handler->GetKeyboards(); } @@ -19,11 +16,5 @@ public: KbData& GetData(const u32 keyboard) { return m_keyboard_handler->GetData(keyboard); } KbConfig& GetConfig(const u32 keyboard) { return m_keyboard_handler->GetConfig(keyboard); } - bool IsInited() const { return m_inited; } + bool IsInited() const { return m_keyboard_handler.operator bool(); } }; - -typedef int(*GetKeyboardHandlerCountCb)(); -typedef KeyboardHandlerBase*(*GetKeyboardHandlerCb)(int i); - -void SetGetKeyboardHandlerCountCallback(GetKeyboardHandlerCountCb cb); -void SetGetKeyboardHandlerCallback(GetKeyboardHandlerCb cb); \ No newline at end of file diff --git a/rpcs3/Emu/Io/Mouse.cpp b/rpcs3/Emu/Io/Mouse.cpp index 5a0f191dae..e07534e3c8 100644 --- a/rpcs3/Emu/Io/Mouse.cpp +++ b/rpcs3/Emu/Io/Mouse.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullMouseHandler.h" +#include "Emu/System.h" + #include "Mouse.h" -GetMouseHandlerCountCb GetMouseHandlerCount = []() +void MouseManager::Init(u32 max_connect) { - return 1; -}; - -GetMouseHandlerCb GetMouseHandler = [](int i) -> MouseHandlerBase* -{ - return new NullMouseHandler; -}; - -void SetGetMouseHandlerCountCallback(GetMouseHandlerCountCb cb) -{ - GetMouseHandlerCount = cb; -} - -void SetGetMouseHandlerCallback(GetMouseHandlerCb cb) -{ - GetMouseHandler = cb; -} - -MouseManager::MouseManager() - : m_mouse_handler(nullptr) - , m_inited(false) -{ -} - -MouseManager::~MouseManager() -{ -} - -void MouseManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 is available. - int numHandlers = GetMouseHandlerCount(); - int selectedHandler = Ini.MouseHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_mouse_handler.reset(GetMouseHandler(selectedHandler)); - + m_mouse_handler = Emu.GetCallbacks().get_mouse_handler(); m_mouse_handler->Init(max_connect); - m_inited = true; } void MouseManager::Close() { - if(m_mouse_handler) m_mouse_handler->Close(); - m_mouse_handler = nullptr; - - m_inited = false; + m_mouse_handler.reset(); } diff --git a/rpcs3/Emu/Io/Mouse.h b/rpcs3/Emu/Io/Mouse.h index c6dbdd61dd..98d86185c4 100644 --- a/rpcs3/Emu/Io/Mouse.h +++ b/rpcs3/Emu/Io/Mouse.h @@ -1,16 +1,13 @@ #pragma once + #include "MouseHandler.h" class MouseManager { - bool m_inited; std::unique_ptr m_mouse_handler; public: - MouseManager(); - ~MouseManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetMice() { return m_mouse_handler->GetMice(); } @@ -18,11 +15,5 @@ public: MouseData& GetData(const u32 mouse) { return m_mouse_handler->GetData(mouse); } MouseRawData& GetRawData(const u32 mouse) { return m_mouse_handler->GetRawData(mouse); } - bool IsInited() const { return m_inited; } + bool IsInited() const { return m_mouse_handler.operator bool(); } }; - -typedef int(*GetMouseHandlerCountCb)(); -typedef MouseHandlerBase*(*GetMouseHandlerCb)(int i); - -void SetGetMouseHandlerCountCallback(GetMouseHandlerCountCb cb); -void SetGetMouseHandlerCallback(GetMouseHandlerCb cb); \ No newline at end of file diff --git a/rpcs3/Emu/Io/Pad.cpp b/rpcs3/Emu/Io/Pad.cpp index 72efc937bd..5c3328337d 100644 --- a/rpcs3/Emu/Io/Pad.cpp +++ b/rpcs3/Emu/Io/Pad.cpp @@ -1,60 +1,15 @@ #include "stdafx.h" -#include "rpcs3/Ini.h" -#include "Null/NullPadHandler.h" +#include "Emu/System.h" + #include "Pad.h" -GetPadHandlerCountCb GetPadHandlerCount = []() +void PadManager::Init(u32 max_connect) { - return 1; -}; - -GetPadHandlerCb GetPadHandler = [](int i) -> PadHandlerBase* -{ - return new NullPadHandler; -}; - -void SetGetPadHandlerCountCallback(GetPadHandlerCountCb cb) -{ - GetPadHandlerCount = cb; -} - -void SetGetPadHandlerCallback(GetPadHandlerCb cb) -{ - GetPadHandler = cb; -} - -PadManager::PadManager() - : m_pad_handler(nullptr) - , m_inited(false) -{ -} - -PadManager::~PadManager() -{ -} - -void PadManager::Init(const u32 max_connect) -{ - if(m_inited) - return; - - // NOTE: Change these to std::make_unique assignments when C++14 is available. - int numHandlers = GetPadHandlerCount(); - int selectedHandler = Ini.PadHandlerMode.GetValue(); - if (selectedHandler > numHandlers) - { - selectedHandler = 0; - } - m_pad_handler.reset(GetPadHandler(selectedHandler)); - + m_pad_handler = Emu.GetCallbacks().get_pad_handler(); m_pad_handler->Init(max_connect); - m_inited = true; } void PadManager::Close() { - if(m_pad_handler) m_pad_handler->Close(); - m_pad_handler = nullptr; - - m_inited = false; -} \ No newline at end of file + m_pad_handler.reset(); +} diff --git a/rpcs3/Emu/Io/Pad.h b/rpcs3/Emu/Io/Pad.h index e6a3260464..8bbb3a01f3 100644 --- a/rpcs3/Emu/Io/Pad.h +++ b/rpcs3/Emu/Io/Pad.h @@ -1,27 +1,18 @@ #pragma once + #include "PadHandler.h" class PadManager { - bool m_inited; std::unique_ptr m_pad_handler; public: - PadManager(); - ~PadManager(); - - void Init(const u32 max_connect); + void Init(u32 max_connect); void Close(); std::vector& GetPads() { return m_pad_handler->GetPads(); } PadInfo& GetInfo() { return m_pad_handler->GetInfo(); } std::vector