Lunchbox
1.6.0
|
00001 00002 /* Copyright (c) 2005-2012, Stefan Eilemann <eile@equalizergraphics.com> 00003 * 2012, Marwan Abdellah <marwan.abdellah@epfl.ch> 00004 * 2012, Daniel Nachbaur <danielnachbaur@gmail.com> 00005 * 00006 * This library is free software; you can redistribute it and/or modify it under 00007 * the terms of the GNU Lesser General Public License version 2.1 as published 00008 * by the Free Software Foundation. 00009 * 00010 * This library is distributed in the hope that it will be useful, but WITHOUT 00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00012 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00013 * details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this library; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 00020 #ifndef LUNCHBOX_THREAD_H 00021 #define LUNCHBOX_THREAD_H 00022 00023 #include <lunchbox/api.h> // LUNCHBOX_API definition 00024 #include <lunchbox/debug.h> // debug macros in thread-safety checks 00025 #include <lunchbox/nonCopyable.h> // base class 00026 #include <lunchbox/threadID.h> // member 00027 #include <lunchbox/types.h> 00028 00029 #include <ostream> 00030 00031 namespace lunchbox 00032 { 00033 namespace detail { class Thread; } 00034 00036 class Thread 00037 { 00038 public: 00040 enum Affinity 00041 { 00042 NONE = 0, 00043 CORE = 1, 00044 SOCKET = -65536, 00045 SOCKET_MAX = -1024 00046 }; 00047 00049 LUNCHBOX_API Thread(); 00050 00052 LUNCHBOX_API Thread( const Thread& from ); 00053 00055 LUNCHBOX_API virtual ~Thread(); 00056 00065 LUNCHBOX_API virtual bool start(); 00066 00078 virtual bool init(){ return true; } 00079 00088 virtual void run() = 0; 00089 00098 LUNCHBOX_API virtual void exit(); 00099 00106 LUNCHBOX_API void cancel(); 00107 00114 LUNCHBOX_API bool join(); 00115 00125 LUNCHBOX_API bool isStopped() const; 00126 00136 LUNCHBOX_API bool isRunning() const; 00137 00143 LUNCHBOX_API bool isCurrent() const; 00144 00146 LUNCHBOX_API static ThreadID getSelfThreadID(); 00147 00149 LUNCHBOX_API static void yield(); 00150 00152 static void pinCurrentThread(); 00153 00155 LUNCHBOX_API static void setName( const std::string& name ); 00156 00167 LUNCHBOX_API static void setAffinity( const int32_t affinity ); 00168 00169 private: 00170 detail::Thread* const _impl; 00171 00172 static void* runChild( void* arg ); 00173 void _runChild(); 00174 00175 void _installCleanupHandler(); 00176 00177 static void _notifyStarted(); 00178 static void _notifyStopping(); 00179 friend void _notifyStopping( void* ); 00180 }; 00181 00182 // thread-safety checks 00183 // These checks are for development purposes, to check that certain objects are 00184 // properly used within the framework. Leaving them enabled during application 00185 // development may cause false positives, e.g., when threadsafety is ensured 00186 // outside of the objects by the application. 00187 00188 #ifndef NDEBUG 00189 # define LB_CHECK_THREADSAFETY 00190 #endif 00191 00193 #define LB_TS_VAR( NAME ) \ 00194 public: \ 00195 struct NAME ## Struct \ 00196 { \ 00197 NAME ## Struct () \ 00198 : extMutex( false ) \ 00199 , inRegion( lunchbox::ThreadID::ZERO ) \ 00200 {} \ 00201 mutable lunchbox::ThreadID id; \ 00202 mutable std::string name; \ 00203 bool extMutex; \ 00204 mutable lunchbox::ThreadID inRegion; \ 00205 } NAME; \ 00206 private: 00207 00208 #ifdef LB_CHECK_THREADSAFETY 00209 # define LB_TS_RESET( NAME ) NAME.id = lunchbox::ThreadID::ZERO; 00210 00211 # define LB_TS_THREAD( NAME ) \ 00212 { \ 00213 if( NAME.id == lunchbox::ThreadID::ZERO ) \ 00214 { \ 00215 NAME.id = lunchbox::Thread::getSelfThreadID(); \ 00216 NAME.name = lunchbox::Log::instance().getThreadName(); \ 00217 LBVERB << "Functions for " << #NAME \ 00218 << " locked to this thread" << std::endl; \ 00219 } \ 00220 if( !NAME.extMutex && NAME.id != lunchbox::Thread::getSelfThreadID( )) \ 00221 { \ 00222 LBERROR << "Threadsafety check for " << #NAME \ 00223 << " failed on object of type " \ 00224 << lunchbox::className( this ) << ", thread " \ 00225 << lunchbox::Thread::getSelfThreadID() << " (" \ 00226 << lunchbox::Log::instance().getThreadName() << ") != " \ 00227 << NAME.id << " (" << NAME.name << ")" << std::endl; \ 00228 LBABORT( "Non-threadsave code called from two threads" ); \ 00229 } \ 00230 } 00231 00232 # define LB_TS_NOT_THREAD( NAME ) \ 00233 { \ 00234 if( !NAME.extMutex && NAME.id != lunchbox::ThreadID::ZERO ) \ 00235 { \ 00236 if( NAME.id == lunchbox::Thread::getSelfThreadID( )) \ 00237 { \ 00238 LBERROR << "Threadsafety check for not " << #NAME \ 00239 << " failed on object of type " \ 00240 << lunchbox::className( this ) << std::endl; \ 00241 LBABORT( "Code called from wrong thread" ); \ 00242 } \ 00243 } \ 00244 } 00245 00247 template< typename T > class ScopedThreadCheck : public NonCopyable 00248 { 00249 public: 00250 explicit ScopedThreadCheck( const T& data ) 00251 : _data( data ) 00252 { 00253 LBASSERTINFO( data.inRegion == lunchbox::ThreadID::ZERO || 00254 data.inRegion == lunchbox::Thread::getSelfThreadID(), 00255 "Another thread already in critical region" ); 00256 data.inRegion = lunchbox::Thread::getSelfThreadID(); 00257 } 00258 00259 ~ScopedThreadCheck() 00260 { 00261 LBASSERTINFO( _data.inRegion == lunchbox::ThreadID::ZERO || 00262 _data.inRegion == lunchbox::Thread::getSelfThreadID(), 00263 "Another thread entered critical region" ); 00264 _data.inRegion = lunchbox::ThreadID::ZERO; 00265 } 00266 private: 00267 const T& _data; 00268 }; 00271 # define LB_TS_SCOPED( NAME ) \ 00272 lunchbox::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME); 00273 00274 #else 00275 # define LB_TS_RESET( NAME ) {} 00276 # define LB_TS_THREAD( NAME ) {} 00277 # define LB_TS_NOT_THREAD( NAME ) {} 00278 # define LB_TS_SCOPED( NAME ) {} 00279 #endif 00280 00281 } 00282 #endif //LUNCHBOX_THREAD_H