1037e7968Spatrick// -*- C++ -*- 2*4bdff4beSrobert//===----------------------------------------------------------------------===// 3037e7968Spatrick// 4037e7968Spatrick// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5037e7968Spatrick// See https://llvm.org/LICENSE.txt for license information. 6037e7968Spatrick// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7037e7968Spatrick// 8037e7968Spatrick//===----------------------------------------------------------------------===// 9037e7968Spatrick 10037e7968Spatrick#ifndef _LIBCPP_LATCH 11037e7968Spatrick#define _LIBCPP_LATCH 12037e7968Spatrick 13037e7968Spatrick/* 14037e7968Spatrick latch synopsis 15037e7968Spatrick 16037e7968Spatricknamespace std 17037e7968Spatrick{ 18037e7968Spatrick 19037e7968Spatrick class latch 20037e7968Spatrick { 21037e7968Spatrick public: 2276d0caaeSpatrick static constexpr ptrdiff_t max() noexcept; 2376d0caaeSpatrick 24037e7968Spatrick constexpr explicit latch(ptrdiff_t __expected); 25037e7968Spatrick ~latch(); 26037e7968Spatrick 27037e7968Spatrick latch(const latch&) = delete; 28037e7968Spatrick latch& operator=(const latch&) = delete; 29037e7968Spatrick 30037e7968Spatrick void count_down(ptrdiff_t __update = 1); 31037e7968Spatrick bool try_wait() const noexcept; 32037e7968Spatrick void wait() const; 33037e7968Spatrick void arrive_and_wait(ptrdiff_t __update = 1); 34037e7968Spatrick 35037e7968Spatrick private: 36037e7968Spatrick ptrdiff_t __counter; // exposition only 37037e7968Spatrick }; 38037e7968Spatrick 39037e7968Spatrick} 40037e7968Spatrick 41037e7968Spatrick*/ 42037e7968Spatrick 43*4bdff4beSrobert#include <__assert> // all public C++ headers provide the assertion handler 4476d0caaeSpatrick#include <__availability> 45037e7968Spatrick#include <__config> 46037e7968Spatrick#include <atomic> 47*4bdff4beSrobert#include <limits> 48*4bdff4beSrobert#include <version> 49037e7968Spatrick 50037e7968Spatrick#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 51037e7968Spatrick# pragma GCC system_header 52037e7968Spatrick#endif 53037e7968Spatrick 54037e7968Spatrick#ifdef _LIBCPP_HAS_NO_THREADS 55*4bdff4beSrobert# error "<latch> is not supported since libc++ has been configured without support for threads." 56037e7968Spatrick#endif 57037e7968Spatrick 5876d0caaeSpatrick_LIBCPP_PUSH_MACROS 5976d0caaeSpatrick#include <__undef_macros> 6076d0caaeSpatrick 61037e7968Spatrick#if _LIBCPP_STD_VER >= 14 62037e7968Spatrick 63037e7968Spatrick_LIBCPP_BEGIN_NAMESPACE_STD 64037e7968Spatrick 65037e7968Spatrickclass latch 66037e7968Spatrick{ 67*4bdff4beSrobert __atomic_base<ptrdiff_t> __a_; 68037e7968Spatrick 69037e7968Spatrickpublic: 70037e7968Spatrick static constexpr ptrdiff_t max() noexcept { 71037e7968Spatrick return numeric_limits<ptrdiff_t>::max(); 72037e7968Spatrick } 73037e7968Spatrick 74037e7968Spatrick inline _LIBCPP_INLINE_VISIBILITY 75*4bdff4beSrobert constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { } 76037e7968Spatrick 77037e7968Spatrick ~latch() = default; 78037e7968Spatrick latch(const latch&) = delete; 79037e7968Spatrick latch& operator=(const latch&) = delete; 80037e7968Spatrick 81037e7968Spatrick inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 82037e7968Spatrick void count_down(ptrdiff_t __update = 1) 83037e7968Spatrick { 84*4bdff4beSrobert auto const __old = __a_.fetch_sub(__update, memory_order_release); 85037e7968Spatrick if(__old == __update) 86*4bdff4beSrobert __a_.notify_all(); 87037e7968Spatrick } 88037e7968Spatrick inline _LIBCPP_INLINE_VISIBILITY 89037e7968Spatrick bool try_wait() const noexcept 90037e7968Spatrick { 91*4bdff4beSrobert return 0 == __a_.load(memory_order_acquire); 92037e7968Spatrick } 93037e7968Spatrick inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 94037e7968Spatrick void wait() const 95037e7968Spatrick { 96*4bdff4beSrobert __cxx_atomic_wait(&__a_.__a_, [&]() -> bool { 97037e7968Spatrick return try_wait(); 98*4bdff4beSrobert }); 99037e7968Spatrick } 100037e7968Spatrick inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 101037e7968Spatrick void arrive_and_wait(ptrdiff_t __update = 1) 102037e7968Spatrick { 103037e7968Spatrick count_down(__update); 104037e7968Spatrick wait(); 105037e7968Spatrick } 106037e7968Spatrick}; 107037e7968Spatrick 108037e7968Spatrick_LIBCPP_END_NAMESPACE_STD 109037e7968Spatrick 110037e7968Spatrick#endif // _LIBCPP_STD_VER >= 14 111037e7968Spatrick 11276d0caaeSpatrick_LIBCPP_POP_MACROS 11376d0caaeSpatrick 114037e7968Spatrick#endif //_LIBCPP_LATCH 115