Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MessageQueue.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_MessageQueue_h_
00003 #define INCLUDED_MessageQueue_h_
00004 
00005 #ifdef PLATFORM_APERIOS
00006 #  warning MessageQueue is not Aperios compatable
00007 #else
00008 
00009 #include "ListMemBuf.h"
00010 #include "RCRegion.h"
00011 #include "SemaphoreManager.h"
00012 #include "MutexLock.h"
00013 #include "Shared/MarkScope.h"
00014 #include "Shared/attributes.h"
00015 #include <exception>
00016 
00017 #include "Shared/TimeET.h"
00018 
00019 //! Defines the interface for sending new shared memory regions between processes
00020 /*! This base class holds all of the template-independent code to allow general
00021  *  operations on MessageQueues.  The templated version of MessageQueue provides
00022  *  concrete implementation, which is what you would instantiate.
00023  *  
00024  *  Each message entails its own shared memory region, as compared to
00025  *  SharedQueue, where a single large buffer is maintained, and all messages are
00026  *  copied into the common buffer.  This class is better for large regions since
00027  *  it can avoid copying data around.
00028  * 
00029  *  @see MessageQueue, MessageQueueStatusListener, MessageReceiver */
00030 class MessageQueueBase {
00031 public:
00032 
00033   //! an interface for filtering (or otherwise monitoring) messages being sent through a MessageQueue, see MessageQueueBase::addMessageFilter()
00034   class MessageFilter {
00035   public:
00036     //! called immediately prior to sending a message -- return true to pass the message into the queue, false to drop it
00037     virtual bool filterSendRequest(RCRegion* rcr)=0;
00038     //! to make compiler warning happy
00039     virtual ~MessageFilter() {}
00040   };
00041   
00042   //!constructor
00043   MessageQueueBase()
00044     : lock(), overflowPolicy(THROW_BAD_ALLOC), isClosed(false), reportDroppings(false), numMessages(0),
00045       numReceivers(0), messagesRead(0)
00046   {
00047     for(unsigned int i=0; i<ProcessID::NumProcesses; ++i)
00048       filters[i]=NULL;
00049   }
00050   //!destructor
00051   virtual ~MessageQueueBase() {}
00052   
00053   
00054   //! The storage type for message entry indicies
00055   /*! This index is to be used with accessor functions, but may be recycled for
00056    *  a new message after all receivers have read the previous message.  If you
00057    *  wish to have a unique message identifier, see getMessageSN() */
00058   typedef unsigned short index_t;
00059   
00060   
00061   //! add one to the receiver reference count
00062   virtual SemaphoreManager::semid_t addReceiver() ATTR_must_check =0;
00063   //! remove one from the receiver reference count
00064   virtual void removeReceiver(SemaphoreManager::semid_t rcvr)=0;
00065   //! return the receiver reference count
00066   virtual unsigned int getNumReceivers() const { return numReceivers; }
00067 
00068   //! registers a semaphore which should be raised whenever a message is marked read
00069   /*! The number of these are limited to the MAX_SENDERS template parameter of
00070     *  MessageQueue... returns false if too many are already registered
00071     *  
00072     *  You probably don't want to call this directly, use a MessageQueueStatusThread */
00073   virtual SemaphoreManager::semid_t addReadStatusListener() ATTR_must_check =0;
00074   //! removes a semaphore from the status listener list
00075   virtual void removeReadStatusListener(SemaphoreManager::semid_t sem)=0;
00076   
00077   
00078   //! post a message into the queue -- a shared reference is added, the caller retains control current reference
00079   /*! Thus, if you are sending a region and do not intend to use it again, either pass
00080    *  true for autoDereference or call RCRegion::RemoveReference() after sending
00081    *  to free the sender's memory.
00082    *  
00083    *  If no one dereferences the region, you can continue to access the region,
00084    *  even as the receiver accesses it as well.  Thus if both sides retain references,
00085    *  you can use the region as a shared memory area for future communication.
00086    *  (beware of race conditions!)
00087    *
00088    *  If @a rcr is NULL, an empty message will be sent (there's still some overhead
00089    *  to this -- may want to consider a semaphore instead of a MessageQueue if all
00090    *  you're going to do is 'ping' another process with empty messages) */
00091   virtual void sendMessage(RCRegion * rcr, bool autoDereference=false)=0;
00092   //! request access to a particular message, increments read counter -- do not call more than once per receiver!
00093   /*! The message is marked read and will be popped from the queue if all
00094    *  receivers have read the message as well.  The caller inherits a reference
00095    *  to the returned region -- call RemoveReference when you are done with
00096    *  it */
00097   virtual RCRegion * readMessage(index_t msg, SemaphoreManager::semid_t rcvr)=0;
00098   //! request access to a particular message, does not mark message -- call as often as you like
00099   /*! The caller inherits a reference to the returned region -- call
00100    *  RemoveReference when you are done with it */
00101   virtual RCRegion * peekMessage(index_t msg)=0;
00102   //! increments read counter -- do not call more than once per receiver per message!
00103   virtual void markRead(index_t msg, SemaphoreManager::semid_t rcvr)=0;
00104   //! do not allow any new messages to be posted
00105   virtual void close() { AutoLock autolock(lock); isClosed=true; }
00106 
00107   //! sets #reportDroppings
00108   virtual void setReportDroppings(bool report) { reportDroppings=report; }
00109   //! gets #reportDroppings
00110   virtual bool getReportDroppings() const { return reportDroppings; }
00111   
00112   
00113   //! Each message gets a unique, monotonically increasing serial number; this function returns that number (MessageQueue::serialNumber)
00114   virtual unsigned int getMessageSN(index_t msg)=0;
00115   
00116   //! Checks to see how many messages have been processed (read by all receivers and removed from queue)
00117   virtual unsigned int getMessagesRead() { return messagesRead; }
00118   
00119   //! Returns the number of messages which have been sent
00120   virtual unsigned int getMessagesSent() { return numMessages; }
00121   
00122   //! Returns the number of messages which have been sent
00123   virtual unsigned int getMessagesUnread() { return getMessagesSent() - getMessagesRead(); }
00124   
00125   //! a typedef to make it easier to obtain a lock on the queue for the extent of a scope
00126   typedef MarkScope AutoLock;
00127   //! returns a reference to the queue's inter-process lock
00128   MutexLock<ProcessID::NumProcesses>& getLock() const { return lock; }
00129 
00130   
00131   virtual index_t oldest() const=0;          //!< return oldest message still in the queue (may or may not have been read by this process)
00132   virtual index_t newer(index_t it) const=0; //!< return the next message in the queue (may or may not have been read by this process)
00133   virtual index_t older(index_t it) const=0; //!< return the previous message in the queue (may or may not have been read by this process)
00134   virtual index_t newest() const=0;          //!< return most recent message added to the queue (may or may not have been read by this process)
00135   virtual bool isEnd(index_t it) const=0;    //!< returns true if @a it is the one-past-the-end of the queue
00136   
00137   //! an enumerations of policies for dealing with overflow, pass to setOverflowPolicy()
00138   enum OverflowPolicy_t {
00139     DROP_OLDEST,     //!< the oldest unread message is dropped
00140     DROP_NEWEST,     //!< the most recently added message is dropped (i.e. the overflowing message is ignored)
00141     WAIT,            //!< the adding process/thread polls until space is available
00142     THROW_BAD_ALLOC  //!< throw a std::bad_alloc exception (falls through to abort() if you don't catch it)
00143   };
00144   //! allows you to pick how to handle running out of space in the queue, see OverflowPolicy_t
00145   void setOverflowPolicy(OverflowPolicy_t op) { overflowPolicy=op; }
00146   //! returns the current overflow policy, see OverflowPolicy_t
00147   OverflowPolicy_t getOverflowPolicy() const { return overflowPolicy; }
00148   
00149   //! sets #semgr
00150   static void setSemaphoreManager(SemaphoreManager* mgr) { semgr=mgr; }
00151   //! gets #semgr
00152   static SemaphoreManager* getSemaphoreManager() { return semgr; }
00153   
00154   //! once called, any messages put into the queue must pass through @a filter first (note: there can only be one filter per process!)
00155   /*! if a filter was previously registered, it is replaced with the new @a filter */
00156   void addMessageFilter(MessageFilter& filter) {
00157     filters[ProcessID::getID()]=&filter;
00158   }
00159   //! removes the current filter in place, if any
00160   void removeMessageFilter() {
00161     filters[ProcessID::getID()]=NULL;
00162   }
00163 protected:
00164   //! the global semaphore manager, needs to be set (once, globally) via setSemaphoreManager() before any receivers are added
00165   static SemaphoreManager* semgr;
00166   
00167   mutable MutexLock<ProcessID::NumProcesses> lock; //!< a lock to grant serial access to the queue
00168   volatile OverflowPolicy_t overflowPolicy; //!< the choice of how to handle message overflow -- see OverflowPolicy_t
00169   bool isClosed; //!< if true, new messages will be rejected
00170   bool reportDroppings; //!< if true, output will be sent on cerr when overflow occurs
00171   unsigned int numMessages; //!< number of messages which have been sent (serial number of next message)
00172   unsigned int numReceivers; //!< how many receivers to expect
00173   unsigned int messagesRead; //!< number of messages which have been read and removed from queue
00174   MessageFilter* filters[ProcessID::NumProcesses]; //!< provides storage of one message filter per process
00175 private:
00176   MessageQueueBase(const MessageQueueBase&); //!< this shouldn't be called...
00177   MessageQueueBase& operator=(const MessageQueueBase&); //!< this shouldn't be called...
00178 };
00179 
00180 //! An implementation of MessageQueueBase, which provides mechanisms for sending shared memory regions between processes
00181 /*! MAX_UNREAD is assigned to #CAPACITY, MAX_RECEIVERS is assigned to #RECEIVER_CAPACITY, and MAX_SENDERS is assigned to #SENDER_CAPACITY
00182  *  @see MessageQueueBase, MessageQueueStatusListener, MessageReceiver */
00183 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS=10, unsigned int MAX_SENDERS=10>
00184 class MessageQueue : public MessageQueueBase {
00185 public:
00186   //! total number of messages which can be backed up in the queue
00187   static const unsigned int CAPACITY=MAX_UNREAD;
00188   //! total number of receivers which can be registered
00189   static const unsigned int RECEIVER_CAPACITY=MAX_RECEIVERS;
00190   //! total number of senders which can be registered
00191   /*! More specifically, this is the maximum number of StatusListeners -- anyone
00192    *  can call sendMessage(), but only this number can get direct notification when
00193    *  messages are received. */
00194   static const unsigned int SENDER_CAPACITY=MAX_SENDERS;
00195   
00196   //! constructor
00197   MessageQueue() : MessageQueueBase(), mq(), rcvrs(), sndrs() {}
00198   
00199   //! destructor
00200   virtual ~MessageQueue();
00201   
00202   virtual SemaphoreManager::semid_t addReadStatusListener() ATTR_must_check;
00203   virtual void removeReadStatusListener(SemaphoreManager::semid_t sem);
00204 
00205   virtual SemaphoreManager::semid_t addReceiver() ATTR_must_check;
00206   virtual void removeReceiver(SemaphoreManager::semid_t rcvr);
00207   
00208   virtual void sendMessage(RCRegion * rcr, bool autoDereference=false);
00209   virtual RCRegion * readMessage(index_t msg, SemaphoreManager::semid_t rcvr);
00210   virtual RCRegion * peekMessage(index_t msg);
00211   virtual void markRead(index_t msg, SemaphoreManager::semid_t rcvr);
00212 
00213   virtual unsigned int getMessageSN(index_t msg) { /*AutoLock autolock(lock);*/ return mq[msg].sn; }
00214   
00215   virtual index_t oldest() const { AutoLock autolock(lock); return mq.begin(); }
00216   virtual index_t newer(index_t it) const { AutoLock autolock(lock); return mq.next(it); }
00217   virtual index_t older(index_t it) const { AutoLock autolock(lock); return mq.prev(it); }
00218   virtual index_t newest() const { AutoLock autolock(lock); return mq.prev(mq.end()); }
00219   virtual bool isEnd(index_t it) const { AutoLock autolock(lock); return it==mq.end() || it>=mq_t::MAX_ENTRIES; }
00220   
00221 protected:
00222   //! data storage needed for each message
00223   struct entry {
00224     entry() : id(), sn(), numRead(0) { memset(readFlags,0,sizeof(readFlags)); } //!< constructor
00225     entry(unsigned int serialNumber, RCRegion* r)
00226     : id(r->ID()), sn(serialNumber), numRead(0) { memset(readFlags,0,sizeof(readFlags)); } //!< constructor, pass message info
00227     RCRegion::Identifier id; //!< the identifier for the shared memory region so that other regions can attach it
00228     unsigned int sn; //!< serial number for this message (not the same as its index in the queue -- indicies are reused, this id is unique to this message
00229     bool readFlags[MAX_RECEIVERS]; //!< a flag for each receiver to indicate if they have read it
00230     unsigned int numRead; //!< a count of the number of receivers which have read this message (should always equal sum(readFlags))
00231   };
00232   
00233   //! shorthand for the type of data storage of message entries
00234   typedef ListMemBuf<entry,MAX_UNREAD,index_t> mq_t;
00235   //! the data storage of message entries
00236   mq_t mq;
00237 
00238   //! shorthand for the type of data storage of message entries
00239   typedef ListMemBuf<SemaphoreManager::semid_t,MAX_RECEIVERS,index_t> rcvrs_t;
00240   //! the data storage of receiver semaphores
00241   rcvrs_t rcvrs;
00242 
00243   //! returns the index within #rcvrs of the receiver id @a rcvr
00244   typename rcvrs_t::index_t lookupReceiver(SemaphoreManager::semid_t rcvr) const;
00245   
00246   //! shorthand for the type of data storage of message entries
00247   typedef ListMemBuf<SemaphoreManager::semid_t,MAX_SENDERS,index_t> sndrs_t;
00248   //! the data storage of receiver semaphores
00249   sndrs_t sndrs;
00250 };
00251 
00252 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00253 MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::~MessageQueue() {
00254     //lock shouldn't be necessary -- refcount should ensure the containing
00255     //region isn't deleted until only one process has access anyway
00256     //AutoLock autolock(lock);
00257     while(!mq.empty()) {
00258       RCRegion * rcr = RCRegion::attach(mq.front().id);
00259       rcr->RemoveSharedReference();
00260       rcr->RemoveReference();
00261       mq.pop_front();
00262     }
00263 }
00264 
00265 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00266 SemaphoreManager::semid_t MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::addReadStatusListener() {
00267     AutoLock autolock(lock);
00268     SemaphoreManager::semid_t sem=semgr->getSemaphore();
00269     if(sem==semgr->invalid()) {
00270       std::cerr << "ERROR: unable to add read status listener to message queue because semaphore manager is out of semaphores" << std::endl;
00271       return semgr->invalid();
00272     }
00273     if(sndrs.push_back(sem)==sndrs.end()) {
00274       std::cerr << "ERROR: unable to add read status listener to message queue because message queue can't register any more senders (MAX_SENDERS)" << std::endl;
00275       semgr->releaseSemaphore(sem);
00276       return semgr->invalid();
00277     }
00278     return sem;
00279 }
00280 
00281 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00282 void MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::removeReadStatusListener(SemaphoreManager::semid_t sem) {
00283     AutoLock autolock(lock);
00284     for(index_t it=sndrs.begin(); it!=sndrs.end(); it=sndrs.next(it))
00285       if(sndrs[it]==sem) {
00286         sndrs.erase(it);
00287         semgr->releaseSemaphore(sem);
00288         break;
00289       }
00290 }
00291 
00292 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00293 SemaphoreManager::semid_t MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::addReceiver() {
00294     AutoLock autolock(lock);
00295     SemaphoreManager::semid_t sem=semgr->getSemaphore();
00296     if(sem==semgr->invalid()) {
00297       std::cerr << "ERROR: unable to add receiver to message queue because semaphore manager is out of semaphores" << std::endl;
00298       return semgr->invalid();
00299     }
00300     if(rcvrs.push_back(sem)==rcvrs.end()) {
00301       std::cerr << "ERROR: unable to add receiver to message queue because message queue can't register any more receivers (MAX_RECEIVERS)" << std::endl;
00302       semgr->releaseSemaphore(sem);
00303       return semgr->invalid();
00304     }
00305     numReceivers++;
00306     return sem;
00307 }
00308 
00309 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00310 void MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::removeReceiver(SemaphoreManager::semid_t rcvr) {
00311     AutoLock autolock(lock);
00312     index_t rcvr_id=rcvrs.begin();
00313     for(; rcvr_id!=rcvrs.end(); rcvr_id=rcvrs.next(rcvr_id))
00314       if(rcvrs[rcvr_id]==rcvr)
00315         break;
00316     if(rcvr_id==rcvrs.end()) {
00317       std::cerr << "WARNING: tried to remove message queue receiver " << rcvr << ", which is not registered as a receiver for this queue" << std::endl;
00318       return;
00319     }
00320     rcvrs.erase(rcvr_id);
00321     semgr->releaseSemaphore(rcvr);
00322     numReceivers--;
00323     for(index_t it=mq.begin(); it!=mq.end(); it=mq.next(it)) {
00324       if(mq[it].readFlags[rcvr_id]) {
00325         // the removed receiver had read this message, decrement the read count
00326         mq[it].readFlags[rcvr_id]=false;
00327         mq[it].numRead--;
00328       } else if(mq[it].numRead==numReceivers) {
00329         //all *remaining* processes have gotten a look, remove the neutral MessageQueue reference
00330         RCRegion * rcr = RCRegion::attach(mq[it].id);
00331         rcr->RemoveSharedReference();
00332         rcr->RemoveReference();
00333         it=mq.prev(it);
00334         mq.erase(mq.next(it));
00335         messagesRead++;
00336         for(index_t sit=sndrs.begin(); sit!=sndrs.end(); sit=sndrs.next(sit))
00337           semgr->raise(sndrs[sit],1);
00338       }
00339     }
00340 }
00341 
00342 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00343 void MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::sendMessage(RCRegion * rcr, bool autoDereference/*=false*/) {
00344     AutoLock autolock(lock);
00345     if(rcr==NULL) {
00346       rcr=new RCRegion(0);
00347       autoDereference=true;
00348     }
00349     if(filters[ProcessID::getID()]!=NULL && !filters[ProcessID::getID()]->filterSendRequest(rcr))
00350       return;
00351     if(numReceivers==0) {
00352       //if(reportDroppings)
00353       //std::cerr << "Warning: MessageQueue dropping " << rcr->ID().key << " because there are no receivers" << std::endl;
00354       messagesRead++; // counts as a read message (read by all 0 readers is still read by all readers!)
00355       for(index_t sit=sndrs.begin(); sit!=sndrs.end(); sit=sndrs.next(sit))
00356         semgr->raise(sndrs[sit],1);
00357       return;
00358     }
00359     if(isClosed) {
00360       if(reportDroppings)
00361         std::cerr << "Warning: MessageQueue dropping " << rcr->ID().key << " because queue is closed" << std::endl;
00362       return;
00363     }
00364     if(mq.size()==mq.getMaxCapacity()) {
00365       switch(overflowPolicy) {
00366         case DROP_OLDEST: {
00367           if(reportDroppings)
00368             std::cerr << "WARNING: MessageQueue full, dropping oldest unread message (" << mq.front().id.key << ")" << std::endl;
00369           RCRegion * eldest = RCRegion::attach(mq.front().id);
00370           eldest->RemoveSharedReference();
00371           mq.pop_front();
00372           eldest->RemoveReference();
00373         } break;
00374         case DROP_NEWEST:
00375           if(reportDroppings)
00376             std::cerr << "WARNING: MessageQueue full, dropping newest unread message (" << rcr->ID().key << ")" << std::endl;
00377           return;
00378         case WAIT:
00379           if(reportDroppings)
00380             std::cerr << "WARNING: MessageQueue full, waiting for readers to catch up" << std::endl;
00381           while(mq.size()==mq.getMaxCapacity()) {
00382             //have to release locks so readers can get access
00383             unsigned int ll=lock.get_lock_level();
00384             lock.releaseAll();
00385             usleep(MutexLockBase::usleep_granularity*15);
00386             for(unsigned int i=0; i<ll; i++)
00387               lock.lock(ProcessID::getID());
00388             if(overflowPolicy!=WAIT) { //may have been changed by a different thread while we were waiting
00389               sendMessage(rcr); //retry with the new policy
00390               return;
00391             }
00392           }
00393             break;
00394         case THROW_BAD_ALLOC:
00395           if(reportDroppings)
00396             std::cerr << "WARNING: MessageQueue full, throwing bad_alloc exception" << std::endl;
00397           throw std::bad_alloc();
00398           break;
00399       }
00400     }
00401     rcr->AddSharedReference();
00402     if(mq.push_back(entry(numMessages++,rcr))==mq.end()) {
00403       //our overflow policy should've prevented this
00404       std::cerr << "ERROR: MessageQueue unable to add message; buggy overflow policy?" << std::endl;
00405       exit(EXIT_FAILURE);
00406     }
00407     
00408     //std::cout << Process::getName() << " sent " << (numMessages-1) << " at " << TimeET() << std::endl;
00409     //notify receivers
00410     for(index_t it=rcvrs.begin(); it!=rcvrs.end(); it=rcvrs.next(it))
00411       semgr->raise(rcvrs[it],1);
00412     
00413     if(autoDereference)
00414       rcr->RemoveReference();
00415 }
00416 
00417 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00418 RCRegion * MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::readMessage(index_t msg, SemaphoreManager::semid_t rcvr) {
00419     AutoLock autolock(lock);
00420     RCRegion * rcr = RCRegion::attach(mq[msg].id);
00421     index_t rcvr_id=lookupReceiver(rcvr);
00422     if(rcvr_id==rcvrs.end())
00423       return rcr;
00424     if(mq[msg].readFlags[rcvr_id]) {
00425       std::cerr << "WARNING: MessageQueue::readMessage(): Receiver re-reading message, could be recycled/invalidated any time" << std::endl;
00426       return rcr; // already read, just return it
00427     }
00428     mq[msg].readFlags[rcvr_id]=true;
00429     mq[msg].numRead++;
00430     if(mq[msg].numRead==numReceivers) {
00431       //all processes have gotten a look, remove the neutral MessageQueue reference
00432       rcr->RemoveSharedReference();
00433       mq.erase(msg);
00434       messagesRead++;
00435       for(index_t sit=sndrs.begin(); sit!=sndrs.end(); sit=sndrs.next(sit))
00436         semgr->raise(sndrs[sit],1);
00437     }
00438     return rcr;
00439 }
00440 
00441 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00442 RCRegion * MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::peekMessage(index_t msg) {
00443     //AutoLock autolock(lock); //I don't think a lock is necessary here
00444     return RCRegion::attach(mq[msg].id);
00445 }
00446 
00447 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00448 void MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::markRead(index_t msg, SemaphoreManager::semid_t rcvr) {
00449     AutoLock autolock(lock);
00450     index_t rcvr_id=lookupReceiver(rcvr);
00451     if(rcvr_id==rcvrs.end())
00452       return;
00453     if(mq[msg].readFlags[rcvr_id]) {
00454       std::cerr << "WARNING: MessageQueue::markRead(): Receiver re-reading message, could be recycled/invalidated any time" << std::endl;
00455       return; // already read, just return it
00456     }
00457     mq[msg].readFlags[rcvr_id]=true;
00458     mq[msg].numRead++;
00459     if(mq[msg].numRead==numReceivers) {
00460       //all processes have gotten a look, remove the neutral MessageQueue reference
00461       RCRegion * rcr = RCRegion::attach(mq[msg].id);
00462       rcr->RemoveSharedReference();
00463       rcr->RemoveReference();
00464       mq.erase(msg);
00465       messagesRead++;
00466       for(index_t sit=sndrs.begin(); sit!=sndrs.end(); sit=sndrs.next(sit))
00467         semgr->raise(sndrs[sit],1);
00468     }
00469 }
00470 
00471 template<unsigned int MAX_UNREAD, unsigned int MAX_RECEIVERS, unsigned int MAX_SENDERS>
00472 typename MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::rcvrs_t::index_t
00473 MessageQueue<MAX_UNREAD,MAX_RECEIVERS,MAX_SENDERS>::lookupReceiver(SemaphoreManager::semid_t rcvr) const {
00474   for(index_t rcvr_id=rcvrs.begin(); rcvr_id!=rcvrs.end(); rcvr_id=rcvrs.next(rcvr_id))
00475     if(rcvrs[rcvr_id]==rcvr)
00476       return rcvr_id;
00477   std::cerr << "WARNING: tried to look up queue receiver " << rcvr << ", which is not registered as a receiver for this queue" << std::endl;
00478   return rcvrs.end();
00479 }
00480 
00481 /*! @file
00482  * @brief Defines MessageQueue, which provides mechanisms for sending shared memory regions between processes
00483  * @author ejt (Creator)
00484  *
00485  * $Author: ejt $
00486  * $Name: tekkotsu-4_0 $
00487  * $Revision: 1.32 $
00488  * $State: Exp $
00489  * $Date: 2007/11/10 22:58:08 $
00490  */
00491 
00492 #endif //APERIOS check
00493 
00494 #endif //INCLUDED

Tekkotsu v4.0
Generated Thu Nov 22 00:54:54 2007 by Doxygen 1.5.4