1*4d6fc14bSjoerg// -*- C++ -*- 2*4d6fc14bSjoerg//===--------------------------- semaphore --------------------------------===// 3*4d6fc14bSjoerg// 4*4d6fc14bSjoerg// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*4d6fc14bSjoerg// See https://llvm.org/LICENSE.txt for license information. 6*4d6fc14bSjoerg// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*4d6fc14bSjoerg// 8*4d6fc14bSjoerg//===----------------------------------------------------------------------===// 9*4d6fc14bSjoerg 10*4d6fc14bSjoerg#ifndef _LIBCPP_SEMAPHORE 11*4d6fc14bSjoerg#define _LIBCPP_SEMAPHORE 12*4d6fc14bSjoerg 13*4d6fc14bSjoerg/* 14*4d6fc14bSjoerg semaphore synopsis 15*4d6fc14bSjoerg 16*4d6fc14bSjoergnamespace std { 17*4d6fc14bSjoerg 18*4d6fc14bSjoergtemplate<ptrdiff_t least_max_value = implementation-defined> 19*4d6fc14bSjoergclass counting_semaphore 20*4d6fc14bSjoerg{ 21*4d6fc14bSjoergpublic: 22*4d6fc14bSjoergstatic constexpr ptrdiff_t max() noexcept; 23*4d6fc14bSjoerg 24*4d6fc14bSjoergconstexpr explicit counting_semaphore(ptrdiff_t desired); 25*4d6fc14bSjoerg~counting_semaphore(); 26*4d6fc14bSjoerg 27*4d6fc14bSjoergcounting_semaphore(const counting_semaphore&) = delete; 28*4d6fc14bSjoergcounting_semaphore& operator=(const counting_semaphore&) = delete; 29*4d6fc14bSjoerg 30*4d6fc14bSjoergvoid release(ptrdiff_t update = 1); 31*4d6fc14bSjoergvoid acquire(); 32*4d6fc14bSjoergbool try_acquire() noexcept; 33*4d6fc14bSjoergtemplate<class Rep, class Period> 34*4d6fc14bSjoerg bool try_acquire_for(const chrono::duration<Rep, Period>& rel_time); 35*4d6fc14bSjoergtemplate<class Clock, class Duration> 36*4d6fc14bSjoerg bool try_acquire_until(const chrono::time_point<Clock, Duration>& abs_time); 37*4d6fc14bSjoerg 38*4d6fc14bSjoergprivate: 39*4d6fc14bSjoergptrdiff_t counter; // exposition only 40*4d6fc14bSjoerg}; 41*4d6fc14bSjoerg 42*4d6fc14bSjoergusing binary_semaphore = counting_semaphore<1>; 43*4d6fc14bSjoerg 44*4d6fc14bSjoerg} 45*4d6fc14bSjoerg 46*4d6fc14bSjoerg*/ 47*4d6fc14bSjoerg 48*4d6fc14bSjoerg#include <__config> 49*4d6fc14bSjoerg#include <__availability> 50*4d6fc14bSjoerg#include <__threading_support> 51*4d6fc14bSjoerg#include <atomic> 52*4d6fc14bSjoerg 53*4d6fc14bSjoerg#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 54*4d6fc14bSjoerg#pragma GCC system_header 55*4d6fc14bSjoerg#endif 56*4d6fc14bSjoerg 57*4d6fc14bSjoerg#ifdef _LIBCPP_HAS_NO_THREADS 58*4d6fc14bSjoerg# error <semaphore> is not supported on this single threaded system 59*4d6fc14bSjoerg#endif 60*4d6fc14bSjoerg 61*4d6fc14bSjoerg_LIBCPP_PUSH_MACROS 62*4d6fc14bSjoerg#include <__undef_macros> 63*4d6fc14bSjoerg 64*4d6fc14bSjoerg#if _LIBCPP_STD_VER >= 14 65*4d6fc14bSjoerg 66*4d6fc14bSjoerg_LIBCPP_BEGIN_NAMESPACE_STD 67*4d6fc14bSjoerg 68*4d6fc14bSjoerg/* 69*4d6fc14bSjoerg 70*4d6fc14bSjoerg__atomic_semaphore_base is the general-case implementation, to be used for 71*4d6fc14bSjoerguser-requested least-max values that exceed the OS implementation support 72*4d6fc14bSjoerg(incl. when the OS has no support of its own) and for binary semaphores. 73*4d6fc14bSjoerg 74*4d6fc14bSjoergIt is a typical Dijkstra semaphore algorithm over atomics, wait and notify 75*4d6fc14bSjoergfunctions. It avoids contention against users' own use of those facilities. 76*4d6fc14bSjoerg 77*4d6fc14bSjoerg*/ 78*4d6fc14bSjoerg 79*4d6fc14bSjoergclass __atomic_semaphore_base 80*4d6fc14bSjoerg{ 81*4d6fc14bSjoerg __atomic_base<ptrdiff_t> __a; 82*4d6fc14bSjoerg 83*4d6fc14bSjoergpublic: 84*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 85*4d6fc14bSjoerg __atomic_semaphore_base(ptrdiff_t __count) : __a(__count) 86*4d6fc14bSjoerg { 87*4d6fc14bSjoerg } 88*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 89*4d6fc14bSjoerg void release(ptrdiff_t __update = 1) 90*4d6fc14bSjoerg { 91*4d6fc14bSjoerg if(0 < __a.fetch_add(__update, memory_order_release)) 92*4d6fc14bSjoerg ; 93*4d6fc14bSjoerg else if(__update > 1) 94*4d6fc14bSjoerg __a.notify_all(); 95*4d6fc14bSjoerg else 96*4d6fc14bSjoerg __a.notify_one(); 97*4d6fc14bSjoerg } 98*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 99*4d6fc14bSjoerg void acquire() 100*4d6fc14bSjoerg { 101*4d6fc14bSjoerg auto const __test_fn = [=]() -> bool { 102*4d6fc14bSjoerg auto __old = __a.load(memory_order_relaxed); 103*4d6fc14bSjoerg return (__old != 0) && __a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed); 104*4d6fc14bSjoerg }; 105*4d6fc14bSjoerg __cxx_atomic_wait(&__a.__a_, __test_fn); 106*4d6fc14bSjoerg } 107*4d6fc14bSjoerg template <class Rep, class Period> 108*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 109*4d6fc14bSjoerg bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time) 110*4d6fc14bSjoerg { 111*4d6fc14bSjoerg auto const __test_fn = [=]() -> bool { 112*4d6fc14bSjoerg auto __old = __a.load(memory_order_acquire); 113*4d6fc14bSjoerg while(1) { 114*4d6fc14bSjoerg if (__old == 0) 115*4d6fc14bSjoerg return false; 116*4d6fc14bSjoerg if(__a.compare_exchange_strong(__old, __old - 1, memory_order_acquire, memory_order_relaxed)) 117*4d6fc14bSjoerg return true; 118*4d6fc14bSjoerg } 119*4d6fc14bSjoerg }; 120*4d6fc14bSjoerg return __libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy(), __rel_time); 121*4d6fc14bSjoerg } 122*4d6fc14bSjoerg}; 123*4d6fc14bSjoerg 124*4d6fc14bSjoerg#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES 125*4d6fc14bSjoerg 126*4d6fc14bSjoerg/* 127*4d6fc14bSjoerg 128*4d6fc14bSjoerg__platform_semaphore_base a simple wrapper for the OS semaphore type. That 129*4d6fc14bSjoergis, every call is routed to the OS in the most direct manner possible. 130*4d6fc14bSjoerg 131*4d6fc14bSjoerg*/ 132*4d6fc14bSjoerg 133*4d6fc14bSjoergclass __platform_semaphore_base 134*4d6fc14bSjoerg{ 135*4d6fc14bSjoerg __libcpp_semaphore_t __semaphore; 136*4d6fc14bSjoerg 137*4d6fc14bSjoergpublic: 138*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 139*4d6fc14bSjoerg __platform_semaphore_base(ptrdiff_t __count) : 140*4d6fc14bSjoerg __semaphore() 141*4d6fc14bSjoerg { 142*4d6fc14bSjoerg __libcpp_semaphore_init(&__semaphore, __count); 143*4d6fc14bSjoerg } 144*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 145*4d6fc14bSjoerg ~__platform_semaphore_base() { 146*4d6fc14bSjoerg __libcpp_semaphore_destroy(&__semaphore); 147*4d6fc14bSjoerg } 148*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 149*4d6fc14bSjoerg void release(ptrdiff_t __update) 150*4d6fc14bSjoerg { 151*4d6fc14bSjoerg for(; __update; --__update) 152*4d6fc14bSjoerg __libcpp_semaphore_post(&__semaphore); 153*4d6fc14bSjoerg } 154*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 155*4d6fc14bSjoerg void acquire() 156*4d6fc14bSjoerg { 157*4d6fc14bSjoerg __libcpp_semaphore_wait(&__semaphore); 158*4d6fc14bSjoerg } 159*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 160*4d6fc14bSjoerg bool try_acquire_for(chrono::nanoseconds __rel_time) 161*4d6fc14bSjoerg { 162*4d6fc14bSjoerg return __libcpp_semaphore_wait_timed(&__semaphore, __rel_time); 163*4d6fc14bSjoerg } 164*4d6fc14bSjoerg}; 165*4d6fc14bSjoerg 166*4d6fc14bSjoergtemplate<ptrdiff_t __least_max_value> 167*4d6fc14bSjoergusing __semaphore_base = 168*4d6fc14bSjoerg typename conditional<(__least_max_value > 1 && __least_max_value <= _LIBCPP_SEMAPHORE_MAX), 169*4d6fc14bSjoerg __platform_semaphore_base, 170*4d6fc14bSjoerg __atomic_semaphore_base>::type; 171*4d6fc14bSjoerg 172*4d6fc14bSjoerg#else 173*4d6fc14bSjoerg 174*4d6fc14bSjoergtemplate<ptrdiff_t __least_max_value> 175*4d6fc14bSjoergusing __semaphore_base = 176*4d6fc14bSjoerg __atomic_semaphore_base; 177*4d6fc14bSjoerg 178*4d6fc14bSjoerg#define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max()) 179*4d6fc14bSjoerg 180*4d6fc14bSjoerg#endif //_LIBCPP_NO_NATIVE_SEMAPHORES 181*4d6fc14bSjoerg 182*4d6fc14bSjoergtemplate<ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX> 183*4d6fc14bSjoergclass counting_semaphore 184*4d6fc14bSjoerg{ 185*4d6fc14bSjoerg __semaphore_base<__least_max_value> __semaphore; 186*4d6fc14bSjoerg 187*4d6fc14bSjoergpublic: 188*4d6fc14bSjoerg static constexpr ptrdiff_t max() noexcept { 189*4d6fc14bSjoerg return __least_max_value; 190*4d6fc14bSjoerg } 191*4d6fc14bSjoerg 192*4d6fc14bSjoerg _LIBCPP_INLINE_VISIBILITY 193*4d6fc14bSjoerg counting_semaphore(ptrdiff_t __count = 0) : __semaphore(__count) { } 194*4d6fc14bSjoerg ~counting_semaphore() = default; 195*4d6fc14bSjoerg 196*4d6fc14bSjoerg counting_semaphore(const counting_semaphore&) = delete; 197*4d6fc14bSjoerg counting_semaphore& operator=(const counting_semaphore&) = delete; 198*4d6fc14bSjoerg 199*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 200*4d6fc14bSjoerg void release(ptrdiff_t __update = 1) 201*4d6fc14bSjoerg { 202*4d6fc14bSjoerg __semaphore.release(__update); 203*4d6fc14bSjoerg } 204*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 205*4d6fc14bSjoerg void acquire() 206*4d6fc14bSjoerg { 207*4d6fc14bSjoerg __semaphore.acquire(); 208*4d6fc14bSjoerg } 209*4d6fc14bSjoerg template<class Rep, class Period> 210*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 211*4d6fc14bSjoerg bool try_acquire_for(chrono::duration<Rep, Period> const& __rel_time) 212*4d6fc14bSjoerg { 213*4d6fc14bSjoerg return __semaphore.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time)); 214*4d6fc14bSjoerg } 215*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 216*4d6fc14bSjoerg bool try_acquire() 217*4d6fc14bSjoerg { 218*4d6fc14bSjoerg return try_acquire_for(chrono::nanoseconds::zero()); 219*4d6fc14bSjoerg } 220*4d6fc14bSjoerg template <class Clock, class Duration> 221*4d6fc14bSjoerg _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INLINE_VISIBILITY 222*4d6fc14bSjoerg bool try_acquire_until(chrono::time_point<Clock, Duration> const& __abs_time) 223*4d6fc14bSjoerg { 224*4d6fc14bSjoerg auto const current = Clock::now(); 225*4d6fc14bSjoerg if(current >= __abs_time) 226*4d6fc14bSjoerg return try_acquire(); 227*4d6fc14bSjoerg else 228*4d6fc14bSjoerg return try_acquire_for(__abs_time - current); 229*4d6fc14bSjoerg } 230*4d6fc14bSjoerg}; 231*4d6fc14bSjoerg 232*4d6fc14bSjoergusing binary_semaphore = counting_semaphore<1>; 233*4d6fc14bSjoerg 234*4d6fc14bSjoerg_LIBCPP_END_NAMESPACE_STD 235*4d6fc14bSjoerg 236*4d6fc14bSjoerg#endif // _LIBCPP_STD_VER >= 14 237*4d6fc14bSjoerg 238*4d6fc14bSjoerg_LIBCPP_POP_MACROS 239*4d6fc14bSjoerg 240*4d6fc14bSjoerg#endif //_LIBCPP_SEMAPHORE 241