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