30 #ifndef _GLIBCXX_SEMAPHORE_BASE_H
31 #define _GLIBCXX_SEMAPHORE_BASE_H 1
33 #pragma GCC system_header
36 #if __cpp_lib_atomic_wait
41 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
43 # include <semaphore.h>
47 #include <type_traits>
49 namespace std _GLIBCXX_VISIBILITY(default)
51 _GLIBCXX_BEGIN_NAMESPACE_VERSION
53 #ifdef _GLIBCXX_HAVE_POSIX_SEMAPHORE
54 struct __platform_semaphore
56 using __clock_t = chrono::system_clock;
58 static constexpr ptrdiff_t _S_max = SEM_VALUE_MAX;
60 static constexpr ptrdiff_t _S_max = _POSIX_SEM_VALUE_MAX;
63 explicit __platform_semaphore(ptrdiff_t __count) noexcept
65 sem_init(&_M_semaphore, 0, __count);
68 __platform_semaphore(
const __platform_semaphore&) =
delete;
69 __platform_semaphore&
operator=(
const __platform_semaphore&) =
delete;
71 ~__platform_semaphore()
72 { sem_destroy(&_M_semaphore); }
74 _GLIBCXX_ALWAYS_INLINE
void
79 auto __err = sem_wait(&_M_semaphore);
80 if (__err && (errno == EINTR))
89 _GLIBCXX_ALWAYS_INLINE
void
90 _M_release(std::ptrdiff_t __update) noexcept
92 for(; __update != 0; --__update)
94 auto __err = sem_post(&_M_semaphore);
101 _M_try_acquire_until_impl(
const chrono::time_point<__clock_t>& __atime)
105 auto __s = chrono::time_point_cast<chrono::seconds>(__atime);
106 auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s);
108 struct timespec __ts =
110 static_cast<std::time_t
>(__s.time_since_epoch().count()),
111 static_cast<long>(__ns.count())
116 if (
auto __err = sem_timedwait(&_M_semaphore, &__ts))
120 else if (errno == ETIMEDOUT || errno == EINVAL)
131 template<
typename _Clock,
typename _Duration>
133 _M_try_acquire_until(
const chrono::time_point<_Clock,
134 _Duration>& __atime) noexcept
136 if constexpr (std::is_same_v<__clock_t, _Clock>)
138 return _M_try_acquire_until_impl(__atime);
142 const typename _Clock::time_point __c_entry = _Clock::now();
143 const auto __s_entry = __clock_t::now();
144 const auto __delta = __atime - __c_entry;
145 const auto __s_atime = __s_entry + __delta;
146 if (_M_try_acquire_until_impl(__s_atime))
152 return (_Clock::now() < __atime);
156 template<
typename _Rep,
typename _Period>
157 _GLIBCXX_ALWAYS_INLINE
bool
158 _M_try_acquire_for(
const chrono::duration<_Rep, _Period>& __rtime)
160 {
return _M_try_acquire_until(__clock_t::now() + __rtime); }
167 template<
typename _Tp>
168 struct __atomic_semaphore
170 static_assert(std::is_integral_v<_Tp>);
175 explicit __atomic_semaphore(_Tp __count) noexcept
176 : _M_counter(__count)
178 __glibcxx_assert(__count >= 0 && __count <= _S_max);
181 __atomic_semaphore(
const __atomic_semaphore&) =
delete;
182 __atomic_semaphore&
operator=(
const __atomic_semaphore&) =
delete;
184 _GLIBCXX_ALWAYS_INLINE
void
185 _M_acquire() noexcept
187 auto const __pred = [
this]
189 auto __old = __atomic_impl::load(&this->_M_counter,
190 memory_order::acquire);
193 return __atomic_impl::compare_exchange_strong(&this->_M_counter,
195 memory_order::acquire,
198 auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
199 std::__atomic_wait(&_M_counter, __old, __pred);
203 _M_try_acquire() noexcept
205 auto __old = __atomic_impl::load(&_M_counter, memory_order::acquire);
206 auto const __pred = [
this, __old]
212 return __atomic_impl::compare_exchange_weak(&this->_M_counter,
214 memory_order::acquire,
217 return std::__atomic_spin(__pred);
220 template<
typename _Clock,
typename _Duration>
221 _GLIBCXX_ALWAYS_INLINE
bool
222 _M_try_acquire_until(
const chrono::time_point<_Clock,
223 _Duration>& __atime) noexcept
225 auto const __pred = [
this]
227 auto __old = __atomic_impl::load(&this->_M_counter,
228 memory_order::acquire);
231 return __atomic_impl::compare_exchange_strong(&this->_M_counter,
233 memory_order::acquire,
237 auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
238 return __atomic_wait_until(&_M_counter, __old, __pred, __atime);
241 template<
typename _Rep,
typename _Period>
242 _GLIBCXX_ALWAYS_INLINE
bool
243 _M_try_acquire_for(
const chrono::duration<_Rep, _Period>& __rtime)
246 auto const __pred = [
this]
248 auto __old = __atomic_impl::load(&this->_M_counter,
249 memory_order::acquire);
252 return __atomic_impl::compare_exchange_strong(&this->_M_counter,
254 memory_order::acquire,
258 auto __old = __atomic_impl::load(&_M_counter, memory_order_relaxed);
259 return __atomic_wait_for(&_M_counter, __old, __pred, __rtime);
262 _GLIBCXX_ALWAYS_INLINE
void
263 _M_release(ptrdiff_t __update) noexcept
265 if (0 < __atomic_impl::fetch_add(&_M_counter, __update, memory_order_release))
268 __atomic_impl::notify_all(&_M_counter);
270 __atomic_impl::notify_one(&_M_counter);
274 alignas(__alignof__(_Tp)) _Tp _M_counter;
279 #if defined _GLIBCXX_HAVE_LINUX_FUTEX && !_GLIBCXX_REQUIRE_POSIX_SEMAPHORE
281 using __fast_semaphore = __atomic_semaphore<__detail::__platform_wait_t>;
282 #elif _GLIBCXX_HAVE_POSIX_SEMAPHORE
283 using __fast_semaphore = __platform_semaphore;
285 using __fast_semaphore = __atomic_semaphore<ptrdiff_t>;
288 template<ptrdiff_t __least_max_value>
290 (__least_max_value > 1),
292 (__least_max_value <= __fast_semaphore::_S_max),
294 __atomic_semaphore<ptrdiff_t>>,
297 _GLIBCXX_END_NAMESPACE_VERSION
auto_ptr & operator=(auto_ptr &__a)
auto_ptr assignment operator.
element_type * release()
Bypassing the smart pointer.
typename conditional< _Cond, _Iftrue, _Iffalse >::type conditional_t
Alias template for conditional.
void terminate() noexcept
ISO C++ entities toplevel namespace is std.
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.