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_SEMAPHORE 11037e7968Spatrick#define _LIBCPP_SEMAPHORE 12037e7968Spatrick 13037e7968Spatrick/* 14037e7968Spatrick semaphore synopsis 15037e7968Spatrick 16037e7968Spatricknamespace std { 17037e7968Spatrick 18037e7968Spatricktemplate<ptrdiff_t least_max_value = implementation-defined> 19037e7968Spatrickclass counting_semaphore 20037e7968Spatrick{ 21037e7968Spatrickpublic: 22037e7968Spatrickstatic constexpr ptrdiff_t max() noexcept; 23037e7968Spatrick 24037e7968Spatrickconstexpr explicit counting_semaphore(ptrdiff_t desired); 25037e7968Spatrick~counting_semaphore(); 26037e7968Spatrick 27037e7968Spatrickcounting_semaphore(const counting_semaphore&) = delete; 28037e7968Spatrickcounting_semaphore& operator=(const counting_semaphore&) = delete; 29037e7968Spatrick 30037e7968Spatrickvoid release(ptrdiff_t update = 1); 31037e7968Spatrickvoid acquire(); 32037e7968Spatrickbool try_acquire() noexcept; 33037e7968Spatricktemplate<class Rep, class Period> 34037e7968Spatrick bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); 35037e7968Spatricktemplate<class Clock, class Duration> 36037e7968Spatrick bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time); 37037e7968Spatrick 38037e7968Spatrickprivate: 39037e7968Spatrickptrdiff_t counter; // exposition only 40037e7968Spatrick}; 41037e7968Spatrick 42037e7968Spatrickusing binary_semaphore = counting_semaphore<1>; 43037e7968Spatrick 44037e7968Spatrick} 45037e7968Spatrick 46037e7968Spatrick*/ 47037e7968Spatrick 48*4bdff4beSrobert#include <__assert> // all public C++ headers provide the assertion handler 4976d0caaeSpatrick#include <__availability> 50*4bdff4beSrobert#include <__chrono/time_point.h> 51037e7968Spatrick#include <__config> 52*4bdff4beSrobert#include <__thread/timed_backoff_policy.h> 53037e7968Spatrick#include <__threading_support> 54037e7968Spatrick#include <atomic> 55*4bdff4beSrobert#include <limits> 56*4bdff4beSrobert#include <version> 57037e7968Spatrick 58037e7968Spatrick#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 59037e7968Spatrick# pragma GCC system_header 60037e7968Spatrick#endif 61037e7968Spatrick 62037e7968Spatrick#ifdef _LIBCPP_HAS_NO_THREADS 63*4bdff4beSrobert# error "<semaphore> is not supported since libc++ has been configured without support for threads." 64037e7968Spatrick#endif 65037e7968Spatrick 6676d0caaeSpatrick_LIBCPP_PUSH_MACROS 6776d0caaeSpatrick#include <__undef_macros> 6876d0caaeSpatrick 69037e7968Spatrick#if _LIBCPP_STD_VER >= 14 70037e7968Spatrick 71037e7968Spatrick_LIBCPP_BEGIN_NAMESPACE_STD 72037e7968Spatrick 73037e7968Spatrick/* 74037e7968Spatrick 75*4bdff4beSrobert__atomic_semaphore_base is the general-case implementation. 7676d0caaeSpatrickIt is a typical Dijkstra semaphore algorithm over atomics, wait and notify 77037e7968Spatrickfunctions. It avoids contention against users' own use of those facilities. 78037e7968Spatrick 79037e7968Spatrick*/ 80037e7968Spatrick 81037e7968Spatrickclass __atomic_semaphore_base 82037e7968Spatrick{ 83*4bdff4beSrobert __atomic_base<ptrdiff_t> __a_; 84037e7968Spatrick 85037e7968Spatrickpublic: 86037e7968Spatrick _LIBCPP_INLINE_VISIBILITY 87*4bdff4beSrobert constexpr explicit __atomic_semaphore_base(ptrdiff_t __count) : __a_(__count) 88037e7968Spatrick { 89037e7968Spatrick } 90037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 91037e7968Spatrick void release(ptrdiff_t __update = 1) 92037e7968Spatrick { 93*4bdff4beSrobert if(0 < __a_.fetch_add(__update, memory_order_release)) 94037e7968Spatrick ; 95037e7968Spatrick else if(__update > 1) 96*4bdff4beSrobert __a_.notify_all(); 97037e7968Spatrick else 98*4bdff4beSrobert __a_.notify_one(); 99037e7968Spatrick } 100037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 101037e7968Spatrick void acquire() 102037e7968Spatrick { 10376d0caaeSpatrick auto const __test_fn = [this]() -> bool { 104*4bdff4beSrobert auto __old = __a_.load(memory_order_relaxed); 105*4bdff4beSrobert return (__old != 0) && __a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed); 106037e7968Spatrick }; 107*4bdff4beSrobert __cxx_atomic_wait(&__a_.__a_, __test_fn); 108037e7968Spatrick } 109037e7968Spatrick template <class Rep, class Period> 110037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 111037e7968Spatrick bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time) 112037e7968Spatrick { 113*4bdff4beSrobert if (__rel_time == chrono::duration<Rep, Period>::zero()) 114*4bdff4beSrobert return try_acquire(); 115*4bdff4beSrobert auto const __test_fn = [this]() { return try_acquire(); }; 116*4bdff4beSrobert return std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time); 117*4bdff4beSrobert } 118*4bdff4beSrobert _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 119*4bdff4beSrobert bool try_acquire() 120*4bdff4beSrobert { 121*4bdff4beSrobert auto __old = __a_.load(memory_order_acquire); 122*4bdff4beSrobert while (true) { 123037e7968Spatrick if (__old == 0) 124037e7968Spatrick return false; 125*4bdff4beSrobert if (__a_.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed)) 126037e7968Spatrick return true; 127037e7968Spatrick } 128037e7968Spatrick } 129037e7968Spatrick}; 130037e7968Spatrick 131037e7968Spatrick#define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max()) 132037e7968Spatrick 133037e7968Spatricktemplate<ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX> 134037e7968Spatrickclass counting_semaphore 135037e7968Spatrick{ 136*4bdff4beSrobert __atomic_semaphore_base __semaphore_; 137037e7968Spatrick 138037e7968Spatrickpublic: 139037e7968Spatrick static constexpr ptrdiff_t max() noexcept { 140037e7968Spatrick return __least_max_value; 141037e7968Spatrick } 142037e7968Spatrick 143037e7968Spatrick _LIBCPP_INLINE_VISIBILITY 144*4bdff4beSrobert constexpr explicit counting_semaphore(ptrdiff_t __count) : __semaphore_(__count) { } 145037e7968Spatrick ~counting_semaphore() = default; 146037e7968Spatrick 147037e7968Spatrick counting_semaphore(const counting_semaphore&) = delete; 148037e7968Spatrick counting_semaphore& operator=(const counting_semaphore&) = delete; 149037e7968Spatrick 150037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 151037e7968Spatrick void release(ptrdiff_t __update = 1) 152037e7968Spatrick { 153*4bdff4beSrobert __semaphore_.release(__update); 154037e7968Spatrick } 155037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 156037e7968Spatrick void acquire() 157037e7968Spatrick { 158*4bdff4beSrobert __semaphore_.acquire(); 159037e7968Spatrick } 160037e7968Spatrick template<class Rep, class Period> 161037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 162037e7968Spatrick bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time) 163037e7968Spatrick { 164*4bdff4beSrobert return __semaphore_.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time)); 165037e7968Spatrick } 166037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 167037e7968Spatrick bool try_acquire() 168037e7968Spatrick { 169*4bdff4beSrobert return __semaphore_.try_acquire(); 170037e7968Spatrick } 171037e7968Spatrick template <class Clock, class Duration> 172037e7968Spatrick _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 173037e7968Spatrick bool try_acquire_until(chrono::time_point<Clock, Duration> const& __abs_time) 174037e7968Spatrick { 175037e7968Spatrick auto const current = Clock::now(); 176037e7968Spatrick if (current >= __abs_time) 177037e7968Spatrick return try_acquire(); 178037e7968Spatrick else 179037e7968Spatrick return try_acquire_for(__abs_time - current); 180037e7968Spatrick } 181037e7968Spatrick}; 182037e7968Spatrick 183037e7968Spatrickusing binary_semaphore = counting_semaphore<1>; 184037e7968Spatrick 185037e7968Spatrick_LIBCPP_END_NAMESPACE_STD 186037e7968Spatrick 187037e7968Spatrick#endif // _LIBCPP_STD_VER >= 14 188037e7968Spatrick 18976d0caaeSpatrick_LIBCPP_POP_MACROS 19076d0caaeSpatrick 191037e7968Spatrick#endif //_LIBCPP_SEMAPHORE 192