diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/atomic_ops.h | 90 | ||||
| -rw-r--r-- | src/common/x64/native_clock.cpp | 10 |
2 files changed, 96 insertions, 4 deletions
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h index b94d73c7a..69fde8421 100644 --- a/src/common/atomic_ops.h +++ b/src/common/atomic_ops.h | |||
| @@ -46,6 +46,50 @@ namespace Common { | |||
| 46 | reinterpret_cast<__int64*>(expected.data())) != 0; | 46 | reinterpret_cast<__int64*>(expected.data())) != 0; |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, | ||
| 50 | u8& actual) { | ||
| 51 | actual = | ||
| 52 | _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected); | ||
| 53 | return actual == expected; | ||
| 54 | } | ||
| 55 | |||
| 56 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, | ||
| 57 | u16& actual) { | ||
| 58 | actual = | ||
| 59 | _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected); | ||
| 60 | return actual == expected; | ||
| 61 | } | ||
| 62 | |||
| 63 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, | ||
| 64 | u32& actual) { | ||
| 65 | actual = | ||
| 66 | _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected); | ||
| 67 | return actual == expected; | ||
| 68 | } | ||
| 69 | |||
| 70 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, | ||
| 71 | u64& actual) { | ||
| 72 | actual = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer), value, | ||
| 73 | expected); | ||
| 74 | return actual == expected; | ||
| 75 | } | ||
| 76 | |||
| 77 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, | ||
| 78 | u128& actual) { | ||
| 79 | const bool result = | ||
| 80 | _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1], | ||
| 81 | value[0], reinterpret_cast<__int64*>(expected.data())) != 0; | ||
| 82 | actual = expected; | ||
| 83 | return result; | ||
| 84 | } | ||
| 85 | |||
| 86 | [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { | ||
| 87 | u128 result{}; | ||
| 88 | _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), result[1], | ||
| 89 | result[0], reinterpret_cast<__int64*>(result.data())); | ||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 49 | #else | 93 | #else |
| 50 | 94 | ||
| 51 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { | 95 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) { |
| @@ -72,6 +116,52 @@ namespace Common { | |||
| 72 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | 116 | return __sync_bool_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); |
| 73 | } | 117 | } |
| 74 | 118 | ||
| 119 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected, | ||
| 120 | u8& actual) { | ||
| 121 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 122 | return actual == expected; | ||
| 123 | } | ||
| 124 | |||
| 125 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected, | ||
| 126 | u16& actual) { | ||
| 127 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 128 | return actual == expected; | ||
| 129 | } | ||
| 130 | |||
| 131 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected, | ||
| 132 | u32& actual) { | ||
| 133 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 134 | return actual == expected; | ||
| 135 | } | ||
| 136 | |||
| 137 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected, | ||
| 138 | u64& actual) { | ||
| 139 | actual = __sync_val_compare_and_swap(pointer, expected, value); | ||
| 140 | return actual == expected; | ||
| 141 | } | ||
| 142 | |||
| 143 | [[nodiscard]] inline bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected, | ||
| 144 | u128& actual) { | ||
| 145 | unsigned __int128 value_a; | ||
| 146 | unsigned __int128 expected_a; | ||
| 147 | unsigned __int128 actual_a; | ||
| 148 | std::memcpy(&value_a, value.data(), sizeof(u128)); | ||
| 149 | std::memcpy(&expected_a, expected.data(), sizeof(u128)); | ||
| 150 | actual_a = __sync_val_compare_and_swap((unsigned __int128*)pointer, expected_a, value_a); | ||
| 151 | std::memcpy(actual.data(), &actual_a, sizeof(u128)); | ||
| 152 | return actual_a == expected_a; | ||
| 153 | } | ||
| 154 | |||
| 155 | [[nodiscard]] inline u128 AtomicLoad128(volatile u64* pointer) { | ||
| 156 | unsigned __int128 zeros_a = 0; | ||
| 157 | unsigned __int128 result_a = | ||
| 158 | __sync_val_compare_and_swap((unsigned __int128*)pointer, zeros_a, zeros_a); | ||
| 159 | |||
| 160 | u128 result; | ||
| 161 | std::memcpy(result.data(), &result_a, sizeof(u128)); | ||
| 162 | return result; | ||
| 163 | } | ||
| 164 | |||
| 75 | #endif | 165 | #endif |
| 76 | 166 | ||
| 77 | } // namespace Common | 167 | } // namespace Common |
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 347e41efc..7a3f21dcf 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp | |||
| @@ -55,8 +55,9 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequen | |||
| 55 | u64 NativeClock::GetRTSC() { | 55 | u64 NativeClock::GetRTSC() { |
| 56 | TimePoint new_time_point{}; | 56 | TimePoint new_time_point{}; |
| 57 | TimePoint current_time_point{}; | 57 | TimePoint current_time_point{}; |
| 58 | |||
| 59 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 58 | do { | 60 | do { |
| 59 | current_time_point.pack = time_point.pack; | ||
| 60 | _mm_mfence(); | 61 | _mm_mfence(); |
| 61 | const u64 current_measure = __rdtsc(); | 62 | const u64 current_measure = __rdtsc(); |
| 62 | u64 diff = current_measure - current_time_point.inner.last_measure; | 63 | u64 diff = current_measure - current_time_point.inner.last_measure; |
| @@ -66,7 +67,7 @@ u64 NativeClock::GetRTSC() { | |||
| 66 | : current_time_point.inner.last_measure; | 67 | : current_time_point.inner.last_measure; |
| 67 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; | 68 | new_time_point.inner.accumulated_ticks = current_time_point.inner.accumulated_ticks + diff; |
| 68 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | 69 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |
| 69 | current_time_point.pack)); | 70 | current_time_point.pack, current_time_point.pack)); |
| 70 | /// The clock cannot be more precise than the guest timer, remove the lower bits | 71 | /// The clock cannot be more precise than the guest timer, remove the lower bits |
| 71 | return new_time_point.inner.accumulated_ticks & inaccuracy_mask; | 72 | return new_time_point.inner.accumulated_ticks & inaccuracy_mask; |
| 72 | } | 73 | } |
| @@ -75,13 +76,14 @@ void NativeClock::Pause(bool is_paused) { | |||
| 75 | if (!is_paused) { | 76 | if (!is_paused) { |
| 76 | TimePoint current_time_point{}; | 77 | TimePoint current_time_point{}; |
| 77 | TimePoint new_time_point{}; | 78 | TimePoint new_time_point{}; |
| 79 | |||
| 80 | current_time_point.pack = Common::AtomicLoad128(time_point.pack.data()); | ||
| 78 | do { | 81 | do { |
| 79 | current_time_point.pack = time_point.pack; | ||
| 80 | new_time_point.pack = current_time_point.pack; | 82 | new_time_point.pack = current_time_point.pack; |
| 81 | _mm_mfence(); | 83 | _mm_mfence(); |
| 82 | new_time_point.inner.last_measure = __rdtsc(); | 84 | new_time_point.inner.last_measure = __rdtsc(); |
| 83 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, | 85 | } while (!Common::AtomicCompareAndSwap(time_point.pack.data(), new_time_point.pack, |
| 84 | current_time_point.pack)); | 86 | current_time_point.pack, current_time_point.pack)); |
| 85 | } | 87 | } |
| 86 | } | 88 | } |
| 87 | 89 | ||