summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/atomic_ops.h90
-rw-r--r--src/common/x64/native_clock.cpp10
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
55u64 NativeClock::GetRTSC() { 55u64 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