Back to index

lightning-sunbird  0.9+nobinonly
GUSIBuffer.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSIBuffer.nw        -      Buffering for GUSI                           
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSIBuffer.h,v $
00008 // % Revision 1.1  2001/03/11 22:33:31  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                               
00011 // % Revision 1.20  2001/01/17 08:33:14  neeri                             
00012 // % Need to set fOldBuffer to nil after deleting                          
00013 // %                                                                       
00014 // % Revision 1.19  2000/10/16 04:34:22  neeri                             
00015 // % Releasing 2.1.2                                                       
00016 // %                                                                       
00017 // % Revision 1.18  2000/05/23 06:53:14  neeri                             
00018 // % Improve formatting                                                    
00019 // %                                                                       
00020 // % Revision 1.17  2000/03/15 07:22:06  neeri                             
00021 // % Enforce alignment choices                                             
00022 // %                                                                       
00023 // % Revision 1.16  1999/09/09 07:19:18  neeri                             
00024 // % Fix read-ahead switch-off                                             
00025 // %                                                                       
00026 // % Revision 1.15  1999/08/26 05:44:59  neeri                             
00027 // % Fixes for literate edition of source code                             
00028 // %                                                                       
00029 // % Revision 1.14  1999/06/30 07:42:05  neeri                             
00030 // % Getting ready to release 2.0b3                                        
00031 // %                                                                       
00032 // % Revision 1.13  1999/05/30 03:09:29  neeri                             
00033 // % Added support for MPW compilers                                       
00034 // %                                                                       
00035 // % Revision 1.12  1999/03/17 09:05:05  neeri                             
00036 // % Added GUSITimer, expanded docs                                        
00037 // %                                                                       
00038 // % Revision 1.11  1998/11/22 23:06:50  neeri                             
00039 // % Releasing 2.0a4 in a hurry                                            
00040 // %                                                                       
00041 // % Revision 1.10  1998/10/25 11:28:43  neeri                             
00042 // % Added MSG_PEEK support, recursive locks.                              
00043 // %                                                                       
00044 // % Revision 1.9  1998/08/02 12:31:36  neeri                              
00045 // % Another typo                                                          
00046 // %                                                                       
00047 // % Revision 1.8  1998/08/02 11:20:06  neeri                              
00048 // % Fixed some typos                                                      
00049 // %                                                                       
00050 // % Revision 1.7  1998/01/25 20:53:51  neeri                              
00051 // % Engine implemented, except for signals & scheduling                   
00052 // %                                                                       
00053 // % Revision 1.6  1997/11/13 21:12:08  neeri                              
00054 // % Fall 1997                                                             
00055 // %                                                                       
00056 // % Revision 1.5  1996/12/22 19:57:55  neeri                              
00057 // % TCP streams work                                                      
00058 // %                                                                       
00059 // % Revision 1.4  1996/12/16 02:16:02  neeri                              
00060 // % Add Size(), make inlines inline, use BlockMoveData                    
00061 // %                                                                       
00062 // % Revision 1.3  1996/11/24  13:00:26  neeri                             
00063 // % Fix comment leaders                                                   
00064 // %                                                                       
00065 // % Revision 1.2  1996/11/24  12:52:05  neeri                             
00066 // % Added GUSIPipeSockets                                                 
00067 // %                                                                       
00068 // % Revision 1.1.1.1  1996/11/03  02:43:32  neeri                         
00069 // % Imported into CVS                                                     
00070 // %                                                                       
00071 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00072 //                                                                         
00073 // \chapter{Buffering for GUSI}                                            
00074 //                                                                         
00075 // This section defines four classes that handle buffering for GUSI:       
00076 // [[GUSIScatterer]], [[GUSIGatherer]], and their common ancestor          
00077 // [[GUSIScattGath]] convert between [[iovecs]] and simple buffers in the  
00078 // absence of specialized communications routines. A [[GUSIRingBuffer]]    
00079 // mediates between a producer and a consumer, one of which is typically   
00080 // normal code and the other interrupt level code.                         
00081 //                                                                         
00082 //                                                                         
00083 // <GUSIBuffer.h>=                                                         
00084 #ifndef _GUSIBuffer_
00085 #define _GUSIBuffer_
00086 
00087 #ifdef GUSI_SOURCE
00088 
00089 #include <sys/types.h>
00090 #include <sys/uio.h>
00091 
00092 #include <MacTypes.h>
00093 
00094 #include "GUSIDiag.h"
00095 #include "GUSIBasics.h"
00096 
00097 #include <ConditionalMacros.h>
00098 
00099 #if PRAGMA_STRUCT_ALIGN
00100 #pragma options align=native
00101 #endif
00102 
00103 // \section{Definition of scattering/gathering}                            
00104 //                                                                         
00105 // A [[GUSIScattGath]] translates between an array of [[iovecs]] and a simple buffer,
00106 // allocating scratch space if necessary.                                  
00107 //                                                                         
00108 // <Definition of class [[GUSIScattGath]]>=                                
00109 class GUSIScattGath  {
00110 protected:
00111        // On constructing a [[GUSIScattGath]], we pass an array of [[iovecs]]. For the
00112  // simpler functions, a variant with a single [[buffer]] and [[length]] is also
00113  // available.                                                              
00114  //                                                                         
00115  // <Constructor and destructor for [[GUSIScattGath]]>=                     
00116  GUSIScattGath(const iovec *iov, int count, bool gather);
00117  GUSIScattGath(void * buffer, size_t length, bool gather);
00118  virtual ~GUSIScattGath();
00119 public:
00120        // The [[iovec]], the buffer and its length are then available for public scrutinity.
00121  // Copy constructor and assignment both are a bit nontrivial.              
00122  //                                                                         
00123  // <Public interface to [[GUSIScattGath]]>=                                
00124  const iovec *       IOVec()  const;
00125  int                        Count()  const;
00126  void *                     Buffer() const;
00127  operator            void *() const;
00128  int                        Length() const;
00129  int                        SetLength(int len) const;
00130  void                operator=(const GUSIScattGath & other);
00131  GUSIScattGath(const GUSIScattGath & other);
00132 private:
00133        // \section{Implementation of scattering/gathering}                        
00134  //                                                                         
00135  // A [[GUSIScattGath]] always consists of [[fIo]], an array of [[iovecs]], [[fCount]],
00136  // the number of sections in the array, and [[fLen]], the total size of the data area.
00137  // If [[fCount]] is 1, [[fBuf]] will be a copy of the pointer to the single section. If 
00138  // [[fCount]] is greater than 1, [[fScratch]] will contain a [[Handle]] to a scratch 
00139  // area of size [[len]] and [[fBuf]] will contain [[*scratch]]. If the object was
00140  // constructed without providing an [[iovec]] array, [[fTrivialIo]] will be set up
00141  // to hold one.                                                            
00142  //                                                                         
00143  // <Privatissima of [[GUSIScattGath]]>=                                    
00144  const iovec *       fIo;
00145  iovec               fTrivialIo;          
00146  mutable int         fCount;
00147  mutable Handle      fScratch;
00148  mutable void *      fBuf;
00149  mutable int         fLen;
00150  bool                fGather;
00151 };
00152 // A [[GUSIScatterer]] distributes the contents of a buffer over an array of
00153 // [[iovecs]].                                                             
00154 //                                                                         
00155 // <Definition of class [[GUSIScatterer]]>=                                
00156 class GUSIScatterer : public GUSIScattGath {
00157 public:
00158        GUSIScatterer(const iovec *iov, int count) 
00159               : GUSIScattGath(iov, count, false) {}
00160        GUSIScatterer(void * buffer, size_t length) 
00161               : GUSIScattGath(buffer, length, false) {}
00162               
00163        GUSIScatterer & operator=(const GUSIScatterer & other)
00164               { *static_cast<GUSIScattGath *>(this) = other; return *this; }
00165 };
00166 // A [[GUSIGatherer]] collects the contents of an array of [[iovecs]] into a single
00167 // buffer.                                                                 
00168 //                                                                         
00169 // <Definition of class [[GUSIGatherer]]>=                                 
00170 class GUSIGatherer : public GUSIScattGath {
00171 public:
00172        GUSIGatherer(const struct iovec *iov, int count)
00173               : GUSIScattGath(iov, count, true) {}
00174        GUSIGatherer(const void * buffer, size_t length)
00175               : GUSIScattGath(const_cast<void *>(buffer), length, true) {}
00176               
00177        GUSIGatherer & operator=(const GUSIGatherer & other)
00178               { *static_cast<GUSIScattGath *>(this) = other; return *this; }
00179 };
00180 
00181 // \section{Definition of ring buffering}                                  
00182 //                                                                         
00183 // A [[GUSIRingBuffer]] typically has on one side a non-preeemptive piece of code
00184 // and on the other side a piece of interrupt code. To transfer data from and to
00185 // the buffer, two interfaces are available: A direct interface that transfers 
00186 // memory, and an indirect interface that allocates memory regions and then
00187 // has OS routines transfer data from or to them                           
00188 //                                                                         
00189 // <Definition of class [[GUSIRingBuffer]]>=                               
00190 class GUSIRingBuffer {
00191 public:
00192        // On construction of a [[GUSIRingBuffer]], a buffer of the specified size is 
00193  // allocated and not released until destruction. [[operator void*]] may be used
00194  // to determine whether construction was successful.                       
00195  //                                                                         
00196  // <Constructor and destructor for [[GUSIRingBuffer]]>=                    
00197  GUSIRingBuffer(size_t bufsiz);
00198  ~GUSIRingBuffer();
00199  operator void*();
00200        // The direct interface to [[GUSIRingBuffer]] is straightforward: [[Produce]] copies
00201  // memory into the buffer, [[Consume]] copies memory from the buffer, [[Free]]
00202  // determines how much space there is for [[Produce]] and [[Valid]] determines
00203  // how much space there is for [[Consume]].                                
00204  //                                                                         
00205  // <Direct interface for [[GUSIRingBuffer]]>=                              
00206  void  Produce(void * from, size_t & len);
00207  void  Produce(const GUSIGatherer & gather, size_t & len, size_t & offset);
00208  void  Produce(const GUSIGatherer & gather, size_t & len);
00209  void  Consume(void * to, size_t & len);
00210  void  Consume(const GUSIScatterer & scatter, size_t & len, size_t & offset);
00211  void  Consume(const GUSIScatterer & scatter, size_t & len);
00212  size_t       Free();       
00213  size_t       Valid();
00214        // [[ProduceBuffer]] tries to find in the ring buffer a contiguous free block of
00215  // memory of the specified size [[len]] or otherwise the biggest available free 
00216  // block, returns a pointer to it and sets [[len]] to its length. [[ValidBuffer]]
00217  // specifies that the next [[len]] bytes of the ring buffer now contain valid data.
00218  //                                                                         
00219  // [[ConsumeBuffer]] returns a pointer to the next valid byte and sets [[len]] to 
00220  // the minimum of the number of contiguous valid bytes and the value of len on 
00221  // entry. [[FreeBuffer]] specifies that the next [[len]] bytes of the ring 
00222  // buffer were consumed and are no longer needed.                          
00223  //                                                                         
00224  // <Indirect interface for [[GUSIRingBuffer]]>=                            
00225  void *       ProduceBuffer(size_t & len);
00226  void *       ConsumeBuffer(size_t & len);
00227  void  ValidBuffer(void * buffer, size_t len);
00228  void  FreeBuffer(void * buffer, size_t len);
00229        // Before the nonpreemptive partner changes any of the buffer's data structures,
00230  // the [[GUSIRingBuffer]] member functions call [[Lock]], and after the change is
00231  // complete, they call [[Release]]. An interrupt level piece of code before 
00232  // changing any data structures has to determine whether the buffer is locked by
00233  // calling [[Locked]]. If the buffer is locked or otherwise in an unsuitable state,
00234  // the code can specify a procedure to be called during the next [[Release]] by 
00235  // calling [[Defer]]. A deferred procedure should call [[ClearDefer]] to avoid
00236  // getting activated again at the next opportunity.                        
00237  //                                                                         
00238  // <Synchronization support for [[GUSIRingBuffer]]>=                       
00239  void         Lock();
00240  void         Release();
00241  bool         Locked();
00242  typedef void (*Deferred)(void *);
00243  void         Defer(Deferred def, void * ar);
00244  void         ClearDefer();
00245        // It is possible to switch buffer sizes during the existence of a buffer, but we
00246  // have to be somewhat careful, since some asynchronous call may still be writing
00247  // into the old buffer. [[PurgeBuffers]], called at safe times, cleans up old
00248  // buffers.                                                                
00249  //                                                                         
00250  // <Buffer switching for [[GUSIRingBuffer]]>=                              
00251  void         SwitchBuffer(size_t bufsiz);
00252  size_t              Size();
00253  void         PurgeBuffers();
00254        // Sometimes, it's necessary to do nondestructive reads, a task complex enough to
00255  // warrant its own class.                                                  
00256  //                                                                         
00257  // <Definition of class [[GUSIRingBuffer::Peeker]]>=                       
00258  class Peeker {
00259  public:
00260        Peeker(GUSIRingBuffer & buffer);
00261        ~Peeker();
00262        
00263        void   Peek(void * to, size_t & len);
00264        void   Peek(const GUSIScatterer & scatter, size_t & len);
00265  private:
00266        // A [[GUSIRingBuffer::Peeker]] has to keep its associated [[GUSIRingBuffer]] locked during
00267   // its entire existence.                                                   
00268   //                                                                         
00269   // <Privatissima of [[GUSIRingBuffer::Peeker]]>=                           
00270   GUSIRingBuffer &   fTopBuffer;
00271   GUSIRingBuffer *   fCurBuffer;
00272   Ptr                              fPeek;
00273   // The core routine for reading is [[PeekBuffer]] which automatically advances the
00274   // peeker as well.                                                         
00275   //                                                                         
00276   // <Privatissima of [[GUSIRingBuffer::Peeker]]>=                           
00277   void *      PeekBuffer(size_t & len);
00278  };
00279  friend class Peeker;
00280 
00281  void  Peek(void * to, size_t & len);
00282  void  Peek(const GUSIScatterer & scatter, size_t & len);
00283 private:
00284        // \section{Implementation of ring buffering}                              
00285  //                                                                         
00286  // The buffer area of a ring buffer extends between [[fBuffer]] and [[fEnd]]. [[fValid]] 
00287  // contains the number of valid bytes, while [[fFree]] and [[fSpare]] (Whose purpose
00288  // will be explained later) sum up to the number of free bytes. [[fProduce]] points at the 
00289  // next free byte, while [[fConsume]] points at the next valid byte. [[fInUse]] 
00290  // indicates that an asynchronous call might be writing into the buffer.   
00291  //                                                                         
00292  // <Privatissima of [[GUSIRingBuffer]]>=                                   
00293  Ptr          fBuffer;
00294  Ptr          fEnd;
00295  Ptr   fConsume;
00296  Ptr          fProduce;
00297  size_t       fFree;
00298  size_t       fValid;
00299  size_t       fSpare;
00300  bool  fInUse;
00301  // The relationships between the various pointers are captured by [[Invariant]] which
00302  // uses the auxiliary function [[Distance]] to determine the distance between two
00303  // pointers in the presence of wrap around areas.                          
00304  //                                                                         
00305  // <Privatissima of [[GUSIRingBuffer]]>=                                   
00306  bool  Invariant();
00307  size_t       Distance(Ptr from, Ptr to);
00308  // The lock mechanism relies on [[fLocked]], and the deferred procedure and its argument
00309  // are stored in [[fDeferred]] and [[fDeferredArg]].                       
00310  //                                                                         
00311  // <Privatissima of [[GUSIRingBuffer]]>=                                   
00312  int                 fLocked;
00313  Deferred     fDeferred;
00314  void *              fDeferredArg;
00315  // We only switch the next time the buffer is empty, so we are prepared to create
00316  // the new buffer dynamically and forward requests to it for a while.      
00317  //                                                                         
00318  // <Privatissima of [[GUSIRingBuffer]]>=                                   
00319  GUSIRingBuffer *    fNewBuffer;
00320  GUSIRingBuffer *    fOldBuffer;
00321  void                       ObsoleteBuffer();
00322  // The scatter/gather variants of [[Produce]] and [[Consume]] rely on a common
00323  // strategy.                                                               
00324  //                                                                         
00325  // <Privatissima of [[GUSIRingBuffer]]>=                                   
00326  void IterateIOVec(const GUSIScattGath & sg, size_t & len, size_t & offset, bool produce);
00327 };
00328 
00329 #if PRAGMA_STRUCT_ALIGN
00330 #pragma options align=reset
00331 #endif
00332 
00333 // Clients need readonly access to the buffer address and read/write access to the length.
00334 // [[operator void*]] server to check whether the [[GUSIScattGath]] was constructed 
00335 // successfully.                                                           
00336 //                                                                         
00337 // <Inline member functions for class [[GUSIScattGath]]>=                  
00338 inline const iovec * GUSIScattGath::IOVec()       const        
00339        {      return fIo;          }
00340 inline int                   GUSIScattGath::Count()      const        
00341        {      return fCount;              }
00342 inline               GUSIScattGath::operator  void *() const
00343        {      return Buffer();     }
00344 inline int                   GUSIScattGath::Length() const            
00345        {      return fLen;         }
00346 inline int                   GUSIScattGath::SetLength(int len) const
00347        {      return GUSI_MUTABLE(GUSIScattGath, fLen) = len;  }
00348 // <Inline member functions for class [[GUSIRingBuffer]]>=                 
00349 inline void GUSIRingBuffer::Produce(const GUSIGatherer & gather, size_t & len, size_t & offset)
00350 {
00351        IterateIOVec(gather, len, offset, true);
00352 }
00353 
00354 inline void GUSIRingBuffer::Consume(const GUSIScatterer & scatter, size_t & len, size_t & offset)
00355 {
00356        IterateIOVec(scatter, len, offset, false);
00357 }
00358 
00359 inline void GUSIRingBuffer::Produce(const GUSIGatherer & gather, size_t & len)
00360 {
00361        size_t offset = 0;
00362        
00363        IterateIOVec(gather, len, offset, true);
00364 }
00365 
00366 inline void GUSIRingBuffer::Consume(const GUSIScatterer & scatter, size_t & len)
00367 {
00368        size_t offset = 0;
00369        
00370        IterateIOVec(scatter, len, offset, false);
00371 }
00372 // The lock support is rather straightforward.                             
00373 //                                                                         
00374 // <Inline member functions for class [[GUSIRingBuffer]]>=                 
00375 inline void   GUSIRingBuffer::Lock()                    {      ++fLocked;                         }
00376 inline bool          GUSIRingBuffer::Locked()           {      return (fLocked!=0); }
00377 inline void          GUSIRingBuffer::ClearDefer()       {      fDeferred     =      nil;   }
00378 inline void   GUSIRingBuffer::Release()          
00379 { 
00380        GUSI_CASSERT_INTERNAL(fLocked > 0);
00381        if (--fLocked <= 0 && fDeferred)
00382               fDeferred(fDeferredArg);
00383 }
00384 inline void          GUSIRingBuffer::Defer(Deferred def, void * ar)
00385 {
00386        fDeferred            =      def;
00387        fDeferredArg  =      ar;
00388 }
00389 // The size is stored only implicitely.                                    
00390 //                                                                         
00391 // <Inline member functions for class [[GUSIRingBuffer]]>=                 
00392 inline size_t GUSIRingBuffer::Size()                           {      return fEnd - fBuffer;      }
00393 // <Inline member functions for class [[GUSIRingBuffer]]>=                 
00394 inline void GUSIRingBuffer::Peek(void * to, size_t & len)
00395 {
00396        Peeker peeker(*this);
00397        
00398        peeker.Peek(to, len);
00399 }
00400 
00401 inline void GUSIRingBuffer::Peek(const GUSIScatterer & scatter, size_t & len)
00402 {
00403        Peeker peeker(*this);
00404        
00405        peeker.Peek(scatter, len);
00406 }
00407 #endif /* GUSI_SOURCE */
00408 
00409 #endif /* _GUSIBuffer_ */