Homepage Demos Overview Downloads Tutorials Reference
Credits

SharedQueue.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_SharedQueue_h_
00003 #define INCLUDED_SharedQueue_h_
00004 
00005 #include "MutexLock.h"
00006 #include "ProcessID.h"
00007 #include "LockScope.h"
00008 
00009 //! SharedQueue is a shared memory message buffer for interprocess communication
00010 /*! This doesn't gain you much functionality over the Aperios messages - in fact,
00011  *  you lose some because you have to poll this for new data whereas Aperios will
00012  *  notify you.
00013  *
00014  *  However, the big advantage of this is that you don't have any lag time from the system
00015  *  in sending the message from one process to the other - it's instantly available.
00016  *  Also, you can poll for new data from within a loop, whereas you cannot check
00017  *  to see if you have any messages waiting from Aperios until you exit to the system.
00018  *  
00019  *  This makes no assumptions about the data to be stored - it's all just an array of bytes
00020  *
00021  *  Assumptions are made about reception usage: all entries will be processed and then
00022  *  cleared so that the queue is emptied.  You cannot pop the front, only clear the whole
00023  *  thing.  This assumption allows much simpler/faster access. (Otherwise we need to
00024  *  implement a circular buffer and worry about wrap around.  *shrug* Not too hard, but
00025  *  unnecessary complication for now.) */
00026 template<unsigned int maxsize, unsigned int maxentries>
00027 class SharedQueue {
00028 public:
00029   //! maximum capacity of data storage for the queue
00030   static const unsigned int MAX_SIZE=maxsize;
00031   //! maximum number of entries that can be queued
00032   static const unsigned int MAX_ENTRIES=maxentries;
00033   
00034   //! constructor
00035   SharedQueue();
00036 
00037   //! inserts a class into the queue
00038   template<class T> bool SharedQueue<maxsize,maxentries>::push(const T& obj);
00039 
00040   //! reserves a number of bytes in the queue, LEAVES QUEUE LOCKED, call done when finished
00041   void* reserve(unsigned int size);
00042   
00043   //! call this when you're finished filling in a buffer you received from reserve
00044   void done() { lock.release(); }
00045 
00046   //! checks to see if the number taken by the reader is the number added, and then clears
00047   /*! This will allow you to process entries without locking the entire queue, but still
00048    *  not worry about missing one (or more) if it was added while you were processing the
00049    *  last one. */
00050   bool clear(unsigned int taken);
00051   
00052   //! returns current number of entries
00053   unsigned int size() const { return len; }
00054   
00055   //! returns size of entry @a i
00056   unsigned int size(unsigned int i) const { return entries[i].size; }
00057 
00058   //! returns data of entry @a i
00059   const void* data(unsigned int i) const { return &buf[entries[i].offset]; }
00060 
00061 protected:
00062   //! returns the first free byte in buf
00063   unsigned int buf_end() { return len==0?0:entries[len-1].offset+entries[len-1].size; }
00064   
00065   //! returns @a sz rounded up to the nearest word (makes @a sz divisible by sizeof(int))
00066   unsigned int round_up(unsigned int sz) { return ((sz-1)/sizeof(int)+1)*sizeof(int); }
00067 
00068   //! provides mutual exclusion on non-const functions
00069   MutexLock<ProcessID::NumProcesses> lock;
00070   //! for convenience in locking functions
00071   typedef LockScope<ProcessID::NumProcesses> AutoLock;
00072 
00073   //! data storage
00074   char buf[MAX_SIZE];
00075   
00076   //! entry information
00077   struct entry_t {
00078     unsigned int offset; //!< offset within SharedQueue::buf
00079     unsigned int size;   //!< size of entry
00080   };
00081 
00082   //! holds number of entries
00083   unsigned int len;
00084   
00085   //! holds entry information
00086   entry_t entries[MAX_ENTRIES];
00087 };
00088 
00089 template<unsigned int maxsize, unsigned int maxentries>
00090 SharedQueue<maxsize,maxentries>::SharedQueue()
00091   : lock(), len(0)
00092 {}
00093 
00094 //! there's a comment above in header - inserts a class into the queue
00095 template<unsigned int maxsize, unsigned int maxentries> template<class T>
00096 bool
00097 SharedQueue<maxsize,maxentries>::push(const T& obj) {
00098   AutoLock(lock,ProcessID::getID());
00099   if(len>=MAX_ENTRIES)
00100     return false;
00101   entries[len].offset=buf_end();
00102   entries[len].size=round_up(sizeof(obj));
00103   if(entries[len].offset+entries[len].size>=MAX_SIZE)
00104     return false;
00105   len++;
00106   return true;
00107 }
00108 
00109 template<unsigned int maxsize, unsigned int maxentries>
00110 void*
00111 SharedQueue<maxsize,maxentries>::reserve(unsigned int sz) {
00112   AutoLock(lock,ProcessID::getID());
00113   if(len>=MAX_ENTRIES)
00114     return NULL;
00115   entries[len].offset=buf_end();
00116   entries[len].size=round_up(sz);
00117   if(entries[len].offset+entries[len].size>=MAX_SIZE)
00118     return NULL;
00119   return &buf[entries[len++].offset];
00120 }
00121 
00122 template<unsigned int maxsize, unsigned int maxentries>
00123 bool
00124 SharedQueue<maxsize,maxentries>::clear(unsigned int taken) {
00125   AutoLock(lock,ProcessID::getID());
00126   if(size()!=taken)
00127     return false;
00128   len=0;
00129   return true;
00130 }
00131 
00132 /*! @file
00133  * @brief Defines SharedQueue, a shared memory message buffer for interprocess communication
00134  * @author ejt (Creator)
00135  *
00136  * $Author: ejt $
00137  * $Name: tekkotsu-2_2 $
00138  * $Revision: 1.5 $
00139  * $State: Exp $
00140  * $Date: 2004/01/18 10:16:58 $
00141  */
00142 
00143 #endif

Tekkotsu v2.2
Generated Tue Oct 19 14:19:15 2004 by Doxygen 1.3.9.1