xref: /freebsd/contrib/llvm-project/libcxx/include/latch (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric// -*- C++ -*-
2349cc55cSDimitry Andric//===----------------------------------------------------------------------===//
35ffd83dbSDimitry Andric//
45ffd83dbSDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
55ffd83dbSDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
65ffd83dbSDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
75ffd83dbSDimitry Andric//
85ffd83dbSDimitry Andric//===----------------------------------------------------------------------===//
95ffd83dbSDimitry Andric
105ffd83dbSDimitry Andric#ifndef _LIBCPP_LATCH
115ffd83dbSDimitry Andric#define _LIBCPP_LATCH
125ffd83dbSDimitry Andric
135ffd83dbSDimitry Andric/*
145ffd83dbSDimitry Andric    latch synopsis
155ffd83dbSDimitry Andric
165ffd83dbSDimitry Andricnamespace std
175ffd83dbSDimitry Andric{
185ffd83dbSDimitry Andric
195ffd83dbSDimitry Andric  class latch
205ffd83dbSDimitry Andric  {
215ffd83dbSDimitry Andric  public:
22e8d8bef9SDimitry Andric    static constexpr ptrdiff_t max() noexcept;
23e8d8bef9SDimitry Andric
245ffd83dbSDimitry Andric    constexpr explicit latch(ptrdiff_t __expected);
255ffd83dbSDimitry Andric    ~latch();
265ffd83dbSDimitry Andric
275ffd83dbSDimitry Andric    latch(const latch&) = delete;
285ffd83dbSDimitry Andric    latch& operator=(const latch&) = delete;
295ffd83dbSDimitry Andric
305ffd83dbSDimitry Andric    void count_down(ptrdiff_t __update = 1);
315ffd83dbSDimitry Andric    bool try_wait() const noexcept;
325ffd83dbSDimitry Andric    void wait() const;
335ffd83dbSDimitry Andric    void arrive_and_wait(ptrdiff_t __update = 1);
345ffd83dbSDimitry Andric
355ffd83dbSDimitry Andric  private:
365ffd83dbSDimitry Andric    ptrdiff_t __counter; // exposition only
375ffd83dbSDimitry Andric  };
385ffd83dbSDimitry Andric
395ffd83dbSDimitry Andric}
405ffd83dbSDimitry Andric
415ffd83dbSDimitry Andric*/
425ffd83dbSDimitry Andric
437a6dacacSDimitry Andric#include <__config>
447a6dacacSDimitry Andric
45*0fca6ea1SDimitry Andric#if !defined(_LIBCPP_HAS_NO_THREADS)
467a6dacacSDimitry Andric
47*0fca6ea1SDimitry Andric#  include <__assert>
4806c3fb27SDimitry Andric#  include <__atomic/atomic_base.h>
4906c3fb27SDimitry Andric#  include <__atomic/atomic_sync.h>
5006c3fb27SDimitry Andric#  include <__atomic/memory_order.h>
5106c3fb27SDimitry Andric#  include <cstddef>
5281ad6265SDimitry Andric#  include <limits>
5304eeddc0SDimitry Andric#  include <version>
545ffd83dbSDimitry Andric
555ffd83dbSDimitry Andric#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
565ffd83dbSDimitry Andric#    pragma GCC system_header
575ffd83dbSDimitry Andric#  endif
585ffd83dbSDimitry Andric
59e8d8bef9SDimitry Andric_LIBCPP_PUSH_MACROS
60e8d8bef9SDimitry Andric#  include <__undef_macros>
61e8d8bef9SDimitry Andric
625ffd83dbSDimitry Andric#  if _LIBCPP_STD_VER >= 14
635ffd83dbSDimitry Andric
645ffd83dbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD
655ffd83dbSDimitry Andric
66*0fca6ea1SDimitry Andricclass _LIBCPP_DEPRECATED_ATOMIC_SYNC latch {
67bdd1243dSDimitry Andric  __atomic_base<ptrdiff_t> __a_;
685ffd83dbSDimitry Andric
695ffd83dbSDimitry Andricpublic:
70cb14a3feSDimitry Andric  static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); }
715ffd83dbSDimitry Andric
72cb14a3feSDimitry Andric  inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) {
737a6dacacSDimitry Andric    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
74cb14a3feSDimitry Andric        __expected >= 0,
7506c3fb27SDimitry Andric        "latch::latch(ptrdiff_t): latch cannot be "
7606c3fb27SDimitry Andric        "initialized with a negative value");
777a6dacacSDimitry Andric    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
78cb14a3feSDimitry Andric        __expected <= max(),
7906c3fb27SDimitry Andric        "latch::latch(ptrdiff_t): latch cannot be "
8006c3fb27SDimitry Andric        "initialized with a value greater than max()");
8106c3fb27SDimitry Andric  }
825ffd83dbSDimitry Andric
8306c3fb27SDimitry Andric  _LIBCPP_HIDE_FROM_ABI ~latch() = default;
845ffd83dbSDimitry Andric  latch(const latch&)            = delete;
855ffd83dbSDimitry Andric  latch& operator=(const latch&) = delete;
865ffd83dbSDimitry Andric
87cb14a3feSDimitry Andric  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) {
887a6dacacSDimitry Andric    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value");
89bdd1243dSDimitry Andric    auto const __old = __a_.fetch_sub(__update, memory_order_release);
907a6dacacSDimitry Andric    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
91cb14a3feSDimitry Andric        __update <= __old,
92cb14a3feSDimitry Andric        "latch::count_down called with a value greater "
9306c3fb27SDimitry Andric        "than the internal counter");
945ffd83dbSDimitry Andric    if (__old == __update)
95bdd1243dSDimitry Andric      __a_.notify_all();
965ffd83dbSDimitry Andric  }
97*0fca6ea1SDimitry Andric  inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept {
98*0fca6ea1SDimitry Andric    auto __value = __a_.load(memory_order_acquire);
99*0fca6ea1SDimitry Andric    return try_wait_impl(__value);
100*0fca6ea1SDimitry Andric  }
101cb14a3feSDimitry Andric  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const {
102*0fca6ea1SDimitry Andric    std::__atomic_wait_unless(
103*0fca6ea1SDimitry Andric        __a_, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }, memory_order_acquire);
1045ffd83dbSDimitry Andric  }
105cb14a3feSDimitry Andric  inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) {
1067a6dacacSDimitry Andric    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value");
10706c3fb27SDimitry Andric    // other preconditions on __update are checked in count_down()
10806c3fb27SDimitry Andric
1095ffd83dbSDimitry Andric    count_down(__update);
1105ffd83dbSDimitry Andric    wait();
1115ffd83dbSDimitry Andric  }
112*0fca6ea1SDimitry Andric
113*0fca6ea1SDimitry Andricprivate:
114*0fca6ea1SDimitry Andric  _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; }
1155ffd83dbSDimitry Andric};
1165ffd83dbSDimitry Andric
1175ffd83dbSDimitry Andric_LIBCPP_END_NAMESPACE_STD
1185ffd83dbSDimitry Andric
1195ffd83dbSDimitry Andric#  endif // _LIBCPP_STD_VER >= 14
1205ffd83dbSDimitry Andric
121e8d8bef9SDimitry Andric_LIBCPP_POP_MACROS
122e8d8bef9SDimitry Andric
123*0fca6ea1SDimitry Andric#endif // !defined(_LIBCPP_HAS_NO_THREADS)
124*0fca6ea1SDimitry Andric
12506c3fb27SDimitry Andric#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
12606c3fb27SDimitry Andric#  include <atomic>
12706c3fb27SDimitry Andric#endif
12806c3fb27SDimitry Andric
1295ffd83dbSDimitry Andric#endif //_LIBCPP_LATCH
130