Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/bits/semaphore_base.h
1 // -*- C++ -*- header. 2 3 // Copyright (C) 2020-2025 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 // <http://www.gnu.org/licenses/>. 24 25 /** @file bits/semaphore_base.h 26 * This is an internal header file, included by other library headers. 27 * Do not attempt to use it directly. @headername{semaphore} 28 */ 29 30 #ifndef _GLIBCXX_SEMAPHORE_BASE_H 31 #define _GLIBCXX_SEMAPHORE_BASE_H 1 32 33 #ifdef _GLIBCXX_SYSHDR 34 #pragma GCC system_header 35 #endif 36 37 #include <bits/atomic_base.h> 38 #include <bits/chrono.h> 39 #if __glibcxx_atomic_wait 40 #include <bits/atomic_timed_wait.h> 41 #include <ext/numeric_traits.h> 42 #endif // __cpp_lib_atomic_wait 43 44 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE 45 # include <cerrno> // errno, EINTR, EAGAIN etc. 46 # include <limits.h> // SEM_VALUE_MAX 47 # include <semaphore.h> // sem_t, sem_init, sem_wait, sem_post etc. 48 #elif defined(_GLIBCXX_USE_POSIX_SEMAPHORE) 49 # warning "POSIX semaphore not available, ignoring _GLIBCXX_USE_POSIX_SEMAPHORE" 50 # undef _GLIBCXX_USE_POSIX_SEMAPHORE 51 #endif 52 53 namespace std _GLIBCXX_VISIBILITY(default) 54 { 55 _GLIBCXX_BEGIN_NAMESPACE_VERSION 56 57 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE 58 struct __platform_semaphore 59 { 60 using __clock_t = chrono::system_clock; 61 #ifdef SEM_VALUE_MAX 62 static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX; 63 #else 64 static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX; 65 #endif 66 67 explicit __platform_semaphore(ptrdiff_t __count) noexcept 68 { 69 sem_init(&_M_semaphore, 0, __count); 70 } 71 72 __platform_semaphore(const __platform_semaphore&) = delete; 73 __platform_semaphore& operator=(const __platform_semaphore&) = delete; 74 75 ~__platform_semaphore() 76 { sem_destroy(&_M_semaphore); } 77 78 _GLIBCXX_ALWAYS_INLINE void 79 _M_acquire() noexcept 80 { 81 while (sem_wait(&_M_semaphore)) 82 if (errno != EINTR) 83 std::__terminate(); 84 } 85 86 _GLIBCXX_ALWAYS_INLINE bool 87 _M_try_acquire() noexcept 88 { 89 while (sem_trywait(&_M_semaphore)) 90 { 91 if (errno == EAGAIN) // already locked 92 return false; 93 else if (errno != EINTR) 94 std::__terminate(); 95 // else got EINTR so retry 96 } 97 return true; 98 } 99 100 _GLIBCXX_ALWAYS_INLINE void 101 _M_release(ptrdiff_t __update) noexcept 102 { 103 for(; __update != 0; --__update) 104 if (sem_post(&_M_semaphore)) 105 std::__terminate(); 106 } 107 108 bool 109 _M_try_acquire_until_impl(const chrono::time_point<__clock_t>& __atime) 110 noexcept 111 { 112 auto __s = chrono::time_point_cast<chrono::seconds>(__atime); 113 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); 114 115 struct timespec __ts = 116 { 117 static_cast<std::time_t>(__s.time_since_epoch().count()), 118 static_cast<long>(__ns.count()) 119 }; 120 121 while (sem_timedwait(&_M_semaphore, &__ts)) 122 { 123 if (errno == ETIMEDOUT) 124 return false; 125 else if (errno != EINTR) 126 std::__terminate(); 127 } 128 return true; 129 } 130 131 template<typename _Clock, typename _Duration> 132 bool 133 _M_try_acquire_until(const chrono::time_point<_Clock, 134 _Duration>& __atime) noexcept 135 { 136 if constexpr (std::is_same_v<__clock_t, _Clock>) 137 { 138 using _Dur = __clock_t::duration; 139 return _M_try_acquire_until_impl(chrono::ceil<_Dur>(__atime)); 140 } 141 else 142 { 143 // TODO: if _Clock is monotonic_clock we could use 144 // sem_clockwait with CLOCK_MONOTONIC. 145 146 const typename _Clock::time_point __c_entry = _Clock::now(); 147 const auto __s_entry = __clock_t::now(); 148 const auto __delta = __atime - __c_entry; 149 const auto __s_atime = __s_entry + __delta; 150 if (_M_try_acquire_until_impl(__s_atime)) 151 return true; 152 153 // We got a timeout when measured against __clock_t but 154 // we need to check against the caller-supplied clock 155 // to tell whether we should return a timeout. 156 return (_Clock::now() < __atime); 157 } 158 } 159 160 template<typename _Rep, typename _Period> 161 _GLIBCXX_ALWAYS_INLINE bool 162 _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) 163 noexcept 164 { return _M_try_acquire_until(__clock_t::now() + __rtime); } 165 166 private: 167 sem_t _M_semaphore; 168 }; 169 #endif // _GLIBCXX_HAVE_POSIX_SEMAPHORE 170 171 #if __glibcxx_atomic_wait 172 struct __atomic_semaphore 173 { 174 static constexpr ptrdiff_t _S_max = __gnu_cxx::__int_traits<int>::__max; 175 explicit __atomic_semaphore(__detail::__platform_wait_t __count) noexcept 176 : _M_counter(__count) 177 { 178 __glibcxx_assert(__count >= 0 && __count <= _S_max); 179 } 180 181 __atomic_semaphore(const __atomic_semaphore&) = delete; 182 __atomic_semaphore& operator=(const __atomic_semaphore&) = delete; 183 184 static _GLIBCXX_ALWAYS_INLINE bool 185 _S_do_try_acquire(__detail::__platform_wait_t* __counter) noexcept 186 { 187 auto __old = __atomic_impl::load(__counter, memory_order::acquire); 188 if (__old == 0) 189 return false; 190 191 return __atomic_impl::compare_exchange_strong(__counter, 192 __old, __old - 1, 193 memory_order::acquire, 194 memory_order::relaxed); 195 } 196 197 _GLIBCXX_ALWAYS_INLINE void 198 _M_acquire() noexcept 199 { 200 auto const __pred = 201 [this] { return _S_do_try_acquire(&this->_M_counter); }; 202 std::__atomic_wait_address_bare(&_M_counter, __pred); 203 } 204 205 bool 206 _M_try_acquire() noexcept 207 { 208 auto const __pred = 209 [this] { return _S_do_try_acquire(&this->_M_counter); }; 210 return std::__detail::__atomic_spin(__pred); 211 } 212 213 template<typename _Clock, typename _Duration> 214 _GLIBCXX_ALWAYS_INLINE bool 215 _M_try_acquire_until(const chrono::time_point<_Clock, 216 _Duration>& __atime) noexcept 217 { 218 auto const __pred = 219 [this] { return _S_do_try_acquire(&this->_M_counter); }; 220 221 return __atomic_wait_address_until_bare(&_M_counter, __pred, __atime); 222 } 223 224 template<typename _Rep, typename _Period> 225 _GLIBCXX_ALWAYS_INLINE bool 226 _M_try_acquire_for(const chrono::duration<_Rep, _Period>& __rtime) 227 noexcept 228 { 229 auto const __pred = 230 [this] { return _S_do_try_acquire(&this->_M_counter); }; 231 232 return __atomic_wait_address_for_bare(&_M_counter, __pred, __rtime); 233 } 234 235 _GLIBCXX_ALWAYS_INLINE void 236 _M_release(ptrdiff_t __update) noexcept 237 { 238 if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release)) 239 return; 240 if (__update > 1) 241 __atomic_notify_address_bare(&_M_counter, true); 242 else 243 __atomic_notify_address_bare(&_M_counter, true); 244 // FIXME - Figure out why this does not wake a waiting thread 245 // __atomic_notify_address_bare(&_M_counter, false); 246 } 247 248 private: 249 alignas(__detail::__platform_wait_alignment) 250 __detail::__platform_wait_t _M_counter; 251 }; 252 #endif // __cpp_lib_atomic_wait 253 254 // Note: the _GLIBCXX_USE_POSIX_SEMAPHORE macro can be used to force the 255 // use of Posix semaphores (sem_t). Doing so however, alters the ABI. 256 #if defined __glibcxx_atomic_wait && !_GLIBCXX_USE_POSIX_SEMAPHORE 257 using __semaphore_impl = __atomic_semaphore; 258 #elif _GLIBCXX_HAVE_POSIX_SEMAPHORE 259 using __semaphore_impl = __platform_semaphore; 260 #endif 261 262 _GLIBCXX_END_NAMESPACE_VERSION 263 } // namespace std 264 #endif // _GLIBCXX_SEMAPHORE_BASE_H