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