Warning, /include/c++/v1/semaphore is written in an unsupported language. File is not indexed.
0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009
0010 #ifndef _LIBCPP_SEMAPHORE
0011 #define _LIBCPP_SEMAPHORE
0012
0013 /*
0014 semaphore synopsis
0015
0016 namespace std {
0017
0018 template<ptrdiff_t least_max_value = implementation-defined>
0019 class counting_semaphore // since C++20
0020 {
0021 public:
0022 static constexpr ptrdiff_t max() noexcept;
0023
0024 constexpr explicit counting_semaphore(ptrdiff_t desired);
0025 ~counting_semaphore();
0026
0027 counting_semaphore(const counting_semaphore&) = delete;
0028 counting_semaphore& operator=(const counting_semaphore&) = delete;
0029
0030 void release(ptrdiff_t update = 1);
0031 void acquire();
0032 bool try_acquire() noexcept;
0033 template<class Rep, class Period>
0034 bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);
0035 template<class Clock, class Duration>
0036 bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);
0037
0038 private:
0039 ptrdiff_t counter; // exposition only
0040 };
0041
0042 using binary_semaphore = counting_semaphore<1>; // since C++20
0043
0044 }
0045
0046 */
0047
0048 #if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
0049 # include <__cxx03/semaphore>
0050 #else
0051 # include <__config>
0052
0053 # if _LIBCPP_HAS_THREADS
0054
0055 # include <__assert>
0056 # include <__atomic/atomic.h>
0057 # include <__atomic/atomic_sync.h>
0058 # include <__atomic/memory_order.h>
0059 # include <__chrono/time_point.h>
0060 # include <__cstddef/ptrdiff_t.h>
0061 # include <__thread/poll_with_backoff.h>
0062 # include <__thread/support.h>
0063 # include <__thread/timed_backoff_policy.h>
0064 # include <limits>
0065 # include <version>
0066
0067 # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0068 # pragma GCC system_header
0069 # endif
0070
0071 _LIBCPP_PUSH_MACROS
0072 # include <__undef_macros>
0073
0074 # if _LIBCPP_STD_VER >= 20
0075
0076 _LIBCPP_BEGIN_NAMESPACE_STD
0077
0078 /*
0079
0080 __atomic_semaphore_base is the general-case implementation.
0081 It is a typical Dijkstra semaphore algorithm over atomics, wait and notify
0082 functions. It avoids contention against users' own use of those facilities.
0083
0084 */
0085
0086 # define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max())
0087
0088 class __atomic_semaphore_base {
0089 atomic<ptrdiff_t> __a_;
0090
0091 public:
0092 _LIBCPP_HIDE_FROM_ABI constexpr explicit __atomic_semaphore_base(ptrdiff_t __count) : __a_(__count) {}
0093 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) {
0094 auto __old = __a_.fetch_add(__update, memory_order_release);
0095 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
0096 __update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");
0097 if (__old == 0) {
0098 __a_.notify_all();
0099 }
0100 }
0101 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() {
0102 std::__atomic_wait_unless(__a_, memory_order_relaxed, [this](ptrdiff_t& __old) {
0103 return __try_acquire_impl(__old);
0104 });
0105 }
0106 template <class _Rep, class _Period>
0107 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
0108 try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
0109 if (__rel_time == chrono::duration<_Rep, _Period>::zero())
0110 return try_acquire();
0111 auto const __poll_fn = [this]() { return try_acquire(); };
0112 return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time);
0113 }
0114 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() {
0115 auto __old = __a_.load(memory_order_relaxed);
0116 return __try_acquire_impl(__old);
0117 }
0118
0119 private:
0120 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __try_acquire_impl(ptrdiff_t& __old) {
0121 while (true) {
0122 if (__old == 0)
0123 return false;
0124 if (__a_.compare_exchange_weak(__old, __old - 1, memory_order_acquire, memory_order_relaxed))
0125 return true;
0126 }
0127 }
0128 };
0129
0130 template <ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX>
0131 class counting_semaphore {
0132 __atomic_semaphore_base __semaphore_;
0133
0134 public:
0135 static_assert(__least_max_value >= 0, "The least maximum value must be a positive number");
0136
0137 static constexpr ptrdiff_t max() noexcept { return __least_max_value; }
0138
0139 _LIBCPP_HIDE_FROM_ABI constexpr explicit counting_semaphore(ptrdiff_t __count) : __semaphore_(__count) {
0140 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
0141 __count >= 0,
0142 "counting_semaphore::counting_semaphore(ptrdiff_t): counting_semaphore cannot be "
0143 "initialized with a negative value");
0144 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
0145 __count <= max(),
0146 "counting_semaphore::counting_semaphore(ptrdiff_t): counting_semaphore cannot be "
0147 "initialized with a value greater than max()");
0148 }
0149 ~counting_semaphore() = default;
0150
0151 counting_semaphore(const counting_semaphore&) = delete;
0152 counting_semaphore& operator=(const counting_semaphore&) = delete;
0153
0154 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) {
0155 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "counting_semaphore:release called with a negative value");
0156 __semaphore_.release(__update);
0157 }
0158 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() { __semaphore_.acquire(); }
0159 template <class _Rep, class _Period>
0160 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
0161 try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {
0162 return __semaphore_.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time));
0163 }
0164 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); }
0165 template <class _Clock, class _Duration>
0166 _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool
0167 try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) {
0168 auto const __current = _Clock::now();
0169 if (__current >= __abs_time)
0170 return try_acquire();
0171 else
0172 return try_acquire_for(__abs_time - __current);
0173 }
0174 };
0175
0176 using binary_semaphore = counting_semaphore<1>;
0177
0178 _LIBCPP_END_NAMESPACE_STD
0179
0180 # endif // _LIBCPP_STD_VER >= 20
0181
0182 _LIBCPP_POP_MACROS
0183
0184 # endif // _LIBCPP_HAS_THREADS
0185
0186 # if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
0187 # include <atomic>
0188 # include <cstddef>
0189 # endif
0190 #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
0191
0192 #endif // _LIBCPP_SEMAPHORE