xref: /netbsd-src/external/apache2/llvm/dist/libcxx/include/semaphore (revision 4d6fc14bc9b0c5bf3e30be318c143ee82cadd108)
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