MessageQueue.hGo to the documentation of this file.00001
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 "LockScope.h"
00012 #include <exception>
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 class MessageQueueBase {
00024 public:
00025
00026
00027 MessageQueueBase()
00028 : lock(), overflowPolicy(THROW_BAD_ALLOC), isClosed(false), reportDroppings(false), numMessages(0),
00029 numReceivers(0), messagesRead()
00030 {}
00031
00032 virtual ~MessageQueueBase() {}
00033
00034
00035
00036 class StatusListener {
00037 public:
00038
00039 virtual ~StatusListener() {}
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 virtual void messagesRead(MessageQueueBase& which, unsigned int howmany)=0;
00054 };
00055
00056
00057 virtual unsigned int pollStatus() {
00058 AutoLock autolock(lock);
00059 unsigned int read=messagesRead;
00060 messagesRead=0;
00061 return read;
00062 }
00063
00064
00065
00066
00067
00068
00069 typedef unsigned short index_t;
00070
00071
00072
00073 virtual void addReceiver()=0;
00074
00075 virtual void removeReceiver()=0;
00076
00077 virtual unsigned int getNumReceivers() const { return numReceivers; }
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 virtual void sendMessage(RCRegion * rcr)=0;
00088
00089
00090
00091
00092
00093 virtual RCRegion * readMessage(index_t msg)=0;
00094
00095
00096
00097 virtual RCRegion * peekMessage(index_t msg)=0;
00098
00099 virtual void markRead(index_t msg)=0;
00100
00101 virtual void close() { AutoLock autolock(lock); isClosed=true; }
00102
00103 virtual void setReportDroppings(bool report) { reportDroppings=report; }
00104 virtual bool getReportDroppings() const { return reportDroppings; }
00105
00106
00107
00108 virtual unsigned int getMessageSN(index_t msg)=0;
00109
00110
00111
00112 typedef LockScope<ProcessID::NumProcesses> AutoLock;
00113
00114 AutoLock getLock() const { return AutoLock(lock); }
00115
00116
00117 virtual index_t oldest() const=0;
00118 virtual index_t newer(index_t it) const=0;
00119 virtual index_t older(index_t it) const=0;
00120 virtual index_t newest() const=0;
00121 virtual bool isEnd(index_t it) const=0;
00122
00123
00124 enum OverflowPolicy_t {
00125 DROP_OLDEST,
00126 DROP_NEWEST,
00127 WAIT,
00128 THROW_BAD_ALLOC
00129 };
00130
00131 void setOverflowPolicy(OverflowPolicy_t op) { overflowPolicy=op; }
00132
00133 OverflowPolicy_t getOverflowPolicy() const { return overflowPolicy; }
00134
00135 protected:
00136
00137 struct entry {
00138 entry() : id(), sn(), numRead(0) {}
00139 entry(unsigned int serialNumber, RCRegion* r)
00140 : id(r->ID()), sn(serialNumber), numRead(0) {}
00141 RCRegion::Identifier id;
00142 unsigned int sn;
00143 unsigned int numRead;
00144 };
00145 mutable MutexLock<ProcessID::NumProcesses> lock;
00146 OverflowPolicy_t overflowPolicy;
00147 bool isClosed;
00148 bool reportDroppings;
00149 unsigned int numMessages;
00150 unsigned int numReceivers;
00151 unsigned int messagesRead;
00152 };
00153
00154
00155
00156 template<unsigned int MAX_UNREAD>
00157 class MessageQueue : public MessageQueueBase {
00158 public:
00159
00160 static const unsigned int CAPACITY=MAX_UNREAD;
00161
00162
00163 MessageQueue() : MessageQueueBase(), mq() {}
00164
00165 virtual ~MessageQueue() {
00166
00167
00168
00169 while(!mq.empty()) {
00170 RCRegion * rcr = RCRegion::attach(mq.front().id);
00171 rcr->RemoveSharedReference();
00172 rcr->RemoveReference();
00173 mq.pop_front();
00174 }
00175 }
00176
00177 virtual void addReceiver() {
00178 AutoLock autolock(lock);
00179 numReceivers++;
00180 }
00181
00182 virtual void removeReceiver() {
00183 AutoLock autolock(lock);
00184 numReceivers--;
00185 for(index_t it=mq.begin(); it!=mq.end(); it=mq.next(it)) {
00186 if(mq[it].numRead==numReceivers) {
00187
00188 RCRegion * rcr = RCRegion::attach(mq[it].id);
00189 rcr->RemoveSharedReference();
00190 rcr->RemoveReference();
00191 it=mq.prev(it);
00192 mq.erase(mq.next(it));
00193 messagesRead++;
00194 }
00195 }
00196 }
00197
00198 virtual void sendMessage(RCRegion * rcr) {
00199 AutoLock autolock(lock);
00200 if(numReceivers==0) {
00201
00202
00203 return;
00204 }
00205 if(isClosed) {
00206 if(reportDroppings)
00207 std::cerr << "Warning: MessageQueue dropping " << rcr->ID().key << " because queue is closed" << std::endl;
00208 return;
00209 }
00210 rcr->AddSharedReference();
00211 if(mq.size()==mq.getMaxCapacity()) {
00212 switch(overflowPolicy) {
00213 case DROP_OLDEST: {
00214 if(reportDroppings)
00215 std::cerr << "WARNING: MessageQueue full, dropping oldest unread message (" << mq.front().id.key << ")" << std::endl;
00216 RCRegion * eldest = RCRegion::attach(mq.front().id);
00217 eldest->RemoveSharedReference();
00218 mq.pop_front();
00219 eldest->RemoveReference();
00220 } break;
00221 case DROP_NEWEST:
00222 if(reportDroppings)
00223 std::cerr << "WARNING: MessageQueue full, dropping newest unread message (" << rcr->ID().key << ")" << std::endl;
00224 rcr->RemoveSharedReference();
00225 return;
00226 case WAIT:
00227 if(reportDroppings)
00228 std::cerr << "WARNING: MessageQueue full, waiting for readers to catch up" << std::endl;
00229 while(mq.size()==mq.getMaxCapacity()) {
00230
00231 unsigned int ll=lock.get_lock_level();
00232 lock.releaseAll();
00233 usleep(MutexLockBase::usleep_granularity*15);
00234 for(unsigned int i=0; i<ll; i++)
00235 lock.lock(ProcessID::getID());
00236 }
00237 break;
00238 case THROW_BAD_ALLOC:
00239 if(reportDroppings)
00240 std::cerr << "WARNING: MessageQueue full, throwing bad_alloc exception" << std::endl;
00241 rcr->RemoveSharedReference();
00242 throw std::bad_alloc();
00243 break;
00244 }
00245 }
00246 if(mq.push_back(entry(numMessages++,rcr))==mq.end()) {
00247
00248 std::cerr << "ERROR: MessageQueue unable to add message; buggy overflow policy?" << std::endl;
00249 exit(EXIT_FAILURE);
00250 }
00251 }
00252
00253 virtual RCRegion * readMessage(index_t msg) {
00254 AutoLock autolock(lock);
00255 RCRegion * rcr = RCRegion::attach(mq[msg].id);
00256 mq[msg].numRead++;
00257 if(mq[msg].numRead==numReceivers) {
00258
00259 rcr->RemoveSharedReference();
00260 mq.erase(msg);
00261 messagesRead++;
00262 }
00263 return rcr;
00264 }
00265
00266 virtual RCRegion * peekMessage(index_t msg) {
00267
00268 return RCRegion::attach(mq[msg].id);
00269 }
00270
00271 virtual void markRead(index_t msg) {
00272 AutoLock autolock(lock);
00273 mq[msg].numRead++;
00274 if(mq[msg].numRead==numReceivers) {
00275
00276 RCRegion * rcr = RCRegion::attach(mq[msg].id);
00277 rcr->RemoveSharedReference();
00278 rcr->RemoveReference();
00279 mq.erase(msg);
00280 messagesRead++;
00281 }
00282 }
00283
00284 virtual unsigned int getMessageSN(index_t msg) { return mq[msg].sn; }
00285
00286 virtual index_t oldest() const { AutoLock autolock(lock); return mq.begin(); }
00287 virtual index_t newer(index_t it) const { AutoLock autolock(lock); return mq.next(it); }
00288 virtual index_t older(index_t it) const { AutoLock autolock(lock); return mq.prev(it); }
00289 virtual index_t newest() const { AutoLock autolock(lock); return mq.prev(mq.end()); }
00290 virtual bool isEnd(index_t it) const { AutoLock autolock(lock); return it==mq.end() || it>=mq_t::MAX_ENTRIES; }
00291
00292 protected:
00293
00294 typedef ListMemBuf<entry,MAX_UNREAD,index_t> mq_t;
00295
00296
00297 mq_t mq;
00298 };
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 #endif //APERIOS check
00312
00313 #endif //INCLUDED
|