brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.1 KiB · 1f19d50 Raw
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