Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

MessageReceiver.cc

Go to the documentation of this file.
00001 #ifndef PLATFORM_APERIOS
00002 
00003 #include "MessageReceiver.h"
00004 #include "Shared/debuget.h"
00005 //#include "local/sim/Process.h"
00006 //#include <iostream>
00007 //using namespace std;
00008 
00009 MessageReceiver::MessageReceiver(MessageQueueBase& mq, bool (*callback) (RCRegion*)/*=NULL*/, bool startThread/*=true*/, bool subscribe/*=true*/)
00010 : Thread(), queue(mq), semid(mq.getSemaphoreManager()->invalid()),
00011 nextMessage(0), lastProcessedMessage(-1U), process(callback), curit((index_t)-1)
00012 {
00013   if(startThread)
00014     start();
00015   else if(subscribe) {
00016     ASSERTRET(semid==queue.getSemaphoreManager()->invalid(),"semid is already set?");
00017     semid=queue.addReceiver();
00018     if(semid==queue.getSemaphoreManager()->invalid())
00019       std::cerr << "ERROR: could not start MessageReceiver -- out of semaphore IDs" << std::endl;
00020   }
00021 }
00022 
00023 MessageReceiver::~MessageReceiver() {
00024   if(!isStarted())
00025     return;
00026   stop();
00027   join();
00028   queue.removeReceiver(semid);
00029   semid=queue.getSemaphoreManager()->invalid();
00030 }
00031 
00032 RCRegion * MessageReceiver::peekNextMessage() {
00033   MessageQueueBase::AutoLock autolock(queue.getLock());
00034   findCurrentMessage();
00035   if(queue.isEnd(curit))
00036     return NULL;
00037   return queue.peekMessage(curit);
00038 }
00039 
00040 RCRegion * MessageReceiver::getNextMessage() {
00041   MessageQueueBase::AutoLock autolock(queue.getLock());
00042   findCurrentMessage();
00043   if(queue.isEnd(curit))
00044     return NULL;
00045   nextMessage=queue.getMessageSN(curit)+1;
00046   curit=queue.newer(curit); //next time, start on (or peek at) the one after this
00047   return queue.readMessage(curit,semid);
00048 }
00049 
00050 void MessageReceiver::stop() {
00051   Thread::stop();
00052   queue.getSemaphoreManager()->raise(semid,1); //trigger a check so the thread will notice the stop
00053 }
00054 
00055 void MessageReceiver::findCurrentMessage() {
00056   if(queue.isEnd(curit)) {
00057     curit=queue.newest(); //start with the newest
00058     while(!queue.isEnd(curit) && queue.getMessageSN(curit)>=nextMessage)
00059       curit=queue.older(curit); //scan back to the first already read by this process
00060     curit=queue.newer(curit); //go to the following one (first unread)
00061   } else {
00062     while(!queue.isEnd(curit) && queue.getMessageSN(curit)<nextMessage)
00063       curit=queue.newer(curit); //scan forward to next message not read by this process
00064   }
00065 }
00066 
00067 void MessageReceiver::finish() {
00068   if(isStarted()) {
00069     stop();
00070     join();
00071   }
00072   if(semid!=queue.getSemaphoreManager()->invalid()) {
00073     //cout << Process::getName() << " finish" << endl;
00074     while(processNextMessage()) {}
00075     queue.removeReceiver(semid);
00076     semid=queue.getSemaphoreManager()->invalid();
00077   }
00078 }
00079 
00080 bool MessageReceiver::launched() {
00081   if(semid==queue.getSemaphoreManager()->invalid())
00082     semid=queue.addReceiver();
00083   if(semid==queue.getSemaphoreManager()->invalid()) {
00084     std::cerr << "ERROR: could not start MessageReceiver -- out of semaphore IDs" << std::endl;
00085     return false;
00086   }
00087   return Thread::launched();
00088 }
00089 
00090 unsigned int MessageReceiver::runloop() {
00091   //cout << Process::getName() << " runloop" << endl;
00092   pushNoCancel();
00093   waitNextMessage();
00094   while(processNextMessage()) { //get everything else in the queue
00095     queue.getSemaphoreManager()->lower(semid,1,false);
00096   }
00097   popNoCancel();
00098   return 0;
00099 }
00100 
00101 bool MessageReceiver::waitNextMessage() {
00102   return queue.getSemaphoreManager()->lower(semid,1,true);
00103 }
00104 
00105 bool MessageReceiver::processNextMessage() {
00106   RCRegion * msg=peekNextMessage();
00107   if(msg==NULL)
00108     return false;
00109   //cout << Process::getName() << " got " << msg->ID().key << ' ' << lastProcessedMessage << ' ' << queue.getMessageSN(curit) << ' ' << curit << endl;
00110   bool used=false;
00111   if(lastProcessedMessage!=queue.getMessageSN(curit)) {
00112     lastProcessedMessage=queue.getMessageSN(curit);
00113     //cout << Process::getName() << " process received " << lastProcessedMessage << " at " << TimeET() << endl;
00114     used=process(msg);
00115     if(used)
00116       markRead(false); // message was consumed, mark it read
00117     //cout << used << ' ' << curit;
00118     //if(!queue.isEnd(curit))
00119     //cout << lastProcessedMessage << ' ' << queue.getMessageSN(curit);
00120     //cout << endl;
00121   }
00122   msg->RemoveReference();
00123   return used;
00124 }
00125 
00126 void MessageReceiver::markRead(bool checkNext) {
00127   findCurrentMessage();
00128   if(queue.isEnd(curit))
00129     return;
00130   nextMessage=queue.getMessageSN(curit)+1;
00131   queue.markRead(curit,semid);
00132   curit=queue.newer(curit); //next time, start on (or peek at) the one after this
00133   if(checkNext && !queue.isEnd(curit))
00134     queue.getSemaphoreManager()->raise(semid,1); //trigger a check if there are more waiting in the queue
00135 }
00136 
00137 
00138 
00139 /*! @file
00140  * @brief 
00141  * @author Ethan Tira-Thompson (ejt) (Creator)
00142  *
00143  * $Author: ejt $
00144  * $Name: tekkotsu-4_0 $
00145  * $Revision: 1.13 $
00146  * $State: Exp $
00147  * $Date: 2007/10/12 16:55:04 $
00148  */
00149 
00150 #endif //PLATFORM_APERIOS check (aperios doesn't support pthreads...)

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