xref: /llvm-project-15.0.7/libcxx/include/thread (revision 30fdc8d8)
1// -*- C++ -*-
2//===--------------------------- thread -----------------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP_THREAD
12#define _LIBCPP_THREAD
13
14/*
15
16    thread synopsis
17
18#define __STDCPP_THREADS __cplusplus
19
20namespace std
21{
22
23class thread
24{
25public:
26    class id;
27    typedef pthread_t native_handle_type;
28
29    thread();
30    template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
31    ~thread();
32
33    thread(const thread&) = delete;
34    thread(thread&& t);
35
36    thread& operator=(const thread&) = delete;
37    thread& operator=(thread&& t);
38
39    void swap(thread& t);
40
41    bool joinable() const;
42    void join();
43    void detach();
44    id get_id() const;
45    native_handle_type native_handle();
46
47    static unsigned hardware_concurrency();
48};
49
50void swap(thread& x, thread& y);
51
52class thread::id
53{
54public:
55    id();
56};
57
58bool operator==(thread::id x, thread::id y);
59bool operator!=(thread::id x, thread::id y);
60bool operator< (thread::id x, thread::id y);
61bool operator<=(thread::id x, thread::id y);
62bool operator> (thread::id x, thread::id y);
63bool operator>=(thread::id x, thread::id y);
64
65template<class charT, class traits>
66basic_ostream<charT, traits>&
67operator<<(basic_ostream<charT, traits>& out, thread::id id);
68
69namespace this_thread
70{
71
72thread::id get_id();
73
74void yield();
75
76template <class Clock, class Duration>
77void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
78
79template <class Rep, class Period>
80void sleep_for(const chrono::duration<Rep, Period>& rel_time);
81
82}  // this_thread
83
84}  // std
85
86*/
87
88#include <__config>
89#include <iosfwd>
90#include <__functional_base>
91#include <type_traits>
92#include <cstddef>
93#include <functional>
94#include <memory>
95#include <system_error>
96#include <chrono>
97#include <__mutex_base>
98#include <pthread.h>
99
100#pragma GCC system_header
101
102#define __STDCPP_THREADS __cplusplus
103
104_LIBCPP_BEGIN_NAMESPACE_STD
105
106class thread;
107class __thread_id;
108
109namespace this_thread
110{
111
112__thread_id get_id();
113
114}  // this_thread
115
116class __thread_id
117{
118    // FIXME: pthread_t is a pointer on Darwin but a long on Linux.
119    // NULL is the no-thread value on Darwin.  Someone needs to check
120    // on other platforms.  We assume 0 works everywhere for now.
121    pthread_t __id_;
122
123public:
124    __thread_id() : __id_(0) {}
125
126    friend bool operator==(__thread_id __x, __thread_id __y)
127        {return __x.__id_ == __y.__id_;}
128    friend bool operator!=(__thread_id __x, __thread_id __y)
129        {return !(__x == __y);}
130    friend bool operator< (__thread_id __x, __thread_id __y)
131        {return __x.__id_ < __y.__id_;}
132    friend bool operator<=(__thread_id __x, __thread_id __y)
133        {return !(__y < __x);}
134    friend bool operator> (__thread_id __x, __thread_id __y)
135        {return   __y < __x ;}
136    friend bool operator>=(__thread_id __x, __thread_id __y)
137        {return !(__x < __y);}
138
139    template<class _CharT, class _Traits>
140    friend
141    basic_ostream<_CharT, _Traits>&
142    operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
143        {return __os << __id.__id_;}
144
145private:
146    __thread_id(pthread_t __id) : __id_(__id) {}
147
148    friend __thread_id this_thread::get_id();
149    friend class thread;
150};
151
152template<class _Tp> struct hash;
153
154template<>
155struct hash<__thread_id>
156    : public unary_function<__thread_id, size_t>
157{
158    size_t operator()(__thread_id __v) const
159    {
160        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
161        return *__p;
162    }
163};
164
165namespace this_thread
166{
167
168inline
169__thread_id
170get_id()
171{
172    return pthread_self();
173}
174
175}  // this_thread
176
177class thread
178{
179    pthread_t __t_;
180
181#ifndef _LIBCPP_MOVE
182    thread(const thread&); // = delete;
183    thread& operator=(const thread&); // = delete;
184#endif
185public:
186    typedef __thread_id id;
187    typedef pthread_t native_handle_type;
188
189    thread() : __t_(0) {}
190#ifndef _LIBCPP_HAS_NO_VARIADICS
191    template <class _F, class ..._Args,
192              class = typename enable_if
193              <
194                   !is_same<typename decay<_F>::type, thread>::value
195              >::type
196             >
197        explicit thread(_F&& __f, _Args&&... __args);
198#else
199    template <class _F> explicit thread(_F __f);
200#endif
201    ~thread();
202
203#ifdef _LIBCPP_MOVE
204    thread(const thread&) = delete;
205    thread(thread&& __t) : __t_(__t.__t_) {__t.__t_ = 0;}
206    thread& operator=(const thread&) = delete;
207    thread& operator=(thread&& __t);
208#endif
209
210    void swap(thread& __t) {_STD::swap(__t_, __t.__t_);}
211
212    bool joinable() const {return __t_ != 0;}
213    void join();
214    void detach();
215    id get_id() const {return __t_;}
216    native_handle_type native_handle() {return __t_;}
217
218    static unsigned hardware_concurrency();
219};
220
221template <class _F>
222void*
223__thread_proxy(void* __vp)
224{
225    std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
226    (*__p)();
227    return nullptr;
228}
229
230#ifndef _LIBCPP_HAS_NO_VARIADICS
231
232template <class _F, class ..._Args,
233          class
234         >
235thread::thread(_F&& __f, _Args&&... __args)
236{
237    typedef decltype(bind(std::forward<_F>(__f), std::forward<_Args>(__args)...)) _G;
238    std::unique_ptr<_G> __p(new _G(bind(std::forward<_F>(__f),
239                              std::forward<_Args>(__args)...)));
240    int __ec = pthread_create(&__t_, 0, &__thread_proxy<_G>, __p.get());
241    if (__ec == 0)
242        __p.release();
243    else
244        __throw_system_error(__ec, "thread constructor failed");
245}
246
247#else
248
249template <class _F>
250thread::thread(_F __f)
251{
252    std::unique_ptr<_F> __p(new _F(__f));
253    int __ec = pthread_create(&__t_, 0, &__thread_proxy<_F>, __p.get());
254    if (__ec == 0)
255        __p.release();
256    else
257        __throw_system_error(__ec, "thread constructor failed");
258}
259
260#endif
261
262#ifdef _LIBCPP_MOVE
263
264inline
265thread&
266thread::operator=(thread&& __t)
267{
268    if (__t_ != 0)
269        terminate();
270    __t_ = __t.__t_;
271    __t.__t_ = 0;
272    return *this;
273}
274
275#endif
276
277inline
278void swap(thread& __x, thread& __y) {__x.swap(__y);}
279
280
281namespace this_thread
282{
283
284void sleep_for(const chrono::nanoseconds& ns);
285
286template <class _Rep, class _Period>
287void
288sleep_for(const chrono::duration<_Rep, _Period>& __d)
289{
290    using namespace chrono;
291    nanoseconds __ns = duration_cast<nanoseconds>(__d);
292    if (__ns < __d)
293        ++__ns;
294    sleep_for(__ns);
295}
296
297template <class _Clock, class _Duration>
298void
299sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
300{
301    using namespace chrono;
302    mutex __mut;
303    condition_variable __cv;
304    unique_lock<mutex> __lk(__mut);
305    while (_Clock::now() < __t)
306        __cv.wait_until(__lk, __t);
307}
308
309template <class _Duration>
310inline
311void
312sleep_until(const chrono::time_point<chrono::monotonic_clock, _Duration>& __t)
313{
314    using namespace chrono;
315    sleep_for(__t - monotonic_clock::now());
316}
317
318inline
319void yield() {sched_yield();}
320
321}  // this_thread
322
323_LIBCPP_END_NAMESPACE_STD
324
325#endif  // _LIBCPP_THREAD
326