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