mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-04 22:19:02 +00:00
Merge remote-tracking branch 'upstream/master' into ppu_llvm_recompiler
Conflicts: Utilities/BEType.h rpcs3/Emu/Cell/PPUInterpreter.h rpcs3/emucore.vcxproj.filters
This commit is contained in:
commit
8a7ba5a709
99 changed files with 2228 additions and 728 deletions
|
|
@ -1,20 +1,91 @@
|
|||
#pragma once
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
union _CRT_ALIGN(16) u128
|
||||
{
|
||||
u64 _u64[2];
|
||||
s64 _s64[2];
|
||||
|
||||
class u64_reversed_array_2
|
||||
{
|
||||
u64 data[2];
|
||||
|
||||
public:
|
||||
u64& operator [] (s32 index)
|
||||
{
|
||||
return data[1 - index];
|
||||
}
|
||||
|
||||
const u64& operator [] (s32 index) const
|
||||
{
|
||||
return data[1 - index];
|
||||
}
|
||||
|
||||
} u64r;
|
||||
|
||||
u32 _u32[4];
|
||||
s32 _s32[4];
|
||||
|
||||
class u32_reversed_array_4
|
||||
{
|
||||
u32 data[4];
|
||||
|
||||
public:
|
||||
u32& operator [] (s32 index)
|
||||
{
|
||||
return data[3 - index];
|
||||
}
|
||||
|
||||
const u32& operator [] (s32 index) const
|
||||
{
|
||||
return data[3 - index];
|
||||
}
|
||||
|
||||
} u32r;
|
||||
|
||||
u16 _u16[8];
|
||||
s16 _s16[8];
|
||||
|
||||
class u16_reversed_array_8
|
||||
{
|
||||
u16 data[8];
|
||||
|
||||
public:
|
||||
u16& operator [] (s32 index)
|
||||
{
|
||||
return data[7 - index];
|
||||
}
|
||||
|
||||
const u16& operator [] (s32 index) const
|
||||
{
|
||||
return data[7 - index];
|
||||
}
|
||||
|
||||
} u16r;
|
||||
|
||||
u8 _u8[16];
|
||||
s8 _s8[16];
|
||||
|
||||
class u8_reversed_array_16
|
||||
{
|
||||
u8 data[16];
|
||||
|
||||
public:
|
||||
u8& operator [] (s32 index)
|
||||
{
|
||||
return data[15 - index];
|
||||
}
|
||||
|
||||
const u8& operator [] (s32 index) const
|
||||
{
|
||||
return data[15 - index];
|
||||
}
|
||||
|
||||
} u8r;
|
||||
|
||||
float _f[4];
|
||||
double _d[2];
|
||||
__m128 xmm;
|
||||
__m128 vf;
|
||||
__m128i vi;
|
||||
|
||||
class bit_array_128
|
||||
{
|
||||
|
|
@ -94,6 +165,11 @@ union _CRT_ALIGN(16) u128
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u128 from64r(u64 _1, u64 _0 = 0)
|
||||
{
|
||||
return from64(_0, _1);
|
||||
}
|
||||
|
||||
static u128 from32(u32 _0, u32 _1 = 0, u32 _2 = 0, u32 _3 = 0)
|
||||
{
|
||||
u128 ret;
|
||||
|
|
@ -105,12 +181,21 @@ union _CRT_ALIGN(16) u128
|
|||
}
|
||||
|
||||
static u128 from32r(u32 _3, u32 _2 = 0, u32 _1 = 0, u32 _0 = 0)
|
||||
{
|
||||
return from32(_0, _1, _2, _3);
|
||||
}
|
||||
|
||||
static u128 from32p(u32 value)
|
||||
{
|
||||
u128 ret;
|
||||
ret._u32[0] = _0;
|
||||
ret._u32[1] = _1;
|
||||
ret._u32[2] = _2;
|
||||
ret._u32[3] = _3;
|
||||
ret.vi = _mm_set1_epi32((int)value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u128 from8p(u8 value)
|
||||
{
|
||||
u128 ret;
|
||||
ret.vi = _mm_set1_epi8((char)value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -121,9 +206,41 @@ union _CRT_ALIGN(16) u128
|
|||
return ret;
|
||||
}
|
||||
|
||||
void setBit(u32 bit)
|
||||
static u128 fromV(__m128i value)
|
||||
{
|
||||
_bit[bit] = true;
|
||||
u128 ret;
|
||||
ret.vi = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __forceinline u128 add8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_add_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static __forceinline u128 sub8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_sub_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static __forceinline u128 minu8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_min_epu8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static __forceinline u128 eq8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_cmpeq_epi8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static __forceinline u128 gtu8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_cmpgt_epu8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
static __forceinline u128 leu8(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_cmple_epu8(left.vi, right.vi));
|
||||
}
|
||||
|
||||
bool operator == (const u128& right) const
|
||||
|
|
@ -136,19 +253,19 @@ union _CRT_ALIGN(16) u128
|
|||
return (_u64[0] != right._u64[0]) || (_u64[1] != right._u64[1]);
|
||||
}
|
||||
|
||||
u128 operator | (const u128& right) const
|
||||
__forceinline u128 operator | (const u128& right) const
|
||||
{
|
||||
return from64(_u64[0] | right._u64[0], _u64[1] | right._u64[1]);
|
||||
return fromV(_mm_or_si128(vi, right.vi));
|
||||
}
|
||||
|
||||
u128 operator & (const u128& right) const
|
||||
__forceinline u128 operator & (const u128& right) const
|
||||
{
|
||||
return from64(_u64[0] & right._u64[0], _u64[1] & right._u64[1]);
|
||||
return fromV(_mm_and_si128(vi, right.vi));
|
||||
}
|
||||
|
||||
u128 operator ^ (const u128& right) const
|
||||
__forceinline u128 operator ^ (const u128& right) const
|
||||
{
|
||||
return from64(_u64[0] ^ right._u64[0], _u64[1] ^ right._u64[1]);
|
||||
return fromV(_mm_xor_si128(vi, right.vi));
|
||||
}
|
||||
|
||||
u128 operator ~ () const
|
||||
|
|
@ -156,6 +273,12 @@ union _CRT_ALIGN(16) u128
|
|||
return from64(~_u64[0], ~_u64[1]);
|
||||
}
|
||||
|
||||
// result = (~left) & (right)
|
||||
static __forceinline u128 andnot(const u128& left, const u128& right)
|
||||
{
|
||||
return fromV(_mm_andnot_si128(left.vi, right.vi));
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_u64[1] = _u64[0] = 0;
|
||||
|
|
@ -180,6 +303,72 @@ union _CRT_ALIGN(16) u128
|
|||
}
|
||||
};
|
||||
|
||||
#ifndef InterlockedCompareExchange
|
||||
static __forceinline u128 InterlockedCompareExchange(volatile u128* dest, u128 exch, u128 comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
auto res = __sync_val_compare_and_swap((volatile __int128_t*)dest, (__int128_t&)comp, (__int128_t&)exch);
|
||||
return (u128&)res;
|
||||
#else
|
||||
_InterlockedCompareExchange128((volatile long long*)dest, exch._u64[1], exch._u64[0], (long long*)&comp);
|
||||
return comp;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static __forceinline bool InterlockedCompareExchangeTest(volatile u128* dest, u128 exch, u128 comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_bool_compare_and_swap((volatile __int128_t*)dest, (__int128_t&)comp, (__int128_t&)exch);
|
||||
#else
|
||||
return _InterlockedCompareExchange128((volatile long long*)dest, exch._u64[1], exch._u64[0], (long long*)&comp) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef InterlockedExchange
|
||||
static __forceinline u128 InterlockedExchange(volatile u128* dest, u128 value)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const u128 old = *(u128*)dest;
|
||||
if (InterlockedCompareExchangeTest(dest, value, old)) return old;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedOr
|
||||
static __forceinline u128 InterlockedOr(volatile u128* dest, u128 value)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const u128 old = *(u128*)dest;
|
||||
if (InterlockedCompareExchangeTest(dest, old | value, old)) return old;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedAnd
|
||||
static __forceinline u128 InterlockedAnd(volatile u128* dest, u128 value)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const u128 old = *(u128*)dest;
|
||||
if (InterlockedCompareExchangeTest(dest, old & value, old)) return old;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedXor
|
||||
static __forceinline u128 InterlockedXor(volatile u128* dest, u128 value)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const u128 old = *(u128*)dest;
|
||||
if (InterlockedCompareExchangeTest(dest, old ^ value, old)) return old;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define re16(val) _byteswap_ushort(val)
|
||||
#define re32(val) _byteswap_ulong(val)
|
||||
#define re64(val) _byteswap_uint64(val)
|
||||
|
|
|
|||
146
Utilities/GNU.h
146
Utilities/GNU.h
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define thread_local __declspec(thread)
|
||||
#elif __APPLE__
|
||||
|
|
@ -44,23 +46,6 @@ void strcpy_trunc(char(&dst)[size], const char(&src)[rsize])
|
|||
#define _byteswap_uint64(x) __builtin_bswap64(x)
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
#define _CRT_ALIGN(x) __attribute__((aligned(x)))
|
||||
#define InterlockedCompareExchange(ptr,new_val,old_val) __sync_val_compare_and_swap(ptr,old_val,new_val)
|
||||
#define InterlockedExchange(ptr, value) __sync_lock_test_and_set(ptr, value)
|
||||
#define InterlockedOr(ptr, value) __sync_fetch_and_or(ptr, value)
|
||||
#define InterlockedAnd(ptr, value) __sync_fetch_and_and(ptr, value)
|
||||
#define InterlockedXor(ptr, value) __sync_fetch_and_xor(ptr, value)
|
||||
|
||||
//inline int64_t InterlockedOr64(volatile int64_t *dest, int64_t val)
|
||||
//{
|
||||
// int64_t olderval;
|
||||
// int64_t oldval = *dest;
|
||||
// do
|
||||
// {
|
||||
// olderval = oldval;
|
||||
// oldval = __sync_val_compare_and_swap(dest, olderval | val, olderval);
|
||||
// } while (olderval != oldval);
|
||||
// return oldval;
|
||||
//}
|
||||
|
||||
inline uint64_t __umulh(uint64_t a, uint64_t b)
|
||||
{
|
||||
|
|
@ -97,95 +82,208 @@ int clock_gettime(int foo, struct timespec *ts);
|
|||
#ifndef InterlockedCompareExchange
|
||||
static __forceinline uint8_t InterlockedCompareExchange(volatile uint8_t* dest, uint8_t exch, uint8_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return _InterlockedCompareExchange8((volatile char*)dest, exch, comp);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint16_t InterlockedCompareExchange(volatile uint16_t* dest, uint16_t exch, uint16_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return _InterlockedCompareExchange16((volatile short*)dest, exch, comp);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint32_t InterlockedCompareExchange(volatile uint32_t* dest, uint32_t exch, uint32_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return _InterlockedCompareExchange((volatile long*)dest, exch, comp);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint64_t InterlockedCompareExchange(volatile uint64_t* dest, uint64_t exch, uint64_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_val_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static __forceinline bool InterlockedCompareExchangeTest(volatile uint8_t* dest, uint8_t exch, uint8_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_bool_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return (uint8_t)_InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp;
|
||||
#endif
|
||||
}
|
||||
static __forceinline bool InterlockedCompareExchangeTest(volatile uint16_t* dest, uint16_t exch, uint16_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_bool_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return (uint16_t)_InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp;
|
||||
#endif
|
||||
}
|
||||
static __forceinline bool InterlockedCompareExchangeTest(volatile uint32_t* dest, uint32_t exch, uint32_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_bool_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return (uint32_t)_InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp;
|
||||
#endif
|
||||
}
|
||||
static __forceinline bool InterlockedCompareExchangeTest(volatile uint64_t* dest, uint64_t exch, uint64_t comp)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_bool_compare_and_swap(dest, comp, exch);
|
||||
#else
|
||||
return (uint64_t)_InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef InterlockedExchange
|
||||
static __forceinline uint8_t InterlockedExchange(volatile uint8_t* dest, uint8_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
#else
|
||||
return _InterlockedExchange8((volatile char*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint16_t InterlockedExchange(volatile uint16_t* dest, uint16_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
#else
|
||||
return _InterlockedExchange16((volatile short*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint32_t InterlockedExchange(volatile uint32_t* dest, uint32_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
#else
|
||||
return _InterlockedExchange((volatile long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint64_t InterlockedExchange(volatile uint64_t* dest, uint64_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_lock_test_and_set(dest, value);
|
||||
#else
|
||||
return _InterlockedExchange64((volatile long long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedOr
|
||||
static __forceinline uint8_t InterlockedOr(volatile uint8_t* dest, uint8_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_or(dest, value);
|
||||
#else
|
||||
return _InterlockedOr8((volatile char*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint16_t InterlockedOr(volatile uint16_t* dest, uint16_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_or(dest, value);
|
||||
#else
|
||||
return _InterlockedOr16((volatile short*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint32_t InterlockedOr(volatile uint32_t* dest, uint32_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_or(dest, value);
|
||||
#else
|
||||
return _InterlockedOr((volatile long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint64_t InterlockedOr(volatile uint64_t* dest, uint64_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_or(dest, value);
|
||||
#else
|
||||
return _InterlockedOr64((volatile long long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedAnd
|
||||
static __forceinline uint8_t InterlockedAnd(volatile uint8_t* dest, uint8_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_and(dest, value);
|
||||
#else
|
||||
return _InterlockedAnd8((volatile char*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint16_t InterlockedAnd(volatile uint16_t* dest, uint16_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_and(dest, value);
|
||||
#else
|
||||
return _InterlockedAnd16((volatile short*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint32_t InterlockedAnd(volatile uint32_t* dest, uint32_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_and(dest, value);
|
||||
#else
|
||||
return _InterlockedAnd((volatile long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint64_t InterlockedAnd(volatile uint64_t* dest, uint64_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_and(dest, value);
|
||||
#else
|
||||
return _InterlockedAnd64((volatile long long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedXor
|
||||
static __forceinline uint8_t InterlockedXor(volatile uint8_t* dest, uint8_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_xor(dest, value);
|
||||
#else
|
||||
return _InterlockedXor8((volatile char*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint16_t InterlockedXor(volatile uint16_t* dest, uint16_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_xor(dest, value);
|
||||
#else
|
||||
return _InterlockedXor16((volatile short*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint32_t InterlockedXor(volatile uint32_t* dest, uint32_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_xor(dest, value);
|
||||
#else
|
||||
return _InterlockedXor((volatile long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
static __forceinline uint64_t InterlockedXor(volatile uint64_t* dest, uint64_t value)
|
||||
{
|
||||
#if defined(__GNUG__)
|
||||
return __sync_fetch_and_xor(dest, value);
|
||||
#else
|
||||
return _InterlockedXor64((volatile long long*)dest, value);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -222,3 +320,17 @@ static __forceinline uint64_t cntlz64(uint64_t arg)
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// compare 16 packed unsigned bytes (greater than)
|
||||
static __forceinline __m128i _mm_cmpgt_epu8(__m128i A, __m128i B)
|
||||
{
|
||||
// (A xor 0x80) > (B xor 0x80)
|
||||
return _mm_cmpgt_epi8(_mm_xor_si128(A, _mm_set1_epi8(-128)), _mm_xor_si128(B, _mm_set1_epi8(-128)));
|
||||
}
|
||||
|
||||
// compare 16 packed unsigned bytes (less or equal)
|
||||
static __forceinline __m128i _mm_cmple_epu8(__m128i A, __m128i B)
|
||||
{
|
||||
// ((B xor 0x80) > (A xor 0x80)) || A == B
|
||||
return _mm_or_si128(_mm_cmpgt_epu8(B, A), _mm_cmpeq_epi8(A, B));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,3 @@ bool SM_IsAborted()
|
|||
{
|
||||
return Emu.IsStopped();
|
||||
}
|
||||
|
||||
void SM_Sleep()
|
||||
{
|
||||
if (NamedThreadBase* t = GetCurrentNamedThread())
|
||||
{
|
||||
t->WaitForAnySignal();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "Emu/Memory/atomic_type.h"
|
||||
|
||||
bool SM_IsAborted();
|
||||
void SM_Sleep();
|
||||
|
||||
enum SMutexResult
|
||||
{
|
||||
|
|
@ -20,8 +19,7 @@ template
|
|||
<
|
||||
typename T,
|
||||
const u64 free_value = 0,
|
||||
const u64 dead_value = 0xffffffffffffffffull,
|
||||
void (*wait)() = SM_Sleep
|
||||
const u64 dead_value = 0xffffffffffffffffull
|
||||
>
|
||||
class SMutexBase
|
||||
{
|
||||
|
|
@ -118,7 +116,7 @@ public:
|
|||
default: return res;
|
||||
}
|
||||
|
||||
if (wait != nullptr) wait();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
|
||||
if (timeout && counter++ > timeout)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
SM_Sleep();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
SM_Sleep();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ public:
|
|||
break;
|
||||
}
|
||||
|
||||
SM_Sleep();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
|
||||
|
|
@ -207,3 +208,58 @@ bool thread::joinable() const
|
|||
{
|
||||
return m_thr.joinable();
|
||||
}
|
||||
|
||||
bool waiter_map_t::is_stopped(u64 signal_id)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
LOG_WARNING(Log::HLE, "%s.waiter_op() aborted (signal_id=0x%llx)", m_name.c_str(), signal_id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
waiter_map_t::waiter_reg_t::waiter_reg_t(waiter_map_t& map, u64 signal_id)
|
||||
: signal_id(signal_id)
|
||||
, thread(GetCurrentNamedThread())
|
||||
, map(map)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(map.m_mutex);
|
||||
|
||||
// add waiter
|
||||
map.m_waiters.push_back({ signal_id, thread });
|
||||
}
|
||||
|
||||
waiter_map_t::waiter_reg_t::~waiter_reg_t()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(map.m_mutex);
|
||||
|
||||
// remove waiter
|
||||
for (size_t i = map.m_waiters.size() - 1; i >= 0; i--)
|
||||
{
|
||||
if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread)
|
||||
{
|
||||
map.m_waiters.erase(map.m_waiters.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str());
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
void waiter_map_t::notify(u64 signal_id)
|
||||
{
|
||||
if (!m_waiters.size()) return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
// find waiter and signal
|
||||
for (auto& v : m_waiters)
|
||||
{
|
||||
if (v.signal_id == signal_id)
|
||||
{
|
||||
v.thread->Notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,56 @@ public:
|
|||
void detach();
|
||||
void join();
|
||||
bool joinable() const;
|
||||
};
|
||||
};
|
||||
|
||||
class waiter_map_t
|
||||
{
|
||||
// TODO: optimize (use custom lightweight readers-writer lock)
|
||||
std::mutex m_mutex;
|
||||
|
||||
struct waiter_t
|
||||
{
|
||||
u64 signal_id;
|
||||
NamedThreadBase* thread;
|
||||
};
|
||||
|
||||
std::vector<waiter_t> m_waiters;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
struct waiter_reg_t
|
||||
{
|
||||
const u64 signal_id;
|
||||
NamedThreadBase* const thread;
|
||||
waiter_map_t& map;
|
||||
|
||||
waiter_reg_t(waiter_map_t& map, u64 signal_id);
|
||||
~waiter_reg_t();
|
||||
};
|
||||
|
||||
bool is_stopped(u64 signal_id);
|
||||
|
||||
public:
|
||||
waiter_map_t(const char* name) : m_name(name) {}
|
||||
|
||||
// wait until waiter_func() returns true, signal_id is an arbitrary number
|
||||
template<typename WT> __forceinline void wait_op(u64 signal_id, const WT waiter_func)
|
||||
{
|
||||
// check condition
|
||||
if (waiter_func()) return;
|
||||
|
||||
// register waiter
|
||||
waiter_reg_t waiter(*this, signal_id);
|
||||
|
||||
while (true)
|
||||
{
|
||||
// wait for 1 ms or until signal arrived
|
||||
waiter.thread->WaitForAnySignal(1);
|
||||
if (is_stopped(signal_id)) break;
|
||||
if (waiter_func()) break;
|
||||
}
|
||||
}
|
||||
|
||||
// signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met)
|
||||
void notify(u64 signal_id);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue