thread revision 227825
1// -*- C++ -*-
2//===--------------------------- thread -----------------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. 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#ifndef _LIBCPP_HAS_NO_VARIADICS
99#include <tuple>
100#endif
101#include <pthread.h>
102
103#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
104#pragma GCC system_header
105#endif
106
107#define __STDCPP_THREADS__ __cplusplus
108
109_LIBCPP_BEGIN_NAMESPACE_STD
110
111template <class _Tp>
112class __thread_specific_ptr
113{
114    pthread_key_t __key_;
115
116    __thread_specific_ptr(const __thread_specific_ptr&);
117    __thread_specific_ptr& operator=(const __thread_specific_ptr&);
118
119    static void __at_thread_exit(void*);
120public:
121    typedef _Tp* pointer;
122
123    __thread_specific_ptr();
124    ~__thread_specific_ptr();
125
126    _LIBCPP_INLINE_VISIBILITY
127    pointer get() const {return static_cast<_Tp*>(pthread_getspecific(__key_));}
128    _LIBCPP_INLINE_VISIBILITY
129    pointer operator*() const {return *get();}
130    _LIBCPP_INLINE_VISIBILITY
131    pointer operator->() const {return get();}
132    pointer release();
133    void reset(pointer __p = nullptr);
134};
135
136template <class _Tp>
137void
138__thread_specific_ptr<_Tp>::__at_thread_exit(void* __p)
139{
140    delete static_cast<pointer>(__p);
141}
142
143template <class _Tp>
144__thread_specific_ptr<_Tp>::__thread_specific_ptr()
145{
146    int __ec = pthread_key_create(&__key_, &__thread_specific_ptr::__at_thread_exit);
147    if (__ec)
148        throw system_error(error_code(__ec, system_category()),
149                           "__thread_specific_ptr construction failed");
150}
151
152template <class _Tp>
153__thread_specific_ptr<_Tp>::~__thread_specific_ptr()
154{
155    pthread_key_delete(__key_);
156}
157
158template <class _Tp>
159typename __thread_specific_ptr<_Tp>::pointer
160__thread_specific_ptr<_Tp>::release()
161{
162    pointer __p = get();
163    pthread_setspecific(__key_, 0);
164    return __p;
165}
166
167template <class _Tp>
168void
169__thread_specific_ptr<_Tp>::reset(pointer __p)
170{
171    pointer __p_old = get();
172    pthread_setspecific(__key_, __p);
173    delete __p_old;
174}
175
176class thread;
177class __thread_id;
178
179namespace this_thread
180{
181
182__thread_id get_id();
183
184}  // this_thread
185
186class _LIBCPP_VISIBLE __thread_id
187{
188    // FIXME: pthread_t is a pointer on Darwin but a long on Linux.
189    // NULL is the no-thread value on Darwin.  Someone needs to check
190    // on other platforms.  We assume 0 works everywhere for now.
191    pthread_t __id_;
192
193public:
194    _LIBCPP_INLINE_VISIBILITY
195    __thread_id() : __id_(0) {}
196
197    friend _LIBCPP_INLINE_VISIBILITY
198        bool operator==(__thread_id __x, __thread_id __y)
199        {return __x.__id_ == __y.__id_;}
200    friend _LIBCPP_INLINE_VISIBILITY
201        bool operator!=(__thread_id __x, __thread_id __y)
202        {return !(__x == __y);}
203    friend _LIBCPP_INLINE_VISIBILITY
204        bool operator< (__thread_id __x, __thread_id __y)
205        {return __x.__id_ < __y.__id_;}
206    friend _LIBCPP_INLINE_VISIBILITY
207        bool operator<=(__thread_id __x, __thread_id __y)
208        {return !(__y < __x);}
209    friend _LIBCPP_INLINE_VISIBILITY
210        bool operator> (__thread_id __x, __thread_id __y)
211        {return   __y < __x ;}
212    friend _LIBCPP_INLINE_VISIBILITY
213        bool operator>=(__thread_id __x, __thread_id __y)
214        {return !(__x < __y);}
215
216    template<class _CharT, class _Traits>
217    friend
218    _LIBCPP_INLINE_VISIBILITY
219    basic_ostream<_CharT, _Traits>&
220    operator<<(basic_ostream<_CharT, _Traits>& __os, __thread_id __id)
221        {return __os << __id.__id_;}
222
223private:
224    _LIBCPP_INLINE_VISIBILITY
225    __thread_id(pthread_t __id) : __id_(__id) {}
226
227    friend __thread_id this_thread::get_id();
228    friend class _LIBCPP_VISIBLE thread;
229};
230
231template<class _Tp> struct hash;
232
233template<>
234struct _LIBCPP_VISIBLE hash<__thread_id>
235    : public unary_function<__thread_id, size_t>
236{
237    _LIBCPP_INLINE_VISIBILITY
238    size_t operator()(__thread_id __v) const
239    {
240        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
241        return *__p;
242    }
243};
244
245namespace this_thread
246{
247
248inline _LIBCPP_INLINE_VISIBILITY
249__thread_id
250get_id()
251{
252    return pthread_self();
253}
254
255}  // this_thread
256
257class _LIBCPP_VISIBLE thread
258{
259    pthread_t __t_;
260
261    thread(const thread&);
262    thread& operator=(const thread&);
263public:
264    typedef __thread_id id;
265    typedef pthread_t native_handle_type;
266
267    _LIBCPP_INLINE_VISIBILITY
268    thread() : __t_(0) {}
269#ifndef _LIBCPP_HAS_NO_VARIADICS
270    template <class _F, class ..._Args,
271              class = typename enable_if
272              <
273                   !is_same<typename decay<_F>::type, thread>::value
274              >::type
275             >
276        explicit thread(_F&& __f, _Args&&... __args);
277#else  // _LIBCPP_HAS_NO_VARIADICS
278    template <class _F> explicit thread(_F __f);
279#endif
280    ~thread();
281
282#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
283    _LIBCPP_INLINE_VISIBILITY
284    thread(thread&& __t) : __t_(__t.__t_) {__t.__t_ = 0;}
285    thread& operator=(thread&& __t);
286#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
287
288    _LIBCPP_INLINE_VISIBILITY
289    void swap(thread& __t) {_VSTD::swap(__t_, __t.__t_);}
290
291    _LIBCPP_INLINE_VISIBILITY
292    bool joinable() const {return __t_ != 0;}
293    void join();
294    void detach();
295    _LIBCPP_INLINE_VISIBILITY
296    id get_id() const {return __t_;}
297    _LIBCPP_INLINE_VISIBILITY
298    native_handle_type native_handle() {return __t_;}
299
300    static unsigned hardware_concurrency();
301};
302
303class __assoc_sub_state;
304
305class _LIBCPP_HIDDEN __thread_struct_imp;
306
307class __thread_struct
308{
309    __thread_struct_imp* __p_;
310
311    __thread_struct(const __thread_struct&);
312    __thread_struct& operator=(const __thread_struct&);
313public:
314    __thread_struct();
315    ~__thread_struct();
316
317    void notify_all_at_thread_exit(condition_variable*, mutex*);
318    void __make_ready_at_thread_exit(__assoc_sub_state*);
319};
320
321__thread_specific_ptr<__thread_struct>& __thread_local_data();
322
323#ifndef _LIBCPP_HAS_NO_VARIADICS
324
325template <class _F, class ..._Args, size_t ..._Indices>
326inline _LIBCPP_INLINE_VISIBILITY
327void
328__threaad_execute(tuple<_F, _Args...>& __t, __tuple_indices<_Indices...>)
329{
330    __invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
331}
332
333template <class _F>
334void*
335__thread_proxy(void* __vp)
336{
337    __thread_local_data().reset(new __thread_struct);
338    std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
339    typedef typename __make_tuple_indices<tuple_size<_F>::value, 1>::type _Index;
340    __threaad_execute(*__p, _Index());
341    return nullptr;
342}
343
344template <class _F, class ..._Args,
345          class
346         >
347thread::thread(_F&& __f, _Args&&... __args)
348{
349    typedef tuple<typename decay<_F>::type, typename decay<_Args>::type...> _G;
350    _VSTD::unique_ptr<_G> __p(new _G(__decay_copy(_VSTD::forward<_F>(__f)),
351                                __decay_copy(_VSTD::forward<_Args>(__args))...));
352    int __ec = pthread_create(&__t_, 0, &__thread_proxy<_G>, __p.get());
353    if (__ec == 0)
354        __p.release();
355    else
356        __throw_system_error(__ec, "thread constructor failed");
357}
358
359#else  // _LIBCPP_HAS_NO_VARIADICS
360
361template <class _F>
362void*
363__thread_proxy(void* __vp)
364{
365    __thread_local_data().reset(new __thread_struct);
366    std::unique_ptr<_F> __p(static_cast<_F*>(__vp));
367    (*__p)();
368    return nullptr;
369}
370
371template <class _F>
372thread::thread(_F __f)
373{
374    std::unique_ptr<_F> __p(new _F(__f));
375    int __ec = pthread_create(&__t_, 0, &__thread_proxy<_F>, __p.get());
376    if (__ec == 0)
377        __p.release();
378    else
379        __throw_system_error(__ec, "thread constructor failed");
380}
381
382#endif  // _LIBCPP_HAS_NO_VARIADICS
383
384#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
385
386inline _LIBCPP_INLINE_VISIBILITY
387thread&
388thread::operator=(thread&& __t)
389{
390    if (__t_ != 0)
391        terminate();
392    __t_ = __t.__t_;
393    __t.__t_ = 0;
394    return *this;
395}
396
397#endif  // _LIBCPP_HAS_NO_RVALUE_REFERENCES
398
399inline _LIBCPP_INLINE_VISIBILITY
400void swap(thread& __x, thread& __y) {__x.swap(__y);}
401
402namespace this_thread
403{
404
405void sleep_for(const chrono::nanoseconds& ns);
406
407template <class _Rep, class _Period>
408void
409sleep_for(const chrono::duration<_Rep, _Period>& __d)
410{
411    using namespace chrono;
412    nanoseconds __ns = duration_cast<nanoseconds>(__d);
413    if (__ns < __d)
414        ++__ns;
415    sleep_for(__ns);
416}
417
418template <class _Clock, class _Duration>
419void
420sleep_until(const chrono::time_point<_Clock, _Duration>& __t)
421{
422    using namespace chrono;
423    mutex __mut;
424    condition_variable __cv;
425    unique_lock<mutex> __lk(__mut);
426    while (_Clock::now() < __t)
427        __cv.wait_until(__lk, __t);
428}
429
430template <class _Duration>
431inline _LIBCPP_INLINE_VISIBILITY
432void
433sleep_until(const chrono::time_point<chrono::steady_clock, _Duration>& __t)
434{
435    using namespace chrono;
436    sleep_for(__t - steady_clock::now());
437}
438
439inline _LIBCPP_INLINE_VISIBILITY
440void yield() {sched_yield();}
441
442}  // this_thread
443
444_LIBCPP_END_NAMESPACE_STD
445
446#endif  // _LIBCPP_THREAD
447