latch 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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-exception
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #ifndef _LIBCPP_LATCH
  10. #define _LIBCPP_LATCH
  11. /*
  12. latch synopsis
  13. namespace std
  14. {
  15. class latch
  16. {
  17. public:
  18. static constexpr ptrdiff_t max() noexcept;
  19. constexpr explicit latch(ptrdiff_t __expected);
  20. ~latch();
  21. latch(const latch&) = delete;
  22. latch& operator=(const latch&) = delete;
  23. void count_down(ptrdiff_t __update = 1);
  24. bool try_wait() const noexcept;
  25. void wait() const;
  26. void arrive_and_wait(ptrdiff_t __update = 1);
  27. private:
  28. ptrdiff_t __counter; // exposition only
  29. };
  30. }
  31. */
  32. #include <__config>
  33. #ifdef _LIBCPP_HAS_NO_THREADS
  34. # error "<latch> is not supported since libc++ has been configured without support for threads."
  35. #endif
  36. #include <__assert>
  37. #include <__atomic/atomic_base.h>
  38. #include <__atomic/atomic_sync.h>
  39. #include <__atomic/memory_order.h>
  40. #include <__availability>
  41. #include <cstddef>
  42. #include <limits>
  43. #include <version>
  44. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  45. # pragma GCC system_header
  46. #endif
  47. _LIBCPP_PUSH_MACROS
  48. #include <__undef_macros>
  49. #if _LIBCPP_STD_VER >= 14
  50. _LIBCPP_BEGIN_NAMESPACE_STD
  51. class latch {
  52. __atomic_base<ptrdiff_t> __a_;
  53. public:
  54. static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
  55. inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {
  56. _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
  57. __expected >= 0,
  58. "latch::latch(ptrdiff_t): latch cannot be "
  59. "initialized with a negative value");
  60. _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
  61. __expected <= max(),
  62. "latch::latch(ptrdiff_t): latch cannot be "
  63. "initialized with a value greater than max()");
  64. }
  65. _LIBCPP_HIDE_FROM_ABI ~latch() = default;
  66. latch(const latch&) = delete;
  67. latch& operator=(const latch&) = delete;
  68. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) {
  69. _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value");
  70. auto const __old = __a_.fetch_sub(__update, memory_order_release);
  71. _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
  72. __update <= __old,
  73. "latch::count_down called with a value greater "
  74. "than the internal counter");
  75. if (__old == __update)
  76. __a_.notify_all();
  77. }
  78. inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
  79. auto __value = __a_.load(memory_order_acquire);
  80. return try_wait_impl(__value);
  81. }
  82. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
  83. std::__atomic_wait_unless(
  84. __a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
  85. }
  86. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
  87. _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
  88. // other preconditions on __update are checked in count_down()
  89. count_down(__update);
  90. wait();
  91. }
  92. private:
  93. _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
  94. };
  95. _LIBCPP_END_NAMESPACE_STD
  96. #endif // _LIBCPP_STD_VER >= 14
  97. _LIBCPP_POP_MACROS
  98. #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
  99. # include <atomic>
  100. #endif
  101. #endif //_LIBCPP_LATCH