blob: 5fcd2c988de911b014e3b9d707627dec0a50a31f [file] [log] [blame]
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00001// -*- C++ -*-
2//===--------------------------- thread -----------------------------------===//
3//
Howard Hinnantf5256e12010-05-11 21:36:01 +00004// The LLVM Compiler Infrastructure
Howard Hinnantbc8d3f92010-05-11 19:42:16 +00005//
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{
Howard Hinnantadff4892010-05-24 17:49:41 +0000118 // 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.
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000121 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
Howard Hinnantadff4892010-05-24 17:49:41 +0000212 bool joinable() const {return __t_ != 0;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000213 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{
Howard Hinnanta6a062d2010-06-02 18:20:39 +0000268 if (__t_ != 0)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000269 terminate();
270 __t_ = __t.__t_;
Howard Hinnanta6a062d2010-06-02 18:20:39 +0000271 __t.__t_ = 0;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000272 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