11
11
12
12
#include < Windows.h>
13
13
14
- #pragma comment(lib, "synchronization")
15
-
16
14
namespace {
17
15
constexpr unsigned long long _Atomic_wait_no_deadline = 0xFFFF'FFFF'FFFF'FFFF ;
18
16
@@ -91,13 +89,134 @@ namespace {
91
89
}
92
90
#endif // defined(_DEBUG)
93
91
}
92
+
93
+ #ifndef _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
94
+ #if _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8
95
+ #define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 1
96
+ #else // ^^^ _STL_WIN32_WINNT >= _STL_WIN32_WINNT_WIN8 / _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 vvv
97
+ #define _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE 0
98
+ #endif // ^^^ _STL_WIN32_WINNT < _STL_WIN32_WINNT_WIN8 ^^^
99
+ #endif // !defined(_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE)
100
+
101
+ #if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
102
+
103
+ #pragma comment(lib, "synchronization")
104
+
105
+ #define __crtWaitOnAddress WaitOnAddress
106
+ #define __crtWakeByAddressSingle WakeByAddressSingle
107
+ #define __crtWakeByAddressAll WakeByAddressAll
108
+
109
+ #else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv
110
+
111
+ struct _Wait_functions_table {
112
+ _STD atomic<decltype (&::WaitOnAddress)> _Pfn_WaitOnAddress{nullptr };
113
+ _STD atomic<decltype (&::WakeByAddressSingle)> _Pfn_WakeByAddressSingle{nullptr };
114
+ _STD atomic<decltype (&::WakeByAddressAll)> _Pfn_WakeByAddressAll{nullptr };
115
+ _STD atomic<__std_atomic_api_level> _Api_level{__std_atomic_api_level::__not_set};
116
+ };
117
+
118
+ _Wait_functions_table _Wait_functions;
119
+
120
+ void _Force_wait_functions_srwlock_only () noexcept {
121
+ auto _Local = _Wait_functions._Api_level .load (_STD memory_order_acquire);
122
+ if (_Local <= __std_atomic_api_level::__detecting) {
123
+ while (!_Wait_functions._Api_level .compare_exchange_weak (
124
+ _Local, __std_atomic_api_level::__has_srwlock, _STD memory_order_acq_rel)) {
125
+ if (_Local > __std_atomic_api_level::__detecting) {
126
+ return ;
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ [[nodiscard]] __std_atomic_api_level _Init_wait_functions (__std_atomic_api_level _Level) {
133
+ while (!_Wait_functions._Api_level .compare_exchange_weak (
134
+ _Level, __std_atomic_api_level::__detecting, _STD memory_order_acq_rel)) {
135
+ if (_Level > __std_atomic_api_level::__detecting) {
136
+ return _Level;
137
+ }
138
+ }
139
+
140
+ _Level = __std_atomic_api_level::__has_srwlock;
141
+
142
+ const HMODULE _Sync_module = GetModuleHandleW (L" api-ms-win-core-synch-l1-2-0.dll" );
143
+ if (_Sync_module != nullptr ) {
144
+ const auto _Wait_on_address =
145
+ reinterpret_cast <decltype (&::WaitOnAddress)>(GetProcAddress (_Sync_module, " WaitOnAddress" ));
146
+ const auto _Wake_by_address_single =
147
+ reinterpret_cast <decltype (&::WakeByAddressSingle)>(GetProcAddress (_Sync_module, " WakeByAddressSingle" ));
148
+ const auto _Wake_by_address_all =
149
+ reinterpret_cast <decltype (&::WakeByAddressAll)>(GetProcAddress (_Sync_module, " WakeByAddressAll" ));
150
+
151
+ if (_Wait_on_address != nullptr && _Wake_by_address_single != nullptr && _Wake_by_address_all != nullptr ) {
152
+ _Wait_functions._Pfn_WaitOnAddress .store (_Wait_on_address, _STD memory_order_relaxed);
153
+ _Wait_functions._Pfn_WakeByAddressSingle .store (_Wake_by_address_single, _STD memory_order_relaxed);
154
+ _Wait_functions._Pfn_WakeByAddressAll .store (_Wake_by_address_all, _STD memory_order_relaxed);
155
+ _Level = __std_atomic_api_level::__has_wait_on_address;
156
+ }
157
+ }
158
+
159
+ // for __has_srwlock, relaxed would have been enough, not distinguishing for consistency
160
+ _Wait_functions._Api_level .store (_Level, _STD memory_order_release);
161
+ return _Level;
162
+ }
163
+
164
+ [[nodiscard]] __std_atomic_api_level _Acquire_wait_functions () noexcept {
165
+ auto _Level = _Wait_functions._Api_level .load (_STD memory_order_acquire);
166
+ if (_Level <= __std_atomic_api_level::__detecting) {
167
+ _Level = _Init_wait_functions (_Level);
168
+ }
169
+
170
+ return _Level;
171
+ }
172
+
173
+ [[nodiscard]] BOOL __crtWaitOnAddress (
174
+ volatile VOID* Address, PVOID CompareAddress, SIZE_T AddressSize, DWORD dwMilliseconds) {
175
+ const auto _Wait_on_address = _Wait_functions._Pfn_WaitOnAddress .load (_STD memory_order_relaxed);
176
+ return _Wait_on_address (Address, CompareAddress, AddressSize, dwMilliseconds);
177
+ }
178
+
179
+ VOID __crtWakeByAddressSingle (PVOID Address) {
180
+ const auto _Wake_by_address_single = _Wait_functions._Pfn_WakeByAddressSingle .load (_STD memory_order_relaxed);
181
+ _Wake_by_address_single (Address);
182
+ }
183
+
184
+ VOID __crtWakeByAddressAll (PVOID Address) {
185
+ const auto _Wake_by_address_all = _Wait_functions._Pfn_WakeByAddressAll .load (_STD memory_order_relaxed);
186
+ _Wake_by_address_all (Address);
187
+ }
188
+
189
+ bool __stdcall _Atomic_wait_are_equal_direct_fallback (
190
+ const void * _Storage, void * _Comparand, size_t _Size, void *) noexcept {
191
+ switch (_Size) {
192
+ case 1 :
193
+ return __iso_volatile_load8 (static_cast <const char *>(_Storage)) == *static_cast <const char *>(_Comparand);
194
+ case 2 :
195
+ return __iso_volatile_load16 (static_cast <const short *>(_Storage)) == *static_cast <const short *>(_Comparand);
196
+ case 4 :
197
+ return __iso_volatile_load32 (static_cast <const int *>(_Storage)) == *static_cast <const int *>(_Comparand);
198
+ case 8 :
199
+ return __iso_volatile_load64 (static_cast <const long long *>(_Storage))
200
+ == *static_cast <const long long *>(_Comparand);
201
+ default :
202
+ _CSTD abort ();
203
+ }
204
+ }
205
+ #endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
94
206
} // unnamed namespace
95
207
96
208
extern " C" {
97
209
int __stdcall __std_atomic_wait_direct (const void * const _Storage, void * const _Comparand, const size_t _Size,
98
210
const unsigned long _Remaining_timeout) noexcept {
99
- const auto _Result =
100
- WaitOnAddress (const_cast <volatile void *>(_Storage), const_cast <void *>(_Comparand), _Size, _Remaining_timeout);
211
+ #if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
212
+ if (_Acquire_wait_functions () < __std_atomic_api_level::__has_wait_on_address) {
213
+ return __std_atomic_wait_indirect (
214
+ _Storage, _Comparand, _Size, nullptr , &_Atomic_wait_are_equal_direct_fallback, _Remaining_timeout);
215
+ }
216
+ #endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
217
+
218
+ const auto _Result = __crtWaitOnAddress (
219
+ const_cast <volatile void *>(_Storage), const_cast <void *>(_Comparand), _Size, _Remaining_timeout);
101
220
102
221
if (!_Result) {
103
222
_Assume_timeout ();
@@ -106,11 +225,25 @@ int __stdcall __std_atomic_wait_direct(const void* const _Storage, void* const _
106
225
}
107
226
108
227
void __stdcall __std_atomic_notify_one_direct (const void * const _Storage) noexcept {
109
- WakeByAddressSingle (const_cast <void *>(_Storage));
228
+ #if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
229
+ if (_Acquire_wait_functions () < __std_atomic_api_level::__has_wait_on_address) {
230
+ __std_atomic_notify_one_indirect (_Storage);
231
+ return ;
232
+ }
233
+ #endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE = 0
234
+
235
+ __crtWakeByAddressSingle (const_cast <void *>(_Storage));
110
236
}
111
237
112
238
void __stdcall __std_atomic_notify_all_direct (const void * const _Storage) noexcept {
113
- WakeByAddressAll (const_cast <void *>(_Storage));
239
+ #if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
240
+ if (_Acquire_wait_functions () < __std_atomic_api_level::__has_wait_on_address) {
241
+ __std_atomic_notify_all_indirect (_Storage);
242
+ return ;
243
+ }
244
+ #endif // _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE == 0
245
+
246
+ __crtWakeByAddressAll (const_cast <void *>(_Storage));
114
247
}
115
248
116
249
void __stdcall __std_atomic_notify_one_indirect (const void * const _Storage) noexcept {
@@ -206,10 +339,25 @@ unsigned long __stdcall __std_atomic_wait_get_remaining_timeout(unsigned long lo
206
339
return static_cast <unsigned long >(_Remaining);
207
340
}
208
341
209
- // TRANSITION, ABI: preserved for binary compatibility
210
- enum class __std_atomic_api_level : unsigned long { __not_set, __detecting, __has_srwlock, __has_wait_on_address };
211
- __std_atomic_api_level __stdcall __std_atomic_set_api_level (__std_atomic_api_level) noexcept {
342
+ __std_atomic_api_level __stdcall __std_atomic_set_api_level (__std_atomic_api_level _Requested_api_level) noexcept {
343
+ # if _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
344
+ ( void ) _Requested_api_level;
212
345
return __std_atomic_api_level::__has_wait_on_address;
346
+ #else // ^^^ _ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE / !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE vvv
347
+ switch (_Requested_api_level) {
348
+ case __std_atomic_api_level::__not_set:
349
+ case __std_atomic_api_level::__detecting:
350
+ _CSTD abort ();
351
+ case __std_atomic_api_level::__has_srwlock:
352
+ _Force_wait_functions_srwlock_only ();
353
+ break ;
354
+ case __std_atomic_api_level::__has_wait_on_address:
355
+ default : // future compat: new header using an old DLL will get the highest requested level supported
356
+ break ;
357
+ }
358
+
359
+ return _Acquire_wait_functions ();
360
+ #endif // !_ATOMIC_WAIT_ON_ADDRESS_STATICALLY_AVAILABLE
213
361
}
214
362
215
363
#pragma warning(push)
0 commit comments