Lunchbox  1.8.0
thread.h
1 
2 /* Copyright (c) 2005-2013, 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/nonCopyable.h> // base class
26 #include <lunchbox/threadID.h> // member
27 #include <lunchbox/types.h>
28 
29 #include <ostream>
30 
31 namespace lunchbox
32 {
33 namespace detail { class Thread; }
34 
36 class Thread
37 {
38 public:
40  enum Affinity
41  {
42  NONE = 0,
43  CORE = 1,
44  SOCKET = -65536,
45  SOCKET_MAX = -1024
46  };
47 
49  LUNCHBOX_API Thread();
50 
52  LUNCHBOX_API Thread( const Thread& from );
53 
55  LUNCHBOX_API virtual ~Thread();
56 
65  LUNCHBOX_API virtual bool start();
66 
78  virtual bool init(){ return true; }
79 
88  virtual void run() = 0;
89 
98  LUNCHBOX_API virtual void exit();
99 
106  LUNCHBOX_API void cancel();
107 
114  LUNCHBOX_API bool join();
115 
125  LUNCHBOX_API bool isStopped() const;
126 
136  LUNCHBOX_API bool isRunning() const;
137 
143  LUNCHBOX_API bool isCurrent() const;
144 
146  LUNCHBOX_API static ThreadID getSelfThreadID();
147 
149  LUNCHBOX_API static void yield();
150 
152  static void pinCurrentThread();
153 
155  LUNCHBOX_API static void setName( const std::string& name );
156 
167  LUNCHBOX_API static void setAffinity( const int32_t affinity );
168 
169 private:
170  detail::Thread* const _impl;
171 
172  Thread& operator=( const Thread& ) { return *this; }
173 
174  static void* runChild( void* arg );
175  void _runChild();
176 };
177 
179 LUNCHBOX_API std::ostream& operator << ( std::ostream&, const Thread::Affinity );
180 
181 // thread-safety checks
182 // These checks are for development purposes, to check that certain objects are
183 // properly used within the framework. Leaving them enabled during application
184 // development may cause false positives, e.g., when threadsafety is ensured
185 // outside of the objects by the application.
186 
187 #ifndef NDEBUG
188 # define LB_CHECK_THREADSAFETY
189 #endif
190 
192 #define LB_TS_VAR( NAME ) \
193  public: \
194  struct NAME ## Struct \
195  { \
196  NAME ## Struct () \
197  : extMutex( false ) \
198  {} \
199  mutable lunchbox::ThreadID id; \
200  mutable std::string name; \
201  bool extMutex; \
202  mutable lunchbox::ThreadID inRegion; \
203  } NAME; \
204 private:
205 
206 #ifdef LB_CHECK_THREADSAFETY
207 # define LB_TS_RESET( NAME ) NAME.id = lunchbox::ThreadID();
208 
209 # define LB_TS_THREAD( NAME ) \
210  { \
211  if( NAME.id == lunchbox::ThreadID( )) \
212  { \
213  NAME.id = lunchbox::Thread::getSelfThreadID(); \
214  NAME.name = lunchbox::Log::instance().getThreadName(); \
215  LBVERB << "Functions for " << #NAME \
216  << " locked to this thread" << std::endl; \
217  } \
218  if( !NAME.extMutex && NAME.id != lunchbox::Thread::getSelfThreadID( )) \
219  { \
220  LBERROR << "Threadsafety check for " << #NAME \
221  << " failed on object of type " \
222  << lunchbox::className( this ) << ", thread " \
223  << lunchbox::Thread::getSelfThreadID() << " (" \
224  << lunchbox::Log::instance().getThreadName() << ") != " \
225  << NAME.id << " (" << NAME.name << ")" << std::endl; \
226  LBABORT( "Non-threadsave code called from two threads" ); \
227  } \
228  }
229 
230 # define LB_TS_NOT_THREAD( NAME ) \
231  { \
232  if( !NAME.extMutex && NAME.id != lunchbox::ThreadID( )) \
233  { \
234  if( NAME.id == lunchbox::Thread::getSelfThreadID( )) \
235  { \
236  LBERROR << "Threadsafety check for not " << #NAME \
237  << " failed on object of type " \
238  << lunchbox::className( this ) << std::endl; \
239  LBABORT( "Code called from wrong thread" ); \
240  } \
241  } \
242  }
243 
245 template< typename T > class ScopedThreadCheck : public NonCopyable
246 {
247 public:
248  explicit ScopedThreadCheck( const T& data )
249  : _data( data )
250  {
251  LBASSERTINFO( data.inRegion == lunchbox::ThreadID() ||
252  data.inRegion == lunchbox::Thread::getSelfThreadID(),
253  "Another thread already in critical region" );
254  data.inRegion = lunchbox::Thread::getSelfThreadID();
255  }
256 
257  ~ScopedThreadCheck()
258  {
259  LBASSERTINFO( _data.inRegion == lunchbox::ThreadID() ||
260  _data.inRegion == lunchbox::Thread::getSelfThreadID(),
261  "Another thread entered critical region" );
262  _data.inRegion = lunchbox::ThreadID();
263  }
264 private:
265  const T& _data;
266 };
269 # define LB_TS_SCOPED( NAME ) \
270  lunchbox::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME);
271 
272 #else
273 # define LB_TS_RESET( NAME ) {}
274 # define LB_TS_THREAD( NAME ) {}
275 # define LB_TS_NOT_THREAD( NAME ) {}
276 # define LB_TS_SCOPED( NAME ) {}
277 #endif
278 
279 }
280 #endif //LUNCHBOX_THREAD_H