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