blob: 6bf3189294fb08ec8946d35edb7009099269c80e [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
Howard Hinnant60a0a8e2010-08-10 20:48:29 +0000181#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
182 thread(const thread&) = delete;
183 thread& operator=(const thread&) = delete;
184#else
185 thread(const thread&);
186 thread& operator=(const thread&);
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000187#endif
188public:
189 typedef __thread_id id;
190 typedef pthread_t native_handle_type;
191
192 thread() : __t_(0) {}
193#ifndef _LIBCPP_HAS_NO_VARIADICS
194 template <class _F, class ..._Args,
195 class = typename enable_if
196 <
197 !is_same<typename decay<_F>::type, thread>::value
198 >::type
199 >
200 explicit thread(_F&& __f, _Args&&... __args);
201#else
202 template <class _F> explicit thread(_F __f);
203#endif
204 ~thread();
205
206#ifdef _LIBCPP_MOVE
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000207 thread(thread&& __t) : __t_(__t.__t_) {__t.__t_ = 0;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000208 thread& operator=(thread&& __t);
209#endif
210
211 void swap(thread& __t) {_STD::swap(__t_, __t.__t_);}
212
Howard Hinnantadff4892010-05-24 17:49:41 +0000213 bool joinable() const {return __t_ != 0;}
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000214 void join();
215 void detach();
216 id get_id() const {return __t_;}
217 native_handle_type native_handle() {return __t_;}
218
219 static unsigned hardware_concurrency();
220};
221
222template <class _F>
223void*
224__thread_proxy(void* __vp)
225{
226 std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
227 (*__p)();
228 return nullptr;
229}
230
231#ifndef _LIBCPP_HAS_NO_VARIADICS
232
233template <class _F, class ..._Args,
234 class
235 >
236thread::thread(_F&& __f, _Args&&... __args)
237{
238 typedef decltype(bind(std::forward<_F>(__f), std::forward<_Args>(__args)...)) _G;
239 std::unique_ptr<_G> __p(new _G(bind(std::forward<_F>(__f),
240 std::forward<_Args>(__args)...)));
241 int __ec = pthread_create(&__t_, 0, &__thread_proxy<_G>, __p.get());
242 if (__ec == 0)
243 __p.release();
244 else
245 __throw_system_error(__ec, "thread constructor failed");
246}
247
248#else
249
250template <class _F>
251thread::thread(_F __f)
252{
253 std::unique_ptr<_F> __p(new _F(__f));
254 int __ec = pthread_create(&__t_, 0, &__thread_proxy<_F>, __p.get());
255 if (__ec == 0)
256 __p.release();
257 else
258 __throw_system_error(__ec, "thread constructor failed");
259}
260
261#endif
262
263#ifdef _LIBCPP_MOVE
264
265inline
266thread&
267thread::operator=(thread&& __t)
268{
Howard Hinnanta6a062d2010-06-02 18:20:39 +0000269 if (__t_ != 0)
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000270 terminate();
271 __t_ = __t.__t_;
Howard Hinnanta6a062d2010-06-02 18:20:39 +0000272 __t.__t_ = 0;
Howard Hinnantbc8d3f92010-05-11 19:42:16 +0000273 return *this;
274}
275
276#endif
277
278inline
279void swap(thread& __x, thread& __y) {__x.swap(__y);}
280
281
282namespace this_thread
283{
284
285void sleep_for(const chrono::nanoseconds& ns);
286
287template <class _Rep, class _Period>
288void
289sleep_for(const chrono::duration<_Rep, _Period>& __d)
290{
291 using namespace chrono;
292 nanoseconds __ns = duration_cast<nanoseconds>(__d);
293 if (__ns < __d)
294 ++__ns;
295 sleep_for(__ns);
296}
297
298template <class _Clock, class _Duration>
299void
300sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
301{
302 using namespace chrono;
303 mutex __mut;
304 condition_variable __cv;
305 unique_lock<mutex> __lk(__mut);
306 while (_Clock::now() < __t)
307 __cv.wait_until(__lk, __t);
308}
309
310template <class _Duration>
311inline
312void
313sleep_until(const chrono::time_point<chrono::monotonic_clock, _Duration>& __t)
314{
315 using namespace chrono;
316 sleep_for(__t - monotonic_clock::now());
317}
318
319inline
320void yield() {sched_yield();}
321
322} // this_thread
323
324_LIBCPP_END_NAMESPACE_STD
325
326#endif // _LIBCPP_THREAD