Where Online Learning is simpler!
The C and C++ Include Header Files
/usr/include/c++/13/bits/atomic_futex.h
$ cat -n /usr/include/c++/13/bits/atomic_futex.h 1 // -*- C++ -*- header. 2 3 // Copyright (C) 2015-2023 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 //
. 24 25 /** @file bits/atomic_futex.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. 28 */ 29 30 #ifndef _GLIBCXX_ATOMIC_FUTEX_H 31 #define _GLIBCXX_ATOMIC_FUTEX_H 1 32 33 #pragma GCC system_header 34 35 #include
36 #if ! (defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1) 37 #include
38 #include
39 #endif 40 #include
41 42 #ifndef _GLIBCXX_ALWAYS_INLINE 43 #define _GLIBCXX_ALWAYS_INLINE inline __attribute__((__always_inline__)) 44 #endif 45 46 namespace std _GLIBCXX_VISIBILITY(default) 47 { 48 _GLIBCXX_BEGIN_NAMESPACE_VERSION 49 50 #ifdef _GLIBCXX_HAS_GTHREADS 51 #if defined(_GLIBCXX_HAVE_LINUX_FUTEX) && ATOMIC_INT_LOCK_FREE > 1 52 struct __atomic_futex_unsigned_base 53 { 54 // __s and __ns are measured against CLOCK_REALTIME. Returns false 55 // iff a timeout occurred. 56 bool 57 _M_futex_wait_until(unsigned *__addr, unsigned __val, bool __has_timeout, 58 chrono::seconds __s, chrono::nanoseconds __ns); 59 60 // __s and __ns are measured against CLOCK_MONOTONIC. Returns 61 // false iff a timeout occurred. 62 bool 63 _M_futex_wait_until_steady(unsigned *__addr, unsigned __val, 64 bool __has_timeout, chrono::seconds __s, chrono::nanoseconds __ns); 65 66 // This can be executed after the object has been destroyed. 67 static void _M_futex_notify_all(unsigned* __addr); 68 }; 69 70 template
71 class __atomic_futex_unsigned : __atomic_futex_unsigned_base 72 { 73 typedef chrono::steady_clock __clock_t; 74 75 // This must be lock-free and at offset 0. 76 atomic
_M_data; 77 78 public: 79 explicit 80 __atomic_futex_unsigned(unsigned __data) : _M_data(__data) 81 { } 82 83 _GLIBCXX_ALWAYS_INLINE unsigned 84 _M_load(memory_order __mo) 85 { 86 return _M_data.load(__mo) & ~_Waiter_bit; 87 } 88 89 private: 90 // If a timeout occurs, returns a current value after the timeout; 91 // otherwise, returns the operand's value if equal is true or a different 92 // value if equal is false. 93 // The assumed value is the caller's assumption about the current value 94 // when making the call. 95 // __s and __ns are measured against CLOCK_REALTIME. 96 unsigned 97 _M_load_and_test_until(unsigned __assumed, unsigned __operand, 98 bool __equal, memory_order __mo, bool __has_timeout, 99 chrono::seconds __s, chrono::nanoseconds __ns) 100 { 101 for (;;) 102 { 103 // Don't bother checking the value again because we expect the caller 104 // to have done it recently. 105 // memory_order_relaxed is sufficient because we can rely on just the 106 // modification order (store_notify uses an atomic RMW operation too), 107 // and the futex syscalls synchronize between themselves. 108 _M_data.fetch_or(_Waiter_bit, memory_order_relaxed); 109 bool __ret = _M_futex_wait_until((unsigned*)(void*)&_M_data, 110 __assumed | _Waiter_bit, 111 __has_timeout, __s, __ns); 112 // Fetch the current value after waiting (clears _Waiter_bit). 113 __assumed = _M_load(__mo); 114 if (!__ret || ((__operand == __assumed) == __equal)) 115 return __assumed; 116 // TODO adapt wait time 117 } 118 } 119 120 // If a timeout occurs, returns a current value after the timeout; 121 // otherwise, returns the operand's value if equal is true or a different 122 // value if equal is false. 123 // The assumed value is the caller's assumption about the current value 124 // when making the call. 125 // __s and __ns are measured against CLOCK_MONOTONIC. 126 unsigned 127 _M_load_and_test_until_steady(unsigned __assumed, unsigned __operand, 128 bool __equal, memory_order __mo, bool __has_timeout, 129 chrono::seconds __s, chrono::nanoseconds __ns) 130 { 131 for (;;) 132 { 133 // Don't bother checking the value again because we expect the caller 134 // to have done it recently. 135 // memory_order_relaxed is sufficient because we can rely on just the 136 // modification order (store_notify uses an atomic RMW operation too), 137 // and the futex syscalls synchronize between themselves. 138 _M_data.fetch_or(_Waiter_bit, memory_order_relaxed); 139 bool __ret = _M_futex_wait_until_steady((unsigned*)(void*)&_M_data, 140 __assumed | _Waiter_bit, 141 __has_timeout, __s, __ns); 142 // Fetch the current value after waiting (clears _Waiter_bit). 143 __assumed = _M_load(__mo); 144 if (!__ret || ((__operand == __assumed) == __equal)) 145 return __assumed; 146 // TODO adapt wait time 147 } 148 } 149 150 // Returns the operand's value if equal is true or a different value if 151 // equal is false. 152 // The assumed value is the caller's assumption about the current value 153 // when making the call. 154 unsigned 155 _M_load_and_test(unsigned __assumed, unsigned __operand, 156 bool __equal, memory_order __mo) 157 { 158 return _M_load_and_test_until(__assumed, __operand, __equal, __mo, 159 false, {}, {}); 160 } 161 162 // If a timeout occurs, returns a current value after the timeout; 163 // otherwise, returns the operand's value if equal is true or a different 164 // value if equal is false. 165 // The assumed value is the caller's assumption about the current value 166 // when making the call. 167 template
168 unsigned 169 _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand, 170 bool __equal, memory_order __mo, 171 const chrono::time_point
& __atime) 172 { 173 auto __s = chrono::time_point_cast
(__atime); 174 auto __ns = chrono::duration_cast
(__atime - __s); 175 // XXX correct? 176 return _M_load_and_test_until(__assumed, __operand, __equal, __mo, 177 true, __s.time_since_epoch(), __ns); 178 } 179 180 template
181 unsigned 182 _M_load_and_test_until_impl(unsigned __assumed, unsigned __operand, 183 bool __equal, memory_order __mo, 184 const chrono::time_point
& __atime) 185 { 186 auto __s = chrono::time_point_cast
(__atime); 187 auto __ns = chrono::duration_cast
(__atime - __s); 188 // XXX correct? 189 return _M_load_and_test_until_steady(__assumed, __operand, __equal, __mo, 190 true, __s.time_since_epoch(), __ns); 191 } 192 193 public: 194 195 _GLIBCXX_ALWAYS_INLINE unsigned 196 _M_load_when_not_equal(unsigned __val, memory_order __mo) 197 { 198 unsigned __i = _M_load(__mo); 199 if ((__i & ~_Waiter_bit) != __val) 200 return (__i & ~_Waiter_bit); 201 // TODO Spin-wait first. 202 return _M_load_and_test(__i, __val, false, __mo); 203 } 204 205 _GLIBCXX_ALWAYS_INLINE void 206 _M_load_when_equal(unsigned __val, memory_order __mo) 207 { 208 unsigned __i = _M_load(__mo); 209 if ((__i & ~_Waiter_bit) == __val) 210 return; 211 // TODO Spin-wait first. 212 _M_load_and_test(__i, __val, true, __mo); 213 } 214 215 // Returns false iff a timeout occurred. 216 template
217 _GLIBCXX_ALWAYS_INLINE bool 218 _M_load_when_equal_for(unsigned __val, memory_order __mo, 219 const chrono::duration<_Rep, _Period>& __rtime) 220 { 221 using __dur = typename __clock_t::duration; 222 return _M_load_when_equal_until(__val, __mo, 223 __clock_t::now() + chrono::__detail::ceil<__dur>(__rtime)); 224 } 225 226 // Returns false iff a timeout occurred. 227 template
228 _GLIBCXX_ALWAYS_INLINE bool 229 _M_load_when_equal_until(unsigned __val, memory_order __mo, 230 const chrono::time_point<_Clock, _Duration>& __atime) 231 { 232 typename _Clock::time_point __c_entry = _Clock::now(); 233 do { 234 const __clock_t::time_point __s_entry = __clock_t::now(); 235 const auto __delta = __atime - __c_entry; 236 const auto __s_atime = __s_entry + 237 chrono::__detail::ceil<__clock_t::duration>(__delta); 238 if (_M_load_when_equal_until(__val, __mo, __s_atime)) 239 return true; 240 __c_entry = _Clock::now(); 241 } while (__c_entry < __atime); 242 return false; 243 } 244 245 // Returns false iff a timeout occurred. 246 template
247 _GLIBCXX_ALWAYS_INLINE bool 248 _M_load_when_equal_until(unsigned __val, memory_order __mo, 249 const chrono::time_point
& __atime) 250 { 251 unsigned __i = _M_load(__mo); 252 if ((__i & ~_Waiter_bit) == __val) 253 return true; 254 // TODO Spin-wait first. Ignore effect on timeout. 255 __i = _M_load_and_test_until_impl(__i, __val, true, __mo, __atime); 256 return (__i & ~_Waiter_bit) == __val; 257 } 258 259 // Returns false iff a timeout occurred. 260 template
261 _GLIBCXX_ALWAYS_INLINE bool 262 _M_load_when_equal_until(unsigned __val, memory_order __mo, 263 const chrono::time_point
& __atime) 264 { 265 unsigned __i = _M_load(__mo); 266 if ((__i & ~_Waiter_bit) == __val) 267 return true; 268 // TODO Spin-wait first. Ignore effect on timeout. 269 __i = _M_load_and_test_until_impl(__i, __val, true, __mo, __atime); 270 return (__i & ~_Waiter_bit) == __val; 271 } 272 273 _GLIBCXX_ALWAYS_INLINE void 274 _M_store_notify_all(unsigned __val, memory_order __mo) 275 { 276 unsigned* __futex = (unsigned *)(void *)&_M_data; 277 if (_M_data.exchange(__val, __mo) & _Waiter_bit) 278 _M_futex_notify_all(__futex); 279 } 280 }; 281 282 #else // ! (_GLIBCXX_HAVE_LINUX_FUTEX && ATOMIC_INT_LOCK_FREE > 1) 283 284 // If futexes are not available, use a mutex and a condvar to wait. 285 // Because we access the data only within critical sections, all accesses 286 // are sequentially consistent; thus, we satisfy any provided memory_order. 287 template
288 class __atomic_futex_unsigned 289 { 290 typedef chrono::system_clock __clock_t; 291 292 unsigned _M_data; 293 mutex _M_mutex; 294 condition_variable _M_condvar; 295 296 public: 297 explicit 298 __atomic_futex_unsigned(unsigned __data) : _M_data(__data) 299 { } 300 301 _GLIBCXX_ALWAYS_INLINE unsigned 302 _M_load(memory_order __mo) 303 { 304 unique_lock
__lock(_M_mutex); 305 return _M_data; 306 } 307 308 _GLIBCXX_ALWAYS_INLINE unsigned 309 _M_load_when_not_equal(unsigned __val, memory_order __mo) 310 { 311 unique_lock
__lock(_M_mutex); 312 while (_M_data == __val) 313 _M_condvar.wait(__lock); 314 return _M_data; 315 } 316 317 _GLIBCXX_ALWAYS_INLINE void 318 _M_load_when_equal(unsigned __val, memory_order __mo) 319 { 320 unique_lock
__lock(_M_mutex); 321 while (_M_data != __val) 322 _M_condvar.wait(__lock); 323 } 324 325 template
326 _GLIBCXX_ALWAYS_INLINE bool 327 _M_load_when_equal_for(unsigned __val, memory_order __mo, 328 const chrono::duration<_Rep, _Period>& __rtime) 329 { 330 unique_lock
__lock(_M_mutex); 331 return _M_condvar.wait_for(__lock, __rtime, 332 [&] { return _M_data == __val;}); 333 } 334 335 template
336 _GLIBCXX_ALWAYS_INLINE bool 337 _M_load_when_equal_until(unsigned __val, memory_order __mo, 338 const chrono::time_point<_Clock, _Duration>& __atime) 339 { 340 unique_lock
__lock(_M_mutex); 341 return _M_condvar.wait_until(__lock, __atime, 342 [&] { return _M_data == __val;}); 343 } 344 345 _GLIBCXX_ALWAYS_INLINE void 346 _M_store_notify_all(unsigned __val, memory_order __mo) 347 { 348 unique_lock
__lock(_M_mutex); 349 _M_data = __val; 350 _M_condvar.notify_all(); 351 } 352 }; 353 354 #endif // _GLIBCXX_HAVE_LINUX_FUTEX && ATOMIC_INT_LOCK_FREE > 1 355 #endif // _GLIBCXX_HAS_GTHREADS 356 357 _GLIBCXX_END_NAMESPACE_VERSION 358 } // namespace std 359 360 #endif
Contact us
|
About us
|
Term of use
|
Copyright © 2000-2025 MyWebUniversity.com ™