marclock.cpp

Go to the documentation of this file.
00001 #include "marclock.h"
00002 
00003 #include <stdio.h>
00004 #include <signal.h>
00005 #include <sys/time.h>
00006 #include <unistd.h>
00007 #include <stdlib.h>
00008 
00009 #define MAXCLQUEUE      100
00010 #define HEART_GRAIN     (0.1)   /* timer grain */
00011 
00012 int     heartbeat_grain_sec = 0;
00013 int     heartbeat_grain_usec = 100000;
00014 int     heartbeat_fast_sec = 0;
00015 int     heartbeat_fast_usec = 20000;
00016 
00017 struct clq_st {
00018   int           clq_used;       /* 0 if currently not used, else 1 */
00019   int           clq_ival;       /* interval timer value */
00020   struct clq_st *clq_prev;      /* pointer to prev quque entry */
00021   struct clq_st *clq_next;      /* pointer to next quque entry */
00022   void          (*clq_fcn)(int);/* fcn to execute on when ival = 0 */
00023   int           clq_arg;        /* argument to the above function */
00024 };
00025 
00026 typedef struct clq_st   clq;
00027 
00028 clq     *clqhead;               /* points to first queue entry */
00029 clq     clqueue[MAXCLQUEUE];    /* array containing the clock queue */
00030 int     block_heartbeat;        /* 1 to temporarily block clock heartbeat */
00031 int     clq_is_init = 0;        /* 1 if queues are initialized */
00032 
00033 double  heartbeat_grain = HEART_GRAIN;
00034 
00035 // void set_timer_params();
00036 // void start_timer();
00037 // void set_timer_grain();
00038 // void enqueue_fcn(void (*fcn)(int), int arg, double dtval);
00039 // void clock_heartbeat();
00040 // void init_clock();
00041 
00042 MarClock::MarClock(QObject *parent)
00043   : inherited(parent)
00044 {
00045 }
00046 
00047 /******************************************************************
00048  * Function: mar_heartbeat
00049  ******************************************************************/
00050 void
00051 MarClock::mar_heartbeat(int)
00052 {
00053   /*
00054    * Re-enable the timer, and return.
00055    */
00056   enqueue_fcn(mar_heartbeat,0,1.0);
00057 }
00058 
00059 /******************************************************************
00060  * Function: mar_clock
00061  ******************************************************************/
00062 void
00063 MarClock::mar_clock()
00064 {
00065   int           i, killtimer = 0;
00066 
00067   enqueue_fcn(mar_heartbeat,0,1.0);
00068   //  enqueue_fcn((void (*)(int))get_status,0,1.0);
00069 
00070   init_clock();
00071 
00072   while(killtimer == 0) {
00073     pause();
00074   }
00075 }
00076 
00077 
00078 /******************************************************************
00079  * Function: set_timer_params
00080  ******************************************************************/
00081 void
00082 MarClock::set_timer_params(double val)
00083 {
00084   double        x;
00085   int   i;
00086 
00087   x = val;
00088   i = (int) x;
00089   heartbeat_grain_sec = i;
00090   x = x - i;
00091   if(x < 0) x = 0;
00092   i = x * 1000000;
00093   heartbeat_grain_usec = i;
00094 
00095   x = val / 5;  /* for the fast timer on heartbeat block */
00096   i = (int) x;
00097   heartbeat_fast_sec = i;
00098   x = x - i;
00099   if(x < 0) x = 0;
00100   i = x * 1000000;
00101   heartbeat_fast_usec = i;
00102 
00103   return;
00104 }
00105 
00106 /******************************************************************
00107  * Function: start_timer
00108  ******************************************************************/
00109 void
00110 MarClock::start_timer(void (*fcn)(int), int speed)
00111 {
00112   struct        itimerval       tv;
00113 
00114   tv.it_interval.tv_sec = 0;
00115   tv.it_interval.tv_usec = 0;
00116   if(speed == 0)
00117     {
00118       tv.it_value.tv_sec = heartbeat_fast_sec;
00119       tv.it_value.tv_usec = heartbeat_fast_usec;
00120     }
00121   else
00122     {
00123       tv.it_value.tv_sec = heartbeat_grain_sec;
00124       tv.it_value.tv_usec = heartbeat_grain_usec;
00125     }
00126 
00127   signal(SIGALRM,fcn);
00128 
00129   setitimer(ITIMER_REAL,&tv,NULL);
00130 }
00131 
00132 /******************************************************************
00133  * Function: set_timer_grain
00134  ******************************************************************/
00135 void
00136 MarClock::set_timer_grain(double val)
00137 {
00138   heartbeat_grain = val;
00139 
00140   set_timer_params(val);
00141 }
00142 
00143 
00144 /******************************************************************
00145  * Function: enqueue_fcn  
00146  ******************************************************************/
00147 void
00148 MarClock::enqueue_fcn(void (*fcn)(int), int arg, double dtval)
00149 {
00150   int   i,j;
00151   clq   *qp;
00152 
00153   block_heartbeat = 1;
00154   if(clq_is_init == 0)
00155     {
00156       clqhead = NULL;
00157       for(i = 0;i < MAXCLQUEUE; i++)
00158         clqueue[i].clq_used = 0;
00159       clq_is_init = 1;
00160     }
00161   for(i = 0;i < MAXCLQUEUE;i++)
00162     if(clqueue[i].clq_used == 0)
00163       {
00164         clqueue[i].clq_used = 1;
00165         j = .5 + dtval / heartbeat_grain;
00166         if(j == 0) j = 1;
00167         clqueue[i].clq_ival = j;
00168         clqueue[i].clq_fcn = fcn;
00169         clqueue[i].clq_arg = arg;
00170         clqueue[i].clq_next = NULL;
00171         if(clqhead == NULL)
00172           {
00173             clqhead = &clqueue[i];
00174             clqueue[i].clq_prev = NULL;
00175             block_heartbeat = 0;
00176             return;
00177           }
00178         for(qp = clqhead; ; qp = qp->clq_next)
00179           if(qp->clq_next == NULL)
00180             {
00181               qp->clq_next = &clqueue[i];
00182               clqueue[i].clq_prev = qp;
00183               block_heartbeat = 0;
00184               return;
00185             }
00186       }
00187   fprintf(stdout,"enqueue_fcn:  no more clock queue entries avail\n");
00188   ::exit(1);
00189 }
00190 
00191 
00192 /******************************************************************
00193  * Function: clock_heartbeat
00194  ******************************************************************/
00195 void
00196 MarClock::clock_heartbeat(int)
00197 {
00198   clq                   *qp;
00199 
00200   if(block_heartbeat == 1)
00201     {
00202       /*
00203        *        If the heartbeat is blocked (e.g., by the enqueue_fcn
00204        *        routine), then we just re-enable the timer to be called
00205        *        again in 1/5th the normal clock grain.  Since functions
00206        *        which block heartbeat must be quick, this fast time
00207        *        will cause sucessful execution on the next timer callout.
00208        */
00209 
00210       start_timer(clock_heartbeat,0);
00211 
00212       return;
00213     }
00214 
00215   if(clqhead == NULL)
00216     {
00217       /*
00218        *        There are no functions queued for execution.  Depending
00219        *        on how the application which uses these routines is
00220        *        written, this condition may indicate an error.  In a
00221        *        completely clock callout driver application, this should
00222        *        happen ONLY before the first callout is queued, and never
00223        *        again.  Since there are other ways to use these routines,
00224        *        we don't flag an error here.
00225        */
00226 
00227       start_timer(clock_heartbeat,1);
00228 
00229       return;
00230     }
00231 
00232   /*
00233    *    Decrement the clq_ival variables in all active queue
00234    *    entries.  Do not decrement any entries whose clq_ival
00235    *    has already gone to zero.  These will executed on a
00236    *    first come, first served basis.
00237    */
00238   for(qp = clqhead; qp != NULL; qp = qp->clq_next)
00239     {
00240       if(qp->clq_ival > 0)
00241         qp->clq_ival--;
00242     }
00243         
00244   /*
00245    *    Queue the next heartbeat now.
00246    */
00247         
00248   start_timer(clock_heartbeat,1);
00249 
00250   /*
00251    *    Find the first entry in the queue whose clq_ival value
00252    *    is zero.  Unqueue it and execute it.
00253    */
00254 
00255   for(qp = clqhead; qp != NULL; qp = qp->clq_next)
00256     if(qp->clq_ival == 0)
00257       {
00258         if(qp->clq_prev == NULL)
00259           {
00260             clqhead = qp->clq_next;
00261             if(qp->clq_next != NULL)
00262               (qp->clq_next)->clq_prev = NULL;
00263           }
00264         else
00265           {
00266             (qp->clq_prev)->clq_next = qp->clq_next;
00267             if(qp->clq_next != NULL)
00268               (qp->clq_next)->clq_prev = qp->clq_prev;
00269           }
00270 
00271         qp->clq_used = 0;
00272 
00273         (void) (*qp->clq_fcn)(qp->clq_arg);
00274 
00275         return;
00276       }
00277   return;
00278 }
00279 
00280 
00281 /******************************************************************
00282  * Function: void init_clock
00283  ******************************************************************/
00284 void
00285 MarClock::init_clock()
00286 {
00287   int                   i;
00288 
00289   if(clq_is_init == 0)
00290     {
00291       clqhead = NULL;
00292       for(i = 0;i < MAXCLQUEUE; i++)
00293         clqueue[i].clq_used = 0;
00294       clq_is_init = 1;
00295     }
00296 
00297   set_timer_params(heartbeat_grain);
00298 
00299   start_timer(clock_heartbeat,1);
00300 }