latch 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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 <__assert> // all public C++ headers provide the assertion handler
  33. #include <__availability>
  34. #include <__config>
  35. #include <atomic>
  36. #include <version>
  37. #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
  38. # pragma GCC system_header
  39. #endif
  40. #ifdef _LIBCPP_HAS_NO_THREADS
  41. # error <latch> is not supported on this single threaded system
  42. #endif
  43. _LIBCPP_PUSH_MACROS
  44. #include <__undef_macros>
  45. #if _LIBCPP_STD_VER >= 14
  46. _LIBCPP_BEGIN_NAMESPACE_STD
  47. class latch
  48. {
  49. __atomic_base<ptrdiff_t> __a;
  50. public:
  51. static constexpr ptrdiff_t max() noexcept {
  52. return numeric_limits<ptrdiff_t>::max();
  53. }
  54. inline _LIBCPP_INLINE_VISIBILITY
  55. constexpr explicit latch(ptrdiff_t __expected) : __a(__expected) { }
  56. ~latch() = default;
  57. latch(const latch&) = delete;
  58. latch& operator=(const latch&) = delete;
  59. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
  60. void count_down(ptrdiff_t __update = 1)
  61. {
  62. auto const __old = __a.fetch_sub(__update, memory_order_release);
  63. if(__old == __update)
  64. __a.notify_all();
  65. }
  66. inline _LIBCPP_INLINE_VISIBILITY
  67. bool try_wait() const noexcept
  68. {
  69. return 0 == __a.load(memory_order_acquire);
  70. }
  71. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
  72. void wait() const
  73. {
  74. __cxx_atomic_wait(&__a.__a_, [&]() -> bool {
  75. return try_wait();
  76. });
  77. }
  78. inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY
  79. void arrive_and_wait(ptrdiff_t __update = 1)
  80. {
  81. count_down(__update);
  82. wait();
  83. }
  84. };
  85. _LIBCPP_END_NAMESPACE_STD
  86. #endif // _LIBCPP_STD_VER >= 14
  87. _LIBCPP_POP_MACROS
  88. #endif //_LIBCPP_LATCH