|
Equalizer
1.3.1-git
|
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 CORE = 1, 00042 SOCKET = -65536, 00043 SOCKET_MAX = -1024 00044 }; 00045 00047 LUNCHBOX_API Thread(); 00048 00050 LUNCHBOX_API Thread( const Thread& from ); 00051 00053 LUNCHBOX_API virtual ~Thread(); 00054 00063 LUNCHBOX_API virtual bool start(); 00064 00076 virtual bool init(){ return true; } 00077 00086 virtual void run() = 0; 00087 00096 LUNCHBOX_API virtual void exit(); 00097 00104 LUNCHBOX_API void cancel(); 00105 00112 LUNCHBOX_API bool join(); 00113 00123 LUNCHBOX_API bool isStopped() const; 00124 00134 LUNCHBOX_API bool isRunning() const; 00135 00141 LUNCHBOX_API bool isCurrent() const; 00142 00144 LUNCHBOX_API static ThreadID getSelfThreadID(); 00145 00147 LUNCHBOX_API static void yield(); 00148 00150 static void pinCurrentThread(); 00151 00153 LUNCHBOX_API static void setName( const std::string& name ); 00154 00165 LUNCHBOX_API static void setAffinity( const int32_t affinity ); 00166 00167 private: 00168 detail::Thread* const _impl; 00169 00170 static void* runChild( void* arg ); 00171 void _runChild(); 00172 00173 void _installCleanupHandler(); 00174 00175 static void _notifyStarted(); 00176 static void _notifyStopping(); 00177 friend void _notifyStopping( void* ); 00178 }; 00179 00180 // thread-safety checks 00181 // These checks are for development purposes, to check that certain objects are 00182 // properly used within the framework. Leaving them enabled during application 00183 // development may cause false positives, e.g., when threadsafety is ensured 00184 // outside of the objects by the application. 00185 00186 #ifndef NDEBUG 00187 # define LB_CHECK_THREADSAFETY 00188 #endif 00189 00191 #define LB_TS_VAR( NAME ) \ 00192 public: \ 00193 struct NAME ## Struct \ 00194 { \ 00195 NAME ## Struct () \ 00196 : extMutex( false ) \ 00197 , inRegion( lunchbox::ThreadID::ZERO ) \ 00198 {} \ 00199 mutable lunchbox::ThreadID id; \ 00200 mutable std::string name; \ 00201 bool extMutex; \ 00202 mutable lunchbox::ThreadID inRegion; \ 00203 } NAME; \ 00204 private: 00205 00206 #ifdef LB_CHECK_THREADSAFETY 00207 # define LB_TS_RESET( NAME ) NAME.id = lunchbox::ThreadID::ZERO; 00208 00209 # define LB_TS_THREAD( NAME ) \ 00210 { \ 00211 if( NAME.id == lunchbox::ThreadID::ZERO ) \ 00212 { \ 00213 NAME.id = lunchbox::Thread::getSelfThreadID(); \ 00214 NAME.name = lunchbox::Log::instance().getThreadName(); \ 00215 LBVERB << "Functions for " << #NAME \ 00216 << " locked to this thread" << std::endl; \ 00217 } \ 00218 if( !NAME.extMutex && NAME.id != lunchbox::Thread::getSelfThreadID( )) \ 00219 { \ 00220 LBERROR << "Threadsafety check for " << #NAME \ 00221 << " failed on object of type " \ 00222 << lunchbox::className( this ) << ", thread " \ 00223 << lunchbox::Thread::getSelfThreadID() << " (" \ 00224 << lunchbox::Log::instance().getThreadName() << ") != " \ 00225 << NAME.id << " (" << NAME.name << ")" << std::endl; \ 00226 LBABORT( "Non-threadsave code called from two threads" ); \ 00227 } \ 00228 } 00229 00230 # define LB_TS_NOT_THREAD( NAME ) \ 00231 { \ 00232 if( !NAME.extMutex && NAME.id != lunchbox::ThreadID::ZERO ) \ 00233 { \ 00234 if( NAME.id == lunchbox::Thread::getSelfThreadID( )) \ 00235 { \ 00236 LBERROR << "Threadsafety check for not " << #NAME \ 00237 << " failed on object of type " \ 00238 << lunchbox::className( this ) << std::endl; \ 00239 LBABORT( "Code called from wrong thread" ); \ 00240 } \ 00241 } \ 00242 } 00243 00245 template< typename T > class ScopedThreadCheck : public NonCopyable 00246 { 00247 public: 00248 explicit ScopedThreadCheck( const T& data ) 00249 : _data( data ) 00250 { 00251 LBASSERTINFO( data.inRegion == lunchbox::ThreadID::ZERO || 00252 data.inRegion == lunchbox::Thread::getSelfThreadID(), 00253 "Another thread already in critical region" ); 00254 data.inRegion = lunchbox::Thread::getSelfThreadID(); 00255 } 00256 00257 ~ScopedThreadCheck() 00258 { 00259 LBASSERTINFO( _data.inRegion == lunchbox::ThreadID::ZERO || 00260 _data.inRegion == lunchbox::Thread::getSelfThreadID(), 00261 "Another thread entered critical region" ); 00262 _data.inRegion = lunchbox::ThreadID::ZERO; 00263 } 00264 private: 00265 const T& _data; 00266 }; 00269 # define LB_TS_SCOPED( NAME ) \ 00270 lunchbox::ScopedThreadCheck< NAME ## Struct > scoped ## NAME ## Check(NAME); 00271 00272 #else 00273 # define LB_TS_RESET( NAME ) {} 00274 # define LB_TS_THREAD( NAME ) {} 00275 # define LB_TS_NOT_THREAD( NAME ) {} 00276 # define LB_TS_SCOPED( NAME ) {} 00277 #endif 00278 00279 } 00280 #endif //LUNCHBOX_THREAD_H
1.3.1-git by
1.8.0