1 /*
2     Copyright (c) 2005-2017 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 
16 
17 
18 
19 */
20 
21 #ifndef __TBB_tbb_thread_H
22 #define __TBB_tbb_thread_H
23 
24 #include "tbb_stddef.h"
25 
26 #if _WIN32||_WIN64
27 #include "machine/windows_api.h"
28 #define __TBB_NATIVE_THREAD_ROUTINE unsigned WINAPI
29 #define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) unsigned (WINAPI* r)( void* )
30 namespace tbb { namespace internal {
31 #if __TBB_WIN8UI_SUPPORT
32     typedef size_t thread_id_type;
33 #else  // __TBB_WIN8UI_SUPPORT
34     typedef DWORD thread_id_type;
35 #endif // __TBB_WIN8UI_SUPPORT
36 }} //namespace tbb::internal
37 #else
38 #define __TBB_NATIVE_THREAD_ROUTINE void*
39 #define __TBB_NATIVE_THREAD_ROUTINE_PTR(r) void* (*r)( void* )
40 #include <pthread.h>
41 namespace tbb { namespace internal {
42     typedef pthread_t thread_id_type;
43 }} //namespace tbb::internal
44 #endif // _WIN32||_WIN64
45 
46 #include "atomic.h"
47 #include "internal/_tbb_hash_compare_impl.h"
48 #include "tick_count.h"
49 
50 #include __TBB_STD_SWAP_HEADER
51 #include <iosfwd>
52 
53 namespace tbb {
54 
55 namespace internal {
56     class tbb_thread_v3;
57 }
58 
59 inline void swap( internal::tbb_thread_v3& t1, internal::tbb_thread_v3& t2 ) __TBB_NOEXCEPT(true);
60 
61 namespace internal {
62 
63     //! Allocate a closure
64     void* __TBB_EXPORTED_FUNC allocate_closure_v3( size_t size );
65     //! Free a closure allocated by allocate_closure_v3
66     void __TBB_EXPORTED_FUNC free_closure_v3( void* );
67 
68     struct thread_closure_base {
newthread_closure_base69         void* operator new( size_t size ) {return allocate_closure_v3(size);}
deletethread_closure_base70         void operator delete( void* ptr ) {free_closure_v3(ptr);}
71     };
72 
73     template<class F> struct thread_closure_0: thread_closure_base {
74         F function;
75 
start_routinethread_closure_076         static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
77             thread_closure_0 *self = static_cast<thread_closure_0*>(c);
78             self->function();
79             delete self;
80             return 0;
81         }
thread_closure_0thread_closure_082         thread_closure_0( const F& f ) : function(f) {}
83     };
84     //! Structure used to pass user function with 1 argument to thread.
85     template<class F, class X> struct thread_closure_1: thread_closure_base {
86         F function;
87         X arg1;
88         //! Routine passed to Windows's _beginthreadex by thread::internal_start() inside tbb.dll
start_routinethread_closure_189         static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
90             thread_closure_1 *self = static_cast<thread_closure_1*>(c);
91             self->function(self->arg1);
92             delete self;
93             return 0;
94         }
thread_closure_1thread_closure_195         thread_closure_1( const F& f, const X& x ) : function(f), arg1(x) {}
96     };
97     template<class F, class X, class Y> struct thread_closure_2: thread_closure_base {
98         F function;
99         X arg1;
100         Y arg2;
101         //! Routine passed to Windows's _beginthreadex by thread::internal_start() inside tbb.dll
start_routinethread_closure_2102         static __TBB_NATIVE_THREAD_ROUTINE start_routine( void* c ) {
103             thread_closure_2 *self = static_cast<thread_closure_2*>(c);
104             self->function(self->arg1, self->arg2);
105             delete self;
106             return 0;
107         }
thread_closure_2thread_closure_2108         thread_closure_2( const F& f, const X& x, const Y& y ) : function(f), arg1(x), arg2(y) {}
109     };
110 
111     //! Versioned thread class.
112     class tbb_thread_v3 {
113 #if __TBB_IF_NO_COPY_CTOR_MOVE_SEMANTICS_BROKEN
114         // Workaround for a compiler bug: declaring the copy constructor as public
115         // enables use of the moving constructor.
116         // The definition is not provided in order to prohibit copying.
117     public:
118 #endif
119         tbb_thread_v3(const tbb_thread_v3&); // = delete;   // Deny access
120     public:
121 #if _WIN32||_WIN64
122         typedef HANDLE native_handle_type;
123 #else
124         typedef pthread_t native_handle_type;
125 #endif // _WIN32||_WIN64
126 
127         class id;
128         //! Constructs a thread object that does not represent a thread of execution.
__TBB_NOEXCEPT(true)129         tbb_thread_v3() __TBB_NOEXCEPT(true) : my_handle(0)
130 #if _WIN32||_WIN64
131             , my_thread_id(0)
132 #endif // _WIN32||_WIN64
133         {}
134 
135         //! Constructs an object and executes f() in a new thread
tbb_thread_v3(F f)136         template <class F> explicit tbb_thread_v3(F f) {
137             typedef internal::thread_closure_0<F> closure_type;
138             internal_start(closure_type::start_routine, new closure_type(f));
139         }
140         //! Constructs an object and executes f(x) in a new thread
tbb_thread_v3(F f,X x)141         template <class F, class X> tbb_thread_v3(F f, X x) {
142             typedef internal::thread_closure_1<F,X> closure_type;
143             internal_start(closure_type::start_routine, new closure_type(f,x));
144         }
145         //! Constructs an object and executes f(x,y) in a new thread
tbb_thread_v3(F f,X x,Y y)146         template <class F, class X, class Y> tbb_thread_v3(F f, X x, Y y) {
147             typedef internal::thread_closure_2<F,X,Y> closure_type;
148             internal_start(closure_type::start_routine, new closure_type(f,x,y));
149         }
150 
151 #if __TBB_CPP11_RVALUE_REF_PRESENT
__TBB_NOEXCEPT(true)152         tbb_thread_v3(tbb_thread_v3&& x) __TBB_NOEXCEPT(true)
153             : my_handle(x.my_handle)
154 #if _WIN32||_WIN64
155             , my_thread_id(x.my_thread_id)
156 #endif
157         {
158             x.internal_wipe();
159         }
__TBB_NOEXCEPT(true)160         tbb_thread_v3& operator=(tbb_thread_v3&& x) __TBB_NOEXCEPT(true) {
161             internal_move(x);
162             return *this;
163         }
164     private:
165         tbb_thread_v3& operator=(const tbb_thread_v3& x); // = delete;
166     public:
167 #else  // __TBB_CPP11_RVALUE_REF_PRESENT
168         tbb_thread_v3& operator=(tbb_thread_v3& x) {
169             internal_move(x);
170             return *this;
171         }
172 #endif // __TBB_CPP11_RVALUE_REF_PRESENT
173 
swap(tbb_thread_v3 & t)174         void swap( tbb_thread_v3& t ) __TBB_NOEXCEPT(true) {tbb::swap( *this, t );}
joinable()175         bool joinable() const __TBB_NOEXCEPT(true) {return my_handle!=0; }
176         //! The completion of the thread represented by *this happens before join() returns.
177         void __TBB_EXPORTED_METHOD join();
178         //! When detach() returns, *this no longer represents the possibly continuing thread of execution.
179         void __TBB_EXPORTED_METHOD detach();
~tbb_thread_v3()180         ~tbb_thread_v3() {if( joinable() ) detach();}
181         inline id get_id() const __TBB_NOEXCEPT(true);
native_handle()182         native_handle_type native_handle() { return my_handle; }
183 
184         //! The number of hardware thread contexts.
185         /** Before TBB 3.0 U4 this methods returned the number of logical CPU in
186             the system. Currently on Windows, Linux and FreeBSD it returns the
187             number of logical CPUs available to the current process in accordance
188             with its affinity mask.
189 
190             NOTE: The return value of this method never changes after its first
191             invocation. This means that changes in the process affinity mask that
192             took place after this method was first invoked will not affect the
193             number of worker threads in the TBB worker threads pool. **/
194         static unsigned __TBB_EXPORTED_FUNC hardware_concurrency() __TBB_NOEXCEPT(true);
195     private:
196         native_handle_type my_handle;
197 #if _WIN32||_WIN64
198         thread_id_type my_thread_id;
199 #endif // _WIN32||_WIN64
200 
internal_wipe()201         void internal_wipe() __TBB_NOEXCEPT(true) {
202             my_handle = 0;
203 #if _WIN32||_WIN64
204             my_thread_id = 0;
205 #endif
206         }
internal_move(tbb_thread_v3 & x)207         void internal_move(tbb_thread_v3& x) __TBB_NOEXCEPT(true) {
208             if (joinable()) detach();
209             my_handle = x.my_handle;
210 #if _WIN32||_WIN64
211             my_thread_id = x.my_thread_id;
212 #endif // _WIN32||_WIN64
213             x.internal_wipe();
214         }
215 
216         /** Runs start_routine(closure) on another thread and sets my_handle to the handle of the created thread. */
217         void __TBB_EXPORTED_METHOD internal_start( __TBB_NATIVE_THREAD_ROUTINE_PTR(start_routine),
218                              void* closure );
219         friend void __TBB_EXPORTED_FUNC move_v3( tbb_thread_v3& t1, tbb_thread_v3& t2 );
220         friend void tbb::swap( tbb_thread_v3& t1, tbb_thread_v3& t2 ) __TBB_NOEXCEPT(true);
221     };
222 
223     class tbb_thread_v3::id {
224         thread_id_type my_id;
id(thread_id_type id_)225         id( thread_id_type id_ ) : my_id(id_) {}
226 
227         friend class tbb_thread_v3;
228     public:
id()229         id() __TBB_NOEXCEPT(true) : my_id(0) {}
230 
231         friend bool operator==( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
232         friend bool operator!=( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
233         friend bool operator<( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
234         friend bool operator<=( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
235         friend bool operator>( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
236         friend bool operator>=( tbb_thread_v3::id x, tbb_thread_v3::id y ) __TBB_NOEXCEPT(true);
237 
238         template<class charT, class traits>
239         friend std::basic_ostream<charT, traits>&
240         operator<< (std::basic_ostream<charT, traits> &out,
241                     tbb_thread_v3::id id)
242         {
243             out << id.my_id;
244             return out;
245         }
246         friend tbb_thread_v3::id __TBB_EXPORTED_FUNC thread_get_id_v3();
247 
tbb_hasher(const tbb_thread_v3::id & id)248         friend inline size_t tbb_hasher( const tbb_thread_v3::id& id ) {
249             __TBB_STATIC_ASSERT(sizeof(id.my_id) <= sizeof(size_t), "Implementaion assumes that thread_id_type fits into machine word");
250             return tbb::tbb_hasher(id.my_id);
251         }
252 
253         // A workaround for lack of tbb::atomic<id> (which would require id to be POD in C++03).
atomic_compare_and_swap(id & location,const id & value,const id & comparand)254         friend id atomic_compare_and_swap(id& location, const id& value, const id& comparand){
255             return as_atomic(location.my_id).compare_and_swap(value.my_id, comparand.my_id);
256         }
257     }; // tbb_thread_v3::id
258 
get_id()259     tbb_thread_v3::id tbb_thread_v3::get_id() const __TBB_NOEXCEPT(true) {
260 #if _WIN32||_WIN64
261         return id(my_thread_id);
262 #else
263         return id(my_handle);
264 #endif // _WIN32||_WIN64
265     }
266 
267     void __TBB_EXPORTED_FUNC move_v3( tbb_thread_v3& t1, tbb_thread_v3& t2 );
268     tbb_thread_v3::id __TBB_EXPORTED_FUNC thread_get_id_v3();
269     void __TBB_EXPORTED_FUNC thread_yield_v3();
270     void __TBB_EXPORTED_FUNC thread_sleep_v3(const tick_count::interval_t &i);
271 
272     inline bool operator==(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
273     {
274         return x.my_id == y.my_id;
275     }
276     inline bool operator!=(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
277     {
278         return x.my_id != y.my_id;
279     }
280     inline bool operator<(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
281     {
282         return x.my_id < y.my_id;
283     }
284     inline bool operator<=(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
285     {
286         return x.my_id <= y.my_id;
287     }
__TBB_NOEXCEPT(true)288     inline bool operator>(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
289     {
290         return x.my_id > y.my_id;
291     }
__TBB_NOEXCEPT(true)292     inline bool operator>=(tbb_thread_v3::id x, tbb_thread_v3::id y) __TBB_NOEXCEPT(true)
293     {
294         return x.my_id >= y.my_id;
295     }
296 
297 } // namespace internal;
298 
299 //! Users reference thread class by name tbb_thread
300 typedef internal::tbb_thread_v3 tbb_thread;
301 
302 using internal::operator==;
303 using internal::operator!=;
304 using internal::operator<;
305 using internal::operator>;
306 using internal::operator<=;
307 using internal::operator>=;
308 
move(tbb_thread & t1,tbb_thread & t2)309 inline void move( tbb_thread& t1, tbb_thread& t2 ) {
310     internal::move_v3(t1, t2);
311 }
312 
swap(internal::tbb_thread_v3 & t1,internal::tbb_thread_v3 & t2)313 inline void swap( internal::tbb_thread_v3& t1, internal::tbb_thread_v3& t2 )  __TBB_NOEXCEPT(true) {
314     std::swap(t1.my_handle, t2.my_handle);
315 #if _WIN32||_WIN64
316     std::swap(t1.my_thread_id, t2.my_thread_id);
317 #endif /* _WIN32||_WIN64 */
318 }
319 
320 namespace this_tbb_thread {
get_id()321     inline tbb_thread::id get_id() { return internal::thread_get_id_v3(); }
322     //! Offers the operating system the opportunity to schedule another thread.
yield()323     inline void yield() { internal::thread_yield_v3(); }
324     //! The current thread blocks at least until the time specified.
sleep(const tick_count::interval_t & i)325     inline void sleep(const tick_count::interval_t &i) {
326         internal::thread_sleep_v3(i);
327     }
328 }  // namespace this_tbb_thread
329 
330 } // namespace tbb
331 
332 #endif /* __TBB_tbb_thread_H */
333