190 lines · plain
1// -*- C++ -*-2//===----------------------------------------------------------------------===//3//4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5// See https://llvm.org/LICENSE.txt for license information.6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP_SEMAPHORE11#define _LIBCPP_SEMAPHORE12 13/*14 semaphore synopsis15 16namespace std {17 18template<ptrdiff_t least_max_value = implementation-defined>19class counting_semaphore // since C++2020{21public:22static constexpr ptrdiff_t max() noexcept;23 24constexpr explicit counting_semaphore(ptrdiff_t desired);25~counting_semaphore();26 27counting_semaphore(const counting_semaphore&) = delete;28counting_semaphore& operator=(const counting_semaphore&) = delete;29 30void release(ptrdiff_t update = 1);31void acquire();32bool try_acquire() noexcept;33template<class Rep, class Period>34 bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time);35template<class Clock, class Duration>36 bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time);37 38private:39ptrdiff_t counter; // exposition only40};41 42using binary_semaphore = counting_semaphore<1>; // since C++2043 44}45 46*/47 48#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)49# include <__cxx03/__config>50#else51# include <__config>52 53# if _LIBCPP_HAS_THREADS54 55# include <__assert>56# include <__atomic/atomic.h>57# include <__atomic/atomic_sync.h>58# include <__atomic/memory_order.h>59# include <__chrono/time_point.h>60# include <__cstddef/ptrdiff_t.h>61# include <__thread/poll_with_backoff.h>62# include <__thread/support.h>63# include <__thread/timed_backoff_policy.h>64# include <limits>65# include <version>66 67# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)68# pragma GCC system_header69# endif70 71_LIBCPP_PUSH_MACROS72# include <__undef_macros>73 74# if _LIBCPP_STD_VER >= 2075 76_LIBCPP_BEGIN_NAMESPACE_STD77 78/*79 80__atomic_semaphore_base is the general-case implementation.81It is a typical Dijkstra semaphore algorithm over atomics, wait and notify82functions. It avoids contention against users' own use of those facilities.83 84*/85 86# define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max())87 88class __atomic_semaphore_base {89 atomic<ptrdiff_t> __a_;90 91public:92 _LIBCPP_HIDE_FROM_ABI constexpr explicit __atomic_semaphore_base(ptrdiff_t __count) : __a_(__count) {}93 _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) {94 auto __old = __a_.fetch_add(__update, memory_order_release);95 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(96 __update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value");97 if (__old == 0) {98 __a_.notify_all();99 }100 }101 _LIBCPP_HIDE_FROM_ABI void acquire() {102 std::__atomic_wait_unless(__a_, memory_order_relaxed, [this](ptrdiff_t& __old) {103 return __try_acquire_impl(__old);104 });105 }106 template <class _Rep, class _Period>107 _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {108 if (__rel_time == chrono::duration<_Rep, _Period>::zero())109 return try_acquire();110 auto const __poll_fn = [this]() { return try_acquire(); };111 return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time);112 }113 _LIBCPP_HIDE_FROM_ABI bool try_acquire() {114 auto __old = __a_.load(memory_order_relaxed);115 return __try_acquire_impl(__old);116 }117 118private:119 _LIBCPP_HIDE_FROM_ABI bool __try_acquire_impl(ptrdiff_t& __old) {120 while (true) {121 if (__old == 0)122 return false;123 if (__a_.compare_exchange_weak(__old, __old - 1, memory_order_acquire, memory_order_relaxed))124 return true;125 }126 }127};128 129template <ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX>130class counting_semaphore {131 __atomic_semaphore_base __semaphore_;132 133public:134 static_assert(__least_max_value >= 0, "The least maximum value must be a positive number");135 136 [[nodiscard]] static constexpr ptrdiff_t max() noexcept { return __least_max_value; }137 138 _LIBCPP_HIDE_FROM_ABI constexpr explicit counting_semaphore(ptrdiff_t __count) : __semaphore_(__count) {139 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(140 __count >= 0,141 "counting_semaphore::counting_semaphore(ptrdiff_t): counting_semaphore cannot be "142 "initialized with a negative value");143 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(144 __count <= max(),145 "counting_semaphore::counting_semaphore(ptrdiff_t): counting_semaphore cannot be "146 "initialized with a value greater than max()");147 }148 ~counting_semaphore() = default;149 150 counting_semaphore(const counting_semaphore&) = delete;151 counting_semaphore& operator=(const counting_semaphore&) = delete;152 153 _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) {154 _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "counting_semaphore:release called with a negative value");155 __semaphore_.release(__update);156 }157 _LIBCPP_HIDE_FROM_ABI void acquire() { __semaphore_.acquire(); }158 template <class _Rep, class _Period>159 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) {160 return __semaphore_.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time));161 }162 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); }163 template <class _Clock, class _Duration>164 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) {165 auto const __current = _Clock::now();166 if (__current >= __abs_time)167 return try_acquire();168 else169 return try_acquire_for(__abs_time - __current);170 }171};172 173using binary_semaphore = counting_semaphore<1>;174 175_LIBCPP_END_NAMESPACE_STD176 177# endif // _LIBCPP_STD_VER >= 20178 179_LIBCPP_POP_MACROS180 181# endif // _LIBCPP_HAS_THREADS182 183# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20184# include <atomic>185# include <cstddef>186# endif187#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)188 189#endif // _LIBCPP_SEMAPHORE190