00001 /* 00002 wefts_ringbuffer.h 00003 Ringbuffer sync object 00004 00005 $Id: wefts_ringbuffer.h,v 1.3 2004/03/10 14:57:04 jonnymind Exp $ 00006 --------------------------------------------- 00007 Begin : 2003-08-16 21:25 00008 Author : Giancarlo Niccolai 00009 00010 Last modified because: 00011 00012 */ 00013 00014 /************************************************************************** 00015 * This program is free software; you can redistribute it and/or modify * 00016 * it under the terms of the GNU Library General Public License as * 00017 * published by the Free Software Foundation; either version 2.1 of the * 00018 * License, or (at your option) any later version. * 00019 ***************************************************************************/ 00020 00021 #ifndef WT_RINGBUFFER_H 00022 #define WT_RINGBUFFER_H 00023 00024 #include <wefts_mutex.h> 00025 #include <wefts_cond.h> 00026 #include <wefts_cleanup.h> 00027 #include <iostream> 00028 00029 namespace Wefts { 00030 00095 template < typename _T > 00096 class RingBuffer: public CleanupHandler 00097 { 00098 private: 00099 Mutex m_mutex; 00100 Condition m_rCond; 00101 Condition m_wCond; 00102 00104 _T *m_buffer; 00105 00107 unsigned long m_size; 00108 00110 unsigned long m_wPos; 00112 unsigned long m_rPos; 00113 00115 int m_wWaiting; 00117 int m_rWaiting; 00118 00124 bool empty() const { 00125 return ( m_wPos == m_rPos + 1|| 00126 (m_size > 1 &&m_wPos == 0 && m_rPos == m_size-1) ); 00127 } 00128 00134 bool full() const { 00135 return (m_wPos == m_rPos); 00136 } 00137 00143 void put( _T data ) { 00144 00145 bool was_empty = empty(); 00146 if ( m_size == 1 ) { 00147 *m_buffer = data; 00148 m_wPos = 0; 00149 } 00150 else { 00151 m_buffer[ m_wPos ++ ] = data; 00152 if ( m_wPos == m_size ) m_wPos = 0; 00153 } 00154 00155 if( was_empty && m_rWaiting != 0 ) 00156 m_rCond.signal(); // tell the readers situation has changed. 00157 } 00158 00159 00164 _T get() { 00165 bool was_full = full(); 00166 00167 if ( m_rPos == m_size -1) 00168 m_rPos = 0; 00169 else 00170 m_rPos++; 00171 00172 if( was_full && m_wWaiting != 0 ) { 00173 m_wCond.signal(); 00174 } 00175 if ( m_size == 1 ) m_wPos = 1; 00176 00177 return m_buffer[ m_rPos ]; 00178 } 00179 00180 00181 public: 00182 00189 RingBuffer ( const unsigned long size ) throw( InitError ) 00190 { 00191 if ( size == 0 ) throw InitError(); 00192 m_buffer = new _T[ size ]; 00193 if ( m_buffer == 0 ) throw InitError(); 00194 00195 m_size = size; 00196 00197 m_wPos = 1; 00198 m_rPos = 0; 00199 m_wWaiting = 0; 00200 m_rWaiting = 0; 00201 00202 m_wCond.setMutex( &m_mutex ); 00203 m_rCond.setMutex( &m_mutex ); 00204 } 00205 00206 ~RingBuffer() { delete m_buffer; } 00207 00209 unsigned long size() const { m_size; } 00210 00222 unsigned long free() { 00223 unsigned long ret; 00224 00225 m_mutex.lock(); 00226 if ( m_wPos > m_rPos ) 00227 m_ret = m_size -m_wPos + m_rPos + 1; 00228 else 00229 m_ret = m_rPos - m_wPos; 00230 m_mutex.unlock(); 00231 00232 return ret; 00233 } 00234 00236 void write( _T data ) 00237 { 00238 m_mutex.lock(); 00239 00240 // have we to wait? 00241 if( full() ) { 00242 m_wWaiting++; 00243 while ( full() ) { 00244 // position == 0 --> cleanup a writer 00245 m_wCond.wait( this, 0 ); 00246 } 00247 m_wWaiting--; 00248 } 00249 put( data ); 00250 00251 m_mutex.unlock(); 00252 } 00253 00254 /* Waits until some data may be read and returns the read data. */ 00255 _T read() 00256 { 00257 m_mutex.lock(); 00258 00259 // have we to wait? 00260 if( empty() ) { 00261 m_rWaiting++; 00262 while ( empty() ) { 00263 // position == 1 --> cleanup a reader 00264 m_rCond.wait( this, 1 ); 00265 } 00266 m_rWaiting--; 00267 } 00268 _T data = get(); 00269 m_mutex.unlock(); 00270 return data; 00271 } 00272 00273 00277 bool tryWrite( _T data ) { 00278 bool ret; 00279 00280 m_mutex.lock(); 00281 if ( ! full() ) { 00282 put( data ); 00283 ret = true; 00284 } 00285 else 00286 ret = false; 00287 m_mutex.unlock(); 00288 00289 return ret; 00290 } 00291 00297 bool tryRead( _T &data ) { 00298 bool ret; 00299 00300 m_mutex.lock(); 00301 if ( ! empty() ) { 00302 data = get(); 00303 ret = true; 00304 } 00305 else 00306 ret = false; 00307 m_mutex.unlock(); 00308 00309 return ret; 00310 } 00311 00313 virtual void handleCleanup( int pos, void * ) 00314 { 00315 if ( pos == 0 ) 00316 // cleanup a writer 00317 m_wWaiting--; 00318 else 00319 // cleanup a reader 00320 m_rWaiting--; 00321 00322 m_mutex.unlock(); 00323 } 00324 }; 00325 00326 } 00327 #endif 00328 00329 /* end wefts_ringbuffer.h */