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

Tekkotsu v3.0
Generated Wed Oct 4 00:03:44 2006 by Doxygen 1.4.7