Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 #ifndef ORO_CORELIB_ATOMIC_QUEUE_HPP
00040 #define ORO_CORELIB_ATOMIC_QUEUE_HPP
00041 
00042 #include "../os/CAS.hpp"
00043 #include <utility>
00044 
00045 namespace RTT
00046 {
00047     namespace internal {
00069     template<class T>
00070     class AtomicQueue
00071     {
00072         const int _size;
00073         typedef T C;
00074         typedef volatile C* CachePtrType;
00075         typedef C* volatile CacheObjType;
00076         typedef C  ValueType;
00077         typedef C* PtrType;
00078 
00079         union SIndexes
00080         {
00081                 unsigned long _value;
00082                 unsigned short _index[2];
00083         };
00084 
00089         CachePtrType  _buf;
00090 
00095         volatile SIndexes _indxes;
00096 
00104         CachePtrType recover_r() const
00105         {
00106             
00107             
00108             
00109             
00110             SIndexes start;
00111             start._value = _indxes._value;
00112             unsigned short r = start._index[1];
00113             while( r != _size) {
00114                 if (_buf[r])
00115                     return &_buf[r];
00116                 ++r;
00117             }
00118             r = 0;
00119             while( r != start._index[1]) {
00120                 if (_buf[r])
00121                     return &_buf[r];
00122                 ++r;
00123             }
00124             return 0;
00125         }
00126 
00131         CachePtrType propose_w()
00132         {
00133                 SIndexes oldval, newval;
00134             do {
00135                 oldval._value = _indxes._value; 
00136                 newval._value = oldval._value; 
00137                 
00138                 if ( (newval._index[0] == newval._index[1] - 1) || (newval._index[0] == newval._index[1] + _size - 1) )
00139                 {
00140                     
00141                     
00142                     return 0;
00143                 }
00144                 ++newval._index[0];
00145                 if ( newval._index[0] == _size )
00146                         newval._index[0] = 0;
00147                 
00148             } while ( !os::CAS( &_indxes._value, oldval._value, newval._value) );
00149 
00150             
00151             return &_buf[ oldval._index[0] ];
00152         }
00157         CachePtrType propose_r()
00158         {
00159                 SIndexes oldval, newval;
00160             do {
00161                 oldval._value = _indxes._value;
00162                 newval._value = oldval._value;
00163                 
00164                 if ( newval._index[0] == newval._index[1] )
00165                 {
00166                     
00167                     
00168                     
00169                     return recover_r();
00170                 }
00171                 ++newval._index[1];
00172                 if ( newval._index[1] == _size )
00173                         newval._index[1] = 0;
00174 
00175             } while ( !os::CAS( &_indxes._value, oldval._value, newval._value) );
00176             
00177             
00178             return &_buf[oldval._index[1] ];
00179         }
00180 
00181         
00182         AtomicQueue( const AtomicQueue<T>& );
00183     public:
00184         typedef unsigned int size_type;
00185 
00190         AtomicQueue( unsigned int size )
00191             : _size(size+1)
00192         {
00193             _buf= new C[_size];
00194             this->clear();
00195         }
00196 
00197         ~AtomicQueue()
00198         {
00199             delete[] _buf;
00200         }
00201 
00206         bool isFull() const
00207         {
00208             
00209             
00210             
00211             SIndexes val;
00212             val._value = _indxes._value;
00213             return val._index[0] == val._index[1] - 1 || val._index[0] == val._index[1] + _size - 1;
00214         }
00215 
00220         bool isEmpty() const
00221         {
00222             
00223             SIndexes val;
00224             val._value = _indxes._value;
00225             return val._index[0] == val._index[1] && recover_r() == 0;
00226         }
00227 
00231         size_type capacity() const
00232         {
00233             return _size -1;
00234         }
00235 
00241         size_type size() const
00242         {
00243             int c = 0, ret = 0;
00244             while (c != _size ) {
00245                 if (_buf[c++] )
00246                     ++ret;
00247             }
00248             return ret;
00249             
00250             
00251         }
00252 
00258         bool enqueue(const T& value)
00259         {
00260             if ( value == 0 )
00261                 return false;
00262             CachePtrType loc;
00263             C null = 0;
00264             do {
00265                 loc = propose_w();
00266                 if ( loc == 0 )
00267                     return false; 
00268                 
00269             } while( !os::CAS(loc, null, value));
00270             return true;
00271         }
00272 
00278         bool dequeue( T& result )
00279         {
00280             CachePtrType loc;
00281             C null = 0;
00282             do {
00283                 loc = propose_r();
00284                 if ( loc == 0 )
00285                     return false; 
00286                 result = *loc;
00287                 
00288             } while( result == 0 || !os::CAS(loc, result, null) );
00289             assert(result);
00290             return true;
00291         }
00292 
00296         const T front() const
00297         {
00298             return _buf[_indxes._index[1] ];
00299         }
00300 
00304         void clear()
00305         {
00306             for(int i = 0 ; i != _size; ++i) {
00307                 _buf[i] = 0;
00308             }
00309             _indxes._value = 0;
00310         }
00311 
00312     };
00313 
00314 }}
00315 
00316 #endif