Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PollThread.cc

Go to the documentation of this file.
00001 #ifndef PLATFORM_APERIOS
00002 #include "PollThread.h"
00003 #include <errno.h>
00004 #include <signal.h>
00005 
00006 //better to put this here instead of the header
00007 using namespace std; 
00008 
00009 void PollThread::start() {
00010   launching=initialPoll=true;
00011   startTime.Set();
00012   Thread::start();
00013 }
00014 
00015 void PollThread::stop() {
00016   Thread::stop();
00017   interrupt(); // break thread out of any long sleep commands
00018 }
00019 
00020 void PollThread::interrupt() {
00021   if(launching) //can't interrupt before thread has been launched!
00022     return;
00023   if(signal(SIGALRM,handleInterrupt)==SIG_ERR)
00024     perror("PollThread::run(): initial signal()");
00025   sendSignal(SIGALRM);
00026 }
00027 
00028 bool PollThread::poll() {
00029   unsigned int sleeptime=runloop();
00030   if(sleeptime==-1U)
00031     return false;
00032   period.Set(static_cast<long>(sleeptime));
00033   return true;
00034 }
00035 
00036 void PollThread::interrupted() {
00037   if(!initialPoll) {
00038     if(period-startTime.Age()<1L) {
00039       delay=0L;
00040     } else {
00041       while(!(period-startTime.Age()<1L))
00042         startTime-=period;
00043       startTime+=period;
00044       delay=period;
00045     }
00046   }
00047 }
00048 
00049 void * PollThread::run() {
00050   launching=false;
00051   timespec sleepSpec,remainSpec;
00052   if(startTime.Age()<delay) {
00053     sleepSpec=delay-startTime.Age();
00054     while(nanosleep(&sleepSpec,&remainSpec)) {
00055       if(errno!=EINTR) {
00056         perror("PollThread::run(): initial nanosleep");
00057         break;
00058       }
00059       //interrupted() may have changed delay to indicate remaining sleep time
00060       if(delay<1L || delay<startTime.Age())
00061         break;
00062       sleepSpec=delay-startTime.Age();
00063     }
00064   }
00065   testCancel();
00066   if(!poll())
00067     return returnValue;
00068   initialPoll=false;
00069   bool wasInterrupted=true; // need to add delay instead of period for the first time, same as if an interrupt occurred
00070   for(;;) {
00071     bool noSleep=false;
00072     if(TimeET(0,0)<period) {
00073       if(trackPollTime) {
00074         if(wasInterrupted) {
00075           if(delay<0L || startTime.Age()<delay) {}
00076           else
00077             startTime+=delay;
00078         } else {
00079           if(startTime.Age()<period) {}
00080           else
00081             startTime+=period;
00082         }
00083         //the idea with this part is that if we get behind, (because of poll() taking longer than period)
00084         // then we want to quick poll again as fast as we can to catch up, but we don't want to backlog
00085         // such that we'll be quick-calling multiple times once we do catch up
00086         if(period<startTime.Age()) {
00087           noSleep=true;
00088           while(period<startTime.Age())
00089             startTime+=period;
00090           startTime-=period; //back off one -- the amount we've overshot counts towards the next period
00091         }
00092         sleepSpec=period-startTime.Age();
00093       } else {
00094         sleepSpec=period;
00095         startTime.Set();
00096       }
00097       wasInterrupted=false;
00098       while(!noSleep && nanosleep(&sleepSpec,&remainSpec)) {
00099         wasInterrupted=true;
00100         if(errno!=EINTR) {
00101           perror("PollThread::run(): periodic nanosleep");
00102           break;
00103         }
00104         //interrupted() should have changed delay and/or period to indicate remaining sleep time
00105         if(delay<1L || delay<startTime.Age())
00106           break;
00107         sleepSpec=delay-startTime.Age();
00108       }
00109     } else {
00110       startTime.Set();
00111     }
00112     testCancel();
00113     if(!poll())
00114       return returnValue;
00115   }
00116   // this return is just to satisfy warnings with silly compiler
00117   return returnValue; //never happens -- cancel or bad poll would exit
00118 }
00119 
00120 //void PollThread::cancelled() {
00121   //signal handlers are global, not per-thread, so if we reset the handler, then the next interrupt will cause the program to end :(
00122   //signal(SIGALRM,SIG_DFL);
00123 //}
00124 
00125 void PollThread::handleInterrupt(int /*signal*/) {
00126   if(signal(SIGALRM,SIG_DFL)==SIG_ERR)
00127     perror("PollThread::handleInterrupt(): could not re-enable signal");
00128   PollThread * cur=dynamic_cast<PollThread*>(Thread::getCurrent());
00129   if(cur==NULL) {
00130     std::cerr << "PollThread::handleInterrupt called from non-PollThread" << endl;
00131     return;
00132   }
00133   if(cur->noCancelDepth==0)
00134     cur->testCancel();
00135   cur->interrupted();
00136 }
00137 
00138 
00139 
00140 /*! @file
00141  * @brief 
00142  * @author Ethan Tira-Thompson (ejt) (Creator)
00143  *
00144  * $Author: ejt $
00145  * $Name: tekkotsu-3_0 $
00146  * $Revision: 1.10 $
00147  * $State: Exp $
00148  * $Date: 2006/08/07 21:55:27 $
00149  */
00150 #endif

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