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