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