Line data Source code
1 :
2 : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2012, Marwan Abdellah <marwan.abdellah@epfl.ch>
4 : * 2012, Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #ifndef LUNCHBOX_THREAD_H
21 : #define LUNCHBOX_THREAD_H
22 :
23 : #include <lunchbox/api.h> // LUNCHBOX_API definition
24 : #include <lunchbox/debug.h> // debug macros in thread-safety checks
25 : #include <lunchbox/threadID.h> // member
26 : #include <lunchbox/types.h>
27 :
28 : #include <boost/noncopyable.hpp>
29 : #include <ostream>
30 :
31 : namespace lunchbox
32 : {
33 : namespace detail { class Thread; }
34 :
35 : /**
36 : * Utility class to execute code in a separate execution thread.
37 : * @deprecated Use Boost.Thread
38 : *
39 : * Example: @include tests/thread.cpp
40 : */
41 : class Thread
42 : {
43 : public:
44 : /** Enumeration values for thread affinity. */
45 : enum Affinity
46 : {
47 : NONE = 0, //!< Don't set any affinity
48 : CORE = 1, //!< Bind to a specific CPU core
49 : SOCKET = -65536, //!< Bind to all cores of a specific socket (CPU)
50 : SOCKET_MAX = -1024 //!< Highest bindable CPU
51 : };
52 :
53 : /** Construct a new thread. @version 1.0 */
54 : LUNCHBOX_API Thread();
55 :
56 : /** Copy constructor. @version 1.1.2 */
57 : LUNCHBOX_API Thread( const Thread& from );
58 :
59 : /** Destruct the thread. @version 1.0 */
60 : LUNCHBOX_API virtual ~Thread();
61 :
62 : /**
63 : * Start the thread.
64 : *
65 : * @return true if the thread was launched and initialized successfully,
66 : * false otherwise.
67 : * @sa init(), run()
68 : * @version 1.0
69 : */
70 : LUNCHBOX_API virtual bool start();
71 :
72 : /**
73 : * The init function for the child thread.
74 : *
75 : * The parent thread will not be unlocked before this function has been
76 : * executed. If the thread initialization fails, that is, this method does
77 : * return false, the thread will be stopped and the start() method will
78 : * return false.
79 : *
80 : * @return the success value of the thread initialization.
81 : * @version 1.0
82 : */
83 3238 : virtual bool init(){ return true; }
84 :
85 : /**
86 : * The entry function for the child thread.
87 : *
88 : * This method should contain the main execution routine for the thread and
89 : * is called after a successful init().
90 : *
91 : * @version 1.0
92 : */
93 : virtual void run() = 0;
94 :
95 : /**
96 : * Exit the child thread immediately.
97 : *
98 : * This function does not return. It is only to be called from the child
99 : * thread.
100 : *
101 : * @version 1.0
102 : */
103 : LUNCHBOX_API virtual void exit();
104 :
105 : /**
106 : * Cancel (stop) the child thread.
107 : *
108 : * This function is not to be called from the child thread.
109 : * @version 1.0
110 : */
111 : LUNCHBOX_API void cancel();
112 :
113 : /**
114 : * Wait for the exit of the child thread.
115 : *
116 : * @return true if the thread was joined, false otherwise.
117 : * @version 1.0
118 : */
119 : LUNCHBOX_API bool join();
120 :
121 : /**
122 : * Return if the thread is stopped.
123 : *
124 : * Note that the thread may be neither running nor stopped if it is
125 : * currently starting or stopping.
126 : *
127 : * @return true if the thread is stopped, false if not.
128 : * @version 1.0
129 : */
130 : LUNCHBOX_API bool isStopped() const;
131 :
132 : /**
133 : * Return if the thread is running.
134 : *
135 : * Note that the thread may be neither running nor stopped if it is
136 : * currently starting or stopping.
137 : *
138 : * @return true if the thread is running, false if not.
139 : * @version 1.0
140 : */
141 : LUNCHBOX_API bool isRunning() const;
142 :
143 : /**
144 : * @return true if the calling thread is the same thread as this
145 : * thread, false otherwise.
146 : * @version 1.0
147 : */
148 : LUNCHBOX_API bool isCurrent() const;
149 :
150 : /** @return a unique identifier for the calling thread. @version 1.0 */
151 : LUNCHBOX_API static ThreadID getSelfThreadID();
152 :
153 : /** @internal */
154 : LUNCHBOX_API static void yield();
155 :
156 : /** @internal */
157 : static void pinCurrentThread();
158 :
159 : /** @internal */
160 : LUNCHBOX_API static void setName( const std::string& name );
161 :
162 : /** @internal
163 : * Set the affinity of the calling thread.
164 : *
165 : * If given a value greater or equal than CORE, this method binds the
166 : * calling thread to core affinity - CORE. If set to a value greater than
167 : * CPU and smaller than 0, this method binds the calling thread to all cores
168 : * of the given processor (affinity - CPU).
169 : *
170 : * @param affinity the affinity value (see above).
171 : */
172 : LUNCHBOX_API static void setAffinity( const int32_t affinity );
173 :
174 : private:
175 : detail::Thread* const _impl;
176 :
177 : Thread& operator=( const Thread& ) { return *this; }
178 :
179 : static void* runChild( void* arg );
180 : void _runChild();
181 : };// LB_DEPRECATED;
182 :
183 : /** Output the affinity setting in human-readable form. @version 1.7.1 */
184 : LUNCHBOX_API std::ostream& operator << ( std::ostream&, const Thread::Affinity );
185 :
186 : // These thread-safety checks are for development purposes, to check that
187 : // certain objects are properly used within the framework. Leaving them enabled
188 : // during application development may cause false positives, e.g., when
189 : // threadsafety is ensured outside of the objects by the application.
190 :
191 : #ifndef NDEBUG
192 : # define LB_CHECK_THREADSAFETY
193 : #endif
194 :
195 : /** Declare a thread id variable to be used for thread-safety checks. */
196 : #define LB_TS_VAR( NAME ) \
197 : public: \
198 : struct NAME ## Struct \
199 : { \
200 : NAME ## Struct () \
201 : : extMutex( false ) \
202 : {} \
203 : mutable lunchbox::ThreadID id; \
204 : mutable std::string name; \
205 : bool extMutex; \
206 : mutable lunchbox::ThreadID inRegion; \
207 : } NAME; \
208 : private:
209 :
210 : #ifdef LB_CHECK_THREADSAFETY
211 : # define LB_TS_RESET( NAME ) NAME.id = lunchbox::ThreadID();
212 :
213 : # define LB_TS_THREAD( NAME ) \
214 : { \
215 : if( NAME.id == lunchbox::ThreadID( )) \
216 : { \
217 : NAME.id = lunchbox::Thread::getSelfThreadID(); \
218 : NAME.name = lunchbox::Log::instance().getThreadName(); \
219 : LBVERB << "Functions for " << #NAME \
220 : << " locked from" << lunchbox::backtrace << std::endl; \
221 : } \
222 : if( !NAME.extMutex && NAME.id != lunchbox::Thread::getSelfThreadID( )) \
223 : { \
224 : LBERROR << "Threadsafety check for " << #NAME \
225 : << " failed on object of type " \
226 : << lunchbox::className( this ) << ", thread " \
227 : << lunchbox::Thread::getSelfThreadID() << " (" \
228 : << lunchbox::Log::instance().getThreadName() << ") != " \
229 : << NAME.id << " (" << NAME.name << ")" << std::endl; \
230 : LBABORT( "Non-threadsafe code called from two threads" ); \
231 : } \
232 : }
233 :
234 : # define LB_TS_NOT_THREAD( NAME ) \
235 : { \
236 : if( !NAME.extMutex && NAME.id != lunchbox::ThreadID( )) \
237 : { \
238 : if( NAME.id == lunchbox::Thread::getSelfThreadID( )) \
239 : { \
240 : LBERROR << "Threadsafety check for not " << #NAME \
241 : << " failed on object of type " \
242 : << lunchbox::className( this ) << std::endl; \
243 : LBABORT( "Code called from wrong thread" ); \
244 : } \
245 : } \
246 : }
247 :
248 : /** @cond IGNORE */
249 : template< typename T > class ScopedThreadCheck : public boost::noncopyable
250 : {
251 : public:
252 1618197 : explicit ScopedThreadCheck( const T& data )
253 1618197 : : _data( data )
254 : {
255 1618197 : LBASSERTINFO( data.inRegion == lunchbox::ThreadID() ||
256 : data.inRegion == lunchbox::Thread::getSelfThreadID(),
257 : "Another thread already in critical region" );
258 1618197 : data.inRegion = lunchbox::Thread::getSelfThreadID();
259 1618197 : }
260 :
261 1618197 : ~ScopedThreadCheck()
262 : {
263 1618197 : LBASSERTINFO( _data.inRegion == lunchbox::ThreadID() ||
264 : _data.inRegion == lunchbox::Thread::getSelfThreadID(),
265 : "Another thread entered critical region" );
266 1618197 : _data.inRegion = lunchbox::ThreadID();
267 1618197 : }
268 : private:
269 : const T& _data;
270 : };
271 : /** @endcond */
272 :
273 : # define LB_TS_SCOPED( NAME ) \
274 : lunchbox::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME);
275 :
276 : #else
277 : # define LB_TS_RESET( NAME ) {}
278 : # define LB_TS_THREAD( NAME ) {}
279 : # define LB_TS_NOT_THREAD( NAME ) {}
280 : # define LB_TS_SCOPED( NAME ) {}
281 : #endif
282 :
283 : }
284 : #endif //LUNCHBOX_THREAD_H
|