Lunchbox  1.6.0
thread.h
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