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