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 4381ad6265SDimitry Andric#include <__assert> // all public C++ headers provide the assertion handler 44*06c3fb27SDimitry Andric#include <__atomic/atomic_base.h> 45*06c3fb27SDimitry Andric#include <__atomic/atomic_sync.h> 46*06c3fb27SDimitry Andric#include <__atomic/memory_order.h> 47e8d8bef9SDimitry Andric#include <__availability> 48fe6060f1SDimitry Andric#include <__config> 49*06c3fb27SDimitry Andric#include <cstddef> 5081ad6265SDimitry Andric#include <limits> 5104eeddc0SDimitry Andric#include <version> 525ffd83dbSDimitry Andric 535ffd83dbSDimitry Andric#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 545ffd83dbSDimitry Andric# pragma GCC system_header 555ffd83dbSDimitry Andric#endif 565ffd83dbSDimitry Andric 575ffd83dbSDimitry Andric#ifdef _LIBCPP_HAS_NO_THREADS 5881ad6265SDimitry Andric# error "<latch> is not supported since libc++ has been configured without support for threads." 595ffd83dbSDimitry Andric#endif 605ffd83dbSDimitry Andric 61e8d8bef9SDimitry Andric_LIBCPP_PUSH_MACROS 62e8d8bef9SDimitry Andric#include <__undef_macros> 63e8d8bef9SDimitry Andric 645ffd83dbSDimitry Andric#if _LIBCPP_STD_VER >= 14 655ffd83dbSDimitry Andric 665ffd83dbSDimitry Andric_LIBCPP_BEGIN_NAMESPACE_STD 675ffd83dbSDimitry Andric 685ffd83dbSDimitry Andricclass latch 695ffd83dbSDimitry Andric{ 70bdd1243dSDimitry Andric __atomic_base<ptrdiff_t> __a_; 715ffd83dbSDimitry Andric 725ffd83dbSDimitry Andricpublic: 73*06c3fb27SDimitry Andric static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { 745ffd83dbSDimitry Andric return numeric_limits<ptrdiff_t>::max(); 755ffd83dbSDimitry Andric } 765ffd83dbSDimitry Andric 775ffd83dbSDimitry Andric inline _LIBCPP_INLINE_VISIBILITY 78*06c3fb27SDimitry Andric constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) 79*06c3fb27SDimitry Andric { 80*06c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__expected >= 0, 81*06c3fb27SDimitry Andric "latch::latch(ptrdiff_t): latch cannot be " 82*06c3fb27SDimitry Andric "initialized with a negative value"); 83*06c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(__expected <= max(), 84*06c3fb27SDimitry Andric "latch::latch(ptrdiff_t): latch cannot be " 85*06c3fb27SDimitry Andric "initialized with a value greater than max()"); 86*06c3fb27SDimitry Andric } 875ffd83dbSDimitry Andric 88*06c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI ~latch() = default; 895ffd83dbSDimitry Andric latch(const latch&) = delete; 905ffd83dbSDimitry Andric latch& operator=(const latch&) = delete; 915ffd83dbSDimitry Andric 925ffd83dbSDimitry Andric inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 935ffd83dbSDimitry Andric void count_down(ptrdiff_t __update = 1) 945ffd83dbSDimitry Andric { 95*06c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED( 96*06c3fb27SDimitry Andric __update >= 0, "latch::count_down called with a negative value"); 97bdd1243dSDimitry Andric auto const __old = __a_.fetch_sub(__update, memory_order_release); 98*06c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED( 99*06c3fb27SDimitry Andric __update <= __old, "latch::count_down called with a value greater " 100*06c3fb27SDimitry Andric "than the internal counter"); 1015ffd83dbSDimitry Andric if (__old == __update) 102bdd1243dSDimitry Andric __a_.notify_all(); 1035ffd83dbSDimitry Andric } 1045ffd83dbSDimitry Andric inline _LIBCPP_INLINE_VISIBILITY 1055ffd83dbSDimitry Andric bool try_wait() const noexcept 1065ffd83dbSDimitry Andric { 107bdd1243dSDimitry Andric return 0 == __a_.load(memory_order_acquire); 1085ffd83dbSDimitry Andric } 1095ffd83dbSDimitry Andric inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 1105ffd83dbSDimitry Andric void wait() const 1115ffd83dbSDimitry Andric { 112*06c3fb27SDimitry Andric __cxx_atomic_wait(&__a_.__a_, [this]() -> bool { 1135ffd83dbSDimitry Andric return try_wait(); 11481ad6265SDimitry Andric }); 1155ffd83dbSDimitry Andric } 1165ffd83dbSDimitry Andric inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 1175ffd83dbSDimitry Andric void arrive_and_wait(ptrdiff_t __update = 1) 1185ffd83dbSDimitry Andric { 119*06c3fb27SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED( 120*06c3fb27SDimitry Andric __update >= 0, "latch::arrive_and_wait called with a negative value"); 121*06c3fb27SDimitry Andric // other preconditions on __update are checked in count_down() 122*06c3fb27SDimitry Andric 1235ffd83dbSDimitry Andric count_down(__update); 1245ffd83dbSDimitry Andric wait(); 1255ffd83dbSDimitry Andric } 1265ffd83dbSDimitry Andric}; 1275ffd83dbSDimitry Andric 1285ffd83dbSDimitry Andric_LIBCPP_END_NAMESPACE_STD 1295ffd83dbSDimitry Andric 1305ffd83dbSDimitry Andric#endif // _LIBCPP_STD_VER >= 14 1315ffd83dbSDimitry Andric 132e8d8bef9SDimitry Andric_LIBCPP_POP_MACROS 133e8d8bef9SDimitry Andric 134*06c3fb27SDimitry Andric#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 135*06c3fb27SDimitry Andric# include <atomic> 136*06c3fb27SDimitry Andric#endif 137*06c3fb27SDimitry Andric 1385ffd83dbSDimitry Andric#endif //_LIBCPP_LATCH 139