00001 /* 00002 wefts_ringbuffer.h 00003 Ringbuffer sync object 00004 00005 $Id: wefts_ringbuffer.h,v 1.1 2003/08/17 01:15:19 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 m_wCond.onStop( this, 0 ); // 0 == cleanup a writer 00206 m_rCond.onStop( this, 1 ); // 1 == cleanup a reader 00207 } 00208 00209 ~RingBuffer() { delete m_buffer; } 00210 00212 unsigned long size() const { m_size; } 00213 00225 unsigned long free() { 00226 unsigned long ret; 00227 00228 m_mutex.lock(); 00229 if ( m_wPos > m_rPos ) 00230 m_ret = m_size -m_wPos + m_rPos + 1; 00231 else 00232 m_ret = m_rPos - m_wPos; 00233 m_mutex.unlock(); 00234 00235 return ret; 00236 } 00237 00239 void write( _T data ) 00240 { 00241 m_mutex.lock(); 00242 00243 // have we to wait? 00244 if( full() ) { 00245 m_wWaiting++; 00246 while ( full() ) { 00247 m_wCond.wait(); 00248 } 00249 m_wWaiting--; 00250 } 00251 put( data ); 00252 00253 m_mutex.unlock(); 00254 } 00255 00256 /* Waits until some data may be read and returns the read data. */ 00257 _T read() 00258 { 00259 m_mutex.lock(); 00260 00261 // have we to wait? 00262 if( empty() ) { 00263 m_rWaiting++; 00264 while ( empty() ) { 00265 m_rCond.wait(); 00266 } 00267 m_rWaiting--; 00268 } 00269 _T data = get(); 00270 m_mutex.unlock(); 00271 return data; 00272 } 00273 00274 00278 bool tryWrite( _T data ) { 00279 bool ret; 00280 00281 m_mutex.lock(); 00282 if ( ! full() ) { 00283 put( data ); 00284 ret = true; 00285 } 00286 else 00287 ret = false; 00288 m_mutex.unlock(); 00289 00290 return ret; 00291 } 00292 00298 bool tryRead( _T &data ) { 00299 bool ret; 00300 00301 m_mutex.lock(); 00302 if ( ! empty() ) { 00303 data = get(); 00304 ret = true; 00305 } 00306 else 00307 ret = false; 00308 m_mutex.unlock(); 00309 00310 return ret; 00311 } 00312 00314 void handleCleanup( int pos ) 00315 { 00316 if ( pos == 0 ) // cleanup a writer 00317 m_wWaiting--; 00318 else 00319 m_rWaiting--; 00320 00321 m_mutex.unlock(); 00322 } 00323 }; 00324 00325 } 00326 #endif 00327 00328 /* end wefts_ringbuffer.h */