154fa9ecdSOlivier Giroux// -*- C++ -*- 2eb8650a7SLouis Dionne//===----------------------------------------------------------------------===// 354fa9ecdSOlivier Giroux// 454fa9ecdSOlivier Giroux// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 554fa9ecdSOlivier Giroux// See https://llvm.org/LICENSE.txt for license information. 654fa9ecdSOlivier Giroux// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 754fa9ecdSOlivier Giroux// 854fa9ecdSOlivier Giroux//===----------------------------------------------------------------------===// 954fa9ecdSOlivier Giroux 1054fa9ecdSOlivier Giroux#ifndef _LIBCPP_LATCH 1154fa9ecdSOlivier Giroux#define _LIBCPP_LATCH 1254fa9ecdSOlivier Giroux 1354fa9ecdSOlivier Giroux/* 1454fa9ecdSOlivier Giroux latch synopsis 1554fa9ecdSOlivier Giroux 1654fa9ecdSOlivier Girouxnamespace std 1754fa9ecdSOlivier Giroux{ 1854fa9ecdSOlivier Giroux 19bf1666fbSLouis Dionne class latch // since C++20 2054fa9ecdSOlivier Giroux { 2154fa9ecdSOlivier Giroux public: 22e2279c23SMarek Kurdej static constexpr ptrdiff_t max() noexcept; 23e2279c23SMarek Kurdej 2454fa9ecdSOlivier Giroux constexpr explicit latch(ptrdiff_t __expected); 2554fa9ecdSOlivier Giroux ~latch(); 2654fa9ecdSOlivier Giroux 2754fa9ecdSOlivier Giroux latch(const latch&) = delete; 2854fa9ecdSOlivier Giroux latch& operator=(const latch&) = delete; 2954fa9ecdSOlivier Giroux 3054fa9ecdSOlivier Giroux void count_down(ptrdiff_t __update = 1); 3154fa9ecdSOlivier Giroux bool try_wait() const noexcept; 3254fa9ecdSOlivier Giroux void wait() const; 3354fa9ecdSOlivier Giroux void arrive_and_wait(ptrdiff_t __update = 1); 3454fa9ecdSOlivier Giroux 3554fa9ecdSOlivier Giroux private: 3654fa9ecdSOlivier Giroux ptrdiff_t __counter; // exposition only 3754fa9ecdSOlivier Giroux }; 3854fa9ecdSOlivier Giroux 3954fa9ecdSOlivier Giroux} 4054fa9ecdSOlivier Giroux 4154fa9ecdSOlivier Giroux*/ 4254fa9ecdSOlivier Giroux 43*b9a2658aSNikolas Klauser#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) 44*b9a2658aSNikolas Klauser# include <__cxx03/latch> 45*b9a2658aSNikolas Klauser#else 4634933d18SMark de Wever# include <__config> 4734933d18SMark de Wever 48c6f3b7bcSNikolas Klauser# if _LIBCPP_HAS_THREADS 4934933d18SMark de Wever 5037dca605SLouis Dionne# include <__assert> 513a634076SLouis Dionne# include <__atomic/atomic.h> 5270617a1aSNikolas Klauser# include <__atomic/atomic_sync.h> 5370617a1aSNikolas Klauser# include <__atomic/memory_order.h> 54e99c4906SNikolas Klauser# include <__cstddef/ptrdiff_t.h> 55643df8faSLouis Dionne# include <limits> 56bd6e6846SMark de Wever# include <version> 5754fa9ecdSOlivier Giroux 5854fa9ecdSOlivier Giroux# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 5954fa9ecdSOlivier Giroux# pragma GCC system_header 6054fa9ecdSOlivier Giroux# endif 6154fa9ecdSOlivier Giroux 62d4303307SArthur O'Dwyer_LIBCPP_PUSH_MACROS 63d4303307SArthur O'Dwyer# include <__undef_macros> 64d4303307SArthur O'Dwyer 65bf1666fbSLouis Dionne# if _LIBCPP_STD_VER >= 20 6654fa9ecdSOlivier Giroux 6754fa9ecdSOlivier Giroux_LIBCPP_BEGIN_NAMESPACE_STD 6854fa9ecdSOlivier Giroux 69bf1666fbSLouis Dionneclass latch { 703a634076SLouis Dionne atomic<ptrdiff_t> __a_; 7154fa9ecdSOlivier Giroux 7254fa9ecdSOlivier Girouxpublic: 739783f28cSLouis Dionne static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); } 7454fa9ecdSOlivier Giroux 759783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { 76dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 779783f28cSLouis Dionne __expected >= 0, 785e807c38SEdoardo Sanguineti "latch::latch(ptrdiff_t): latch cannot be " 795e807c38SEdoardo Sanguineti "initialized with a negative value"); 80dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 819783f28cSLouis Dionne __expected <= max(), 825e807c38SEdoardo Sanguineti "latch::latch(ptrdiff_t): latch cannot be " 835e807c38SEdoardo Sanguineti "initialized with a value greater than max()"); 845e807c38SEdoardo Sanguineti } 8554fa9ecdSOlivier Giroux 8683ce1397SNikolas Klauser _LIBCPP_HIDE_FROM_ABI ~latch() = default; 8754fa9ecdSOlivier Giroux latch(const latch&) = delete; 8854fa9ecdSOlivier Giroux latch& operator=(const latch&) = delete; 8954fa9ecdSOlivier Giroux 909783f28cSLouis Dionne inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) { 91dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value"); 9284fc2c3cSNikolas Klauser auto const __old = __a_.fetch_sub(__update, memory_order_release); 93dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( 949783f28cSLouis Dionne __update <= __old, 959783f28cSLouis Dionne "latch::count_down called with a value greater " 965e807c38SEdoardo Sanguineti "than the internal counter"); 9754fa9ecdSOlivier Giroux if (__old == __update) 9884fc2c3cSNikolas Klauser __a_.notify_all(); 9954fa9ecdSOlivier Giroux } 10095ebf2beSJan Kokemüller inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { 10195ebf2beSJan Kokemüller auto __value = __a_.load(memory_order_acquire); 10295ebf2beSJan Kokemüller return try_wait_impl(__value); 10395ebf2beSJan Kokemüller } 1049783f28cSLouis Dionne inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const { 105d681e103SLouis Dionne std::__atomic_wait_unless(__a_, memory_order_acquire, [this](ptrdiff_t& __value) -> bool { 106d681e103SLouis Dionne return try_wait_impl(__value); 107d681e103SLouis Dionne }); 10854fa9ecdSOlivier Giroux } 1099783f28cSLouis Dionne inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) { 110dc577520SKonstantin Varlamov _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value"); 1115e807c38SEdoardo Sanguineti // other preconditions on __update are checked in count_down() 1125e807c38SEdoardo Sanguineti 11354fa9ecdSOlivier Giroux count_down(__update); 11454fa9ecdSOlivier Giroux wait(); 11554fa9ecdSOlivier Giroux } 11695ebf2beSJan Kokemüller 11795ebf2beSJan Kokemüllerprivate: 1181f613bceSHui _LIBCPP_HIDE_FROM_ABI bool try_wait_impl(ptrdiff_t& __value) const noexcept { return __value == 0; } 11954fa9ecdSOlivier Giroux}; 12054fa9ecdSOlivier Giroux 12154fa9ecdSOlivier Giroux_LIBCPP_END_NAMESPACE_STD 12254fa9ecdSOlivier Giroux 123bf1666fbSLouis Dionne# endif // _LIBCPP_STD_VER >= 20 124ab41129bSLouis Dionne 125d4303307SArthur O'Dwyer_LIBCPP_POP_MACROS 126d4303307SArthur O'Dwyer 127c6f3b7bcSNikolas Klauser# endif // _LIBCPP_HAS_THREADS 128ef51e617SLouis Dionne 12970617a1aSNikolas Klauser# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 13070617a1aSNikolas Klauser# include <atomic> 131e99c4906SNikolas Klauser# include <cstddef> 13270617a1aSNikolas Klauser# endif 133*b9a2658aSNikolas Klauser#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) 13470617a1aSNikolas Klauser 13554fa9ecdSOlivier Giroux#endif // _LIBCPP_LATCH 136