Lunchbox  1.4.0
perThread.h
00001 
00002 /* Copyright (c) 2005-2012, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #ifndef LUNCHBOX_PERTHREAD_H
00019 #define LUNCHBOX_PERTHREAD_H
00020 
00021 #include <lunchbox/nonCopyable.h>
00022 
00023 #include <cstdio>
00024 #include <string.h>
00025 
00026 namespace lunchbox
00027 {
00028 namespace detail { class PerThread; }
00029 
00031     template< class T > void perThreadDelete( T* object ) { delete object; }
00032 
00034     template< class T > void perThreadNoDelete( T* object ) {}
00035 
00049     template< class T, void (*D)( T* ) = perThreadDelete< T > >
00050     class PerThread : public NonCopyable
00051     {
00052     public:
00054         PerThread();
00056         ~PerThread();
00057 
00059         PerThread<T, D>& operator = ( const T* data );
00061         PerThread<T, D>& operator = ( const PerThread<T, D>& rhs );
00062 
00064         T* get();
00066         const T* get() const;
00068         T* operator->();
00070         const T* operator->() const;
00071 
00073         T& operator*()
00074             { LBASSERTINFO( get(), className( this )); return *get(); }
00076         const T& operator*() const
00077             { LBASSERTINFO( get(), className( this )); return *get(); }
00078 
00083         bool operator == ( const PerThread& rhs ) const 
00084             { return ( get() == rhs.get( )); }
00085 
00090         bool operator == ( const T* rhs ) const { return ( get()==rhs ); }
00091 
00096         bool operator != ( const T* rhs ) const { return ( get()!=rhs ); }
00097 
00102         bool operator ! () const;
00103 
00108         bool isValid() const;
00109 
00110     private:
00111         detail::PerThread* const _impl;
00112     };
00113 }
00114 
00115 //----------------------------------------------------------------------
00116 // implementation
00117 //----------------------------------------------------------------------
00118 
00119 // Crude test if pthread.h was included
00120 #ifdef PTHREAD_MUTEX_INITIALIZER
00121 #  ifndef HAVE_PTHREAD_H
00122 #    define HAVE_PTHREAD_H
00123 #  endif
00124 #endif
00125 
00126 #ifdef HAVE_PTHREAD_H
00127 
00128 #include <lunchbox/debug.h>
00129 #include <lunchbox/thread.h>
00130 
00131 namespace lunchbox
00132 {
00133 namespace detail
00134 {
00135 class PerThread
00136 {
00137 public:
00138     pthread_key_t key;
00139 };
00140 }
00141 
00142 template< class T, void (*D)( T* ) >
00143 PerThread<T, D>::PerThread() 
00144         : _impl( new detail::PerThread )
00145 {
00146     typedef void (*PThreadDtor_t)(void*);
00147     const int error = pthread_key_create( &_impl->key, (PThreadDtor_t)( D ));
00148     if( error )
00149     {
00150         LBERROR << "Can't create thread-specific key: " 
00151                 << strerror( error ) << std::endl;
00152         LBASSERT( !error );
00153     }
00154 }
00155 
00156 template< class T, void (*D)( T* ) >
00157 PerThread<T, D>::~PerThread()
00158 {
00159     T* object = get();
00160     if( object )
00161         D( object );
00162 
00163     pthread_key_delete( _impl->key );
00164     delete _impl;
00165 }
00166 
00167 template< class T, void (*D)( T* ) >
00168 PerThread<T, D>& PerThread<T, D>::operator = ( const T* data )
00169 { 
00170     pthread_setspecific( _impl->key, static_cast<const void*>( data ));
00171     return *this; 
00172 }
00173 
00174 template< class T, void (*D)( T* ) >
00175 PerThread<T, D>& PerThread<T, D>::operator = ( const PerThread<T, D>& rhs )
00176 { 
00177     pthread_setspecific( _impl->key, pthread_getspecific( rhs._impl->key ));
00178     return *this;
00179 }
00180 
00181 template< class T, void (*D)( T* ) >
00182 T* PerThread<T, D>::get()
00183 {
00184     return static_cast< T* >( pthread_getspecific( _impl->key )); 
00185 }
00186 template< class T, void (*D)( T* ) >
00187 const T* PerThread<T, D>::get() const
00188 {
00189     return static_cast< const T* >( pthread_getspecific( _impl->key )); 
00190 }
00191 
00192 template< class T, void (*D)( T* ) >
00193 T* PerThread<T, D>::operator->() 
00194 {
00195     return static_cast< T* >( pthread_getspecific( _impl->key )); 
00196 }
00197 template< class T, void (*D)( T* ) >
00198 const T* PerThread<T, D>::operator->() const 
00199 { 
00200     return static_cast< const T* >( pthread_getspecific( _impl->key )); 
00201 }
00202 
00203 template< class T, void (*D)( T* ) >
00204 bool PerThread<T, D>::operator ! () const
00205 {
00206     return pthread_getspecific( _impl->key ) == 0;
00207 }
00208 
00209 template< class T, void (*D)( T* ) >
00210 bool PerThread<T, D>::isValid() const
00211 {
00212     return pthread_getspecific( _impl->key ) != 0;
00213 }
00214 
00215 }
00216 #endif // HAVE_PTHREAD_H
00217 #endif //LUNCHBOX_PERTHREAD_H