Equalizer  1.2.1
spinLock.h
00001 
00002 /* Copyright (c) 2010, 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 COBASE_SPINLOCK_H
00019 #define COBASE_SPINLOCK_H
00020 
00021 #include <co/base/atomic.h>         // member
00022 #include <co/base/nonCopyable.h>    // base class
00023 #include <co/base/thread.h>         // used in inline method
00024 
00025 namespace co
00026 {
00027 namespace base
00028 {
00038     class SpinLock : public NonCopyable
00039     {
00040         static const long _writelocked = -1;
00041         static const long _unlocked = 0;
00042 
00043     public:
00045         SpinLock() : _state( _unlocked ) {}
00046 
00048         ~SpinLock() { _state = _unlocked; }
00049 
00051         void set()
00052             {
00053                 while( true )
00054                 {
00055                     if( trySet( ))
00056                         return;
00057                     Thread::yield();
00058                 }
00059             }
00060 
00062         void unset()
00063             {
00064                 EQASSERT( _state == _writelocked );
00065                 _state = _unlocked;
00066             }
00067 
00075         bool trySet()
00076             {
00077                 if( !_state.compareAndSwap( _unlocked, _writelocked ))
00078                     return false;
00079                 EQASSERTINFO( isSetWrite(), _state );
00080                 return true;
00081             }
00082 
00084         void setRead()
00085             {
00086                 while( true )
00087                 {
00088                     if( trySetRead( ))
00089                         return;
00090                     Thread::yield();
00091                 }
00092             }
00093 
00095         void unsetRead()
00096             {
00097                 while( true )
00098                 {
00099                     EQASSERT( _state > _unlocked );
00100                     memoryBarrier();
00101                     const int32_t expected = _state;
00102                     if( _state.compareAndSwap( expected, expected-1 ))
00103                         return;
00104                 }
00105             }
00106 
00114         bool trySetRead()
00115             {
00116                 memoryBarrier();
00117                 const int32_t state = _state;
00118                 // Note: 0 used here since using _unlocked unexplicably gives
00119                 //       'undefined reference to co::base::SpinLock::_unlocked'
00120                 const int32_t expected = (state==_writelocked) ? 0 : state;
00121 
00122                 if( !_state.compareAndSwap( expected, expected+1 ))
00123                     return false;
00124 
00125                 EQASSERTINFO( isSetRead(), _state << ", " << expected );
00126                 return true;
00127             }
00128 
00136         bool isSet() { return ( _state != _unlocked ); }
00137 
00144         bool isSetWrite() { return ( _state == _writelocked ); }
00145 
00152         bool isSetRead() { return ( _state > _unlocked ); }
00153 
00154     private:
00155         a_int32_t _state;
00156     };
00157 }
00158 
00159 }
00160 #endif //COBASE_SPINLOCK_H
Generated on Fri Jun 8 2012 15:44:32 for Equalizer 1.2.1 by  doxygen 1.8.0