Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

timer.cc

Go to the documentation of this file.
00001 /*
00002   timer.cc -- interval timer code.  A TIMER object lets you wait on
00003   the expiration of a cyclic period, to the resolution of the system
00004   clock.
00005 
00006   Ideally, we'd like to use the POSIX struct timespec, in timers.h,
00007   for second-nanosecond resolution in real time.  However, at the
00008   moment, most OSes do not have this interface since the POSIX realtime
00009   draft is still out.
00010 
00011   These functions use the BSD 'gettimeofday' interface for LynxOS and
00012   SunOS, and the tickLib and taskLib interface on VxWorks.
00013   */
00014 
00015 
00016 #include "rcs_defs.hh"          // __MSDOS__
00017 #include "dbg_mem.h"            // DEBUG_MALLOC,DEBUG_FREE
00018 
00019 #ifdef VXWORKS
00020 
00021 extern "C"
00022 {
00023 #include <vxWorks.h>
00024 
00025 #ifndef NO_STDIO
00026 #include <stdio.h>
00027 #endif
00028 
00029 #include <string.h>             // strtok(), strncmp()
00030 #include <stdlib.h>             // atof()
00031 #include <taskLib.h>            /* taskDelay() */
00032 #include <tickLib.h>            /* tickGet() */
00033 #include <sysLib.h>             /* sysClkRateGet() */
00034 }
00035 
00036 #endif                          /* VXWORKS */
00037 
00038 #ifdef LYNX
00039 
00040 extern "C"
00041 {
00042 #include <string.h>             // strtok(), strncmp()
00043 #include <stdlib.h>             // atof()
00044 
00045 #ifndef NO_STDIO
00046 #include <stdio.h>              /* NULL */
00047 #endif
00048 
00049 #include <stdlib.h>             /* exit() */
00050 #include <signal.h>             /* struct sigaction, sigaction(), SIGALRM,
00051                                    sigset_t */
00052 #include <errno.h>              /* perror(), EINTR */
00053 #include <unistd.h>             /* select() */
00054 #include <time.h>               /* CLK_TCK, since no _SC_CLK_TCK, */
00055   /* setitimer() */
00056 #include <sys/time.h>           /* struct timeval, gettimeofday(),
00057                                    struct itimerval,
00058                                    ITIMER_REAL */
00059 
00060 }
00061 
00062 #endif                          /* LYNX */
00063 
00064 #if defined(SUN) || defined(LINUX)
00065 
00066 extern "C"
00067 {
00068 #include <stdlib.h>             // atof()
00069 #include <string.h>             // strtok(), strncmp()
00070 
00071 #ifndef NO_STDIO
00072 #include <stdio.h>              /* NULL */
00073 #endif
00074 
00075 #include <stdlib.h>             /* exit() */
00076 #include <signal.h>             /* struct sigaction, sigaction(), SIGALRM,
00077                                    sigset_t */
00078 #include <errno.h>              /* perror(), EINTR */
00079 #include <unistd.h>             /* select(), sysconf(), _SC_CLK_TCK */
00080 #include <sys/time.h>           /* struct timeval, gettimeofday(),
00081                                    struct itimerval, setitimer(),
00082                                    ITIMER_REAL */
00083 #include <sys/types.h>
00084 #include <sys/wait.h>           // waitpid()
00085 }
00086 
00087 #endif                          /* SUN */
00088 
00089 #ifdef __MSDOS__
00090 #include <stdlib.h>             // atof()
00091 #include <string.h>             // strtok(), strncmp()
00092 #include <time.h>               /* clock(), CLK_TCK */
00093 #ifndef _WINDOWS
00094 #include <dos.h>                /* delay() */
00095 #endif
00096 #endif
00097 
00098 #include "inetfile.hh"          // inet_file_open(), inet_file_gets()
00099 
00100 #include "timer.hh"
00101 
00102 #define INT(x) ((int) (x))
00103 #define FRAC(x) ((x) - INT(x))
00104 
00105 
00106 #if (defined (SUN) || defined (LYNX)) && !defined(lynxosVME)  && !defined(sunos4CC)
00107 
00108 /* set up SIGALRM to go off after time, either once or periodically */
00109 int
00110 itimer_set (double time, int periodic)
00111 {
00112   struct itimerval val;
00113   long secs, usecs;
00114 
00115   /* set up the interval timer */
00116   secs = (long) time;           /* lose the fraction */
00117   usecs = (long) ((time - (double) secs) * 1000000.0);
00118   val.it_value.tv_sec = secs;
00119   val.it_value.tv_usec = usecs;
00120   if (periodic == 0)
00121     {
00122       val.it_interval.tv_sec = val.it_interval.tv_usec = 0;
00123     }
00124   else
00125     {
00126       val.it_interval.tv_sec = val.it_value.tv_sec;
00127       val.it_interval.tv_usec = val.it_value.tv_usec;
00128     }
00129   return setitimer (ITIMER_REAL, &val, 0);
00130 }
00131 
00132 /* do-nothing default function for itimer_attach() */
00133 static void
00134 noaction (...)
00135 {
00136   return;
00137 }
00138 
00139 /* attach a function to the SIGALRM handler */
00140 void
00141 itimer_attach (RCS_SIGFUNC function)
00142 {
00143   struct sigaction act;
00144 
00145   /* set up action to occur upon receipt of SIGALRM-- call function */
00146 #ifdef sparcworks_sun4
00147   act.sa_handler =
00148     (void (*)(int,...)) ((function == NULL) ? noaction : function);
00149 #else
00150 #if defined(sparcworks_sun5) || defined(sunos5CC)       /* CenterLine is picky, picky, picky */
00151   act.sa_handler = (void (*)(int)) ((function == NULL) ? noaction : function);
00152 #else
00153   act.sa_handler = ((function == NULL) ? noaction : function);
00154 #endif
00155 #endif
00156   sigfillset (&act.sa_mask);    /* mask all signals while in SIGALRM */
00157   act.sa_flags = 0;             /* no special flags */
00158   sigaction (SIGALRM, &act, NULL);
00159 }
00160 
00161 /* block on arrival of SIGALRM */
00162 void
00163 itimer_wait ()
00164 {
00165   sigset_t mask;
00166 
00167   /* set up to block on SIGALRM */
00168   sigfillset (&mask);           /* block all signals */
00169   sigdelset (&mask, SIGALRM);   /* accept SIGALRM */
00170   sigsuspend (&mask);           /* block until SIGALRM is received */
00171 }
00172 
00173 #endif /* SUN or LYNX */
00174 
00175 
00176 /* RCS_TIMER class */
00177 RCS_TIMER::RCS_TIMER (char *process_name, char *config_file)
00178 {
00179 #if 0
00180   read_config_file (process_name, config_file);
00181 #endif
00182 }
00183 
00184 RCS_TIMER::RCS_TIMER (double _timeout, char *process_name, char *config_file)
00185 {
00186 #if 0
00187   read_config_file (process_name, config_file);
00188 #endif
00189   set_timeout (_timeout);
00190 }
00191 
00192 void
00193 RCS_TIMER::set_timeout (double _timeout)
00194 {
00195   timeout = _timeout;
00196   if (timeout < clk_tck ())
00197     {
00198       counts_per_real_sleep = (int) (clk_tck () / _timeout) + 1;
00199     }
00200   else
00201     {
00202       counts_per_real_sleep = 0;
00203     }
00204 }
00205 
00206 #if 0
00207 void
00208 RCS_TIMER::read_config_file (char *process_name, char *config_file)
00209 {
00210   zero_timer ();
00211   if (NULL == process_name || NULL == config_file)
00212     {
00213       return;
00214     }
00215   INET_FILE *ifp = inet_file_open (config_file, "r");
00216   if (NULL == ifp)
00217     {
00218       return;
00219     }
00220   int process_name_length = strlen (process_name);
00221   char line[256];
00222   char *token;
00223   while (!inet_file_eof (ifp))
00224     {
00225       inet_file_gets (line, 256, ifp);
00226       token = strtok (line, " \r\n:\t\b,;");
00227       if (line[0] == '#')
00228         {
00229           continue;
00230         }
00231       if (token == NULL)
00232         {
00233           continue;
00234         }
00235       if (strncmp (token, process_name, process_name_length))
00236         {
00237           continue;
00238         }
00239       token = strtok (NULL, " \r\n:\t\b,;");
00240       if (NULL == token)
00241         {
00242           break;
00243         }
00244       timeout = atof (token);
00245       token = strtok (NULL, " \r\n:\t\b,;");
00246       if (NULL == token)
00247         {
00248           break;
00249         }
00250 #if 0
00251       sem_key = strtol (token, NULL, 0);
00252       token = strtok (NULL, " \r\n:\t\b,;");
00253       if (NULL == token)
00254         {
00255           break;
00256         }
00257       num_sems = strtol (token, NULL, 0);
00258       token = strtok (NULL, " \r\n:\t\b,;");
00259       if (NULL == token)
00260         {
00261           break;
00262         }
00263 #endif
00264       id = strtol (token, NULL, 0);
00265       token = strtok (NULL, " \r\n:\t\b,;");
00266       if (NULL == token)
00267         {
00268           break;
00269         }
00270 #if 0
00271       create_sems = strtol (token, NULL, 0);
00272 #endif
00273     }
00274   inet_file_close (ifp);
00275   init (timeout, id);
00276 }
00277 #endif
00278 
00279 
00280 
00281 void
00282 RCS_TIMER::zero_timer ()
00283 {
00284   num_sems = 0;
00285 #if USE_SEMS_FOR_TIMER
00286   sems = NULL;
00287 #endif
00288   id = 0;
00289   function = NULL;
00290   idle = 0.0;                   /* set accumulated idle time to 0.0 */
00291   counts = 0;                   /* set accumulated waits to 0 */
00292   start_time = etime ();        /* set creation time to now */
00293   time_since_real_sleep = start_time;
00294   counts_per_real_sleep = 0;
00295   counts_since_real_sleep = 0;
00296   clk_tck_val = clk_tck ();
00297   timeout = clk_tck_val;
00298 }
00299 
00300 
00301 
00302 void
00303 RCS_TIMER::init (double _timeout, int _id)
00304 {
00305   zero_timer ();
00306   id = _id;
00307 #if 0
00308   num_sems = _num_sems;
00309   int sem_key = _sem_key;
00310   int create_sems = _create_sems;
00311   if (num_sems > 0 && id >= 0 && id < num_sems)
00312     {
00313       sems =
00314         (RCS_SEMAPHORE **) DEBUG_MALLOC (sizeof (RCS_SEMAPHORE *) * num_sems);
00315       for (int i = 0; i < num_sems; i++)
00316         {
00317           sems[i] = new RCS_SEMAPHORE (sem_key + i, create_sems, -1);
00318         }
00319       sems[id]->post ();
00320       poller_pid = fork ();
00321       if (poller_pid == 0)
00322         {
00323           timer_poll (_timeout, sems[id]);
00324         }
00325     }
00326   else
00327     {
00328       num_sems = 0;
00329     }
00330 #endif
00331   set_timeout (_timeout);
00332 
00333 }
00334 
00335 
00336 
00337 RCS_TIMER::RCS_TIMER (double _timeout, RCS_TIMERFUNC _function, void *_arg)
00338 {
00339   zero_timer ();
00340   counts_per_real_sleep = 0;
00341   counts_since_real_sleep = 0;
00342 
00343   if (_timeout < clk_tck_val)
00344     {
00345       counts_per_real_sleep = (int) (clk_tck_val / _timeout);
00346       /* bump interval up to minimum system clock tick */
00347       timeout = clk_tck_val;
00348     }
00349   else
00350     {
00351       timeout = _timeout;
00352     }
00353   function = _function;
00354   arg = _arg;
00355   last_time = etime ();         /* initialize start time and last time called
00356                                    to current time since epoch */
00357   idle = 0.0;                   /* set accumulated idle time to 0.0 */
00358   counts = 0;                   /* set accumulated waits to 0 */
00359   start_time = etime ();        /* set creation time to now */
00360   time_since_real_sleep = start_time;
00361 }
00362 
00363 /* Restart the timing interval. */
00364 void
00365 RCS_TIMER::sync ()
00366 {
00367   last_time = etime ();         /* initialize start time and last time called
00368                                    to current time since epoch */
00369 }
00370 
00371 int
00372 RCS_TIMER::wait ()
00373 {
00374   double interval;              /* interval between this and last wakeup */
00375   double numcycles;             /* interval, in units of timeout */
00376   int missed = 0;               /* cycles missed */
00377   double remaining = 0.0;       /* time remaining until timeout */
00378   double time_in = 0.0;         /* time wait() was entered */
00379   double time_done = 0.0;       /* time user function finished */
00380   /* first call the user timing function, if any */
00381   if (function != NULL)
00382     {
00383       /* set time in */
00384       time_in = etime ();
00385 
00386       if ((*function) (arg) == -1)
00387         {
00388           return -1;            /* fatal error in timing function */
00389         }
00390       time_done = etime ();
00391     }
00392   else
00393     {
00394       /* set time in, time done not used */
00395       time_in = etime ();
00396     }
00397 
00398   /* calculate the interval-- for user timing functions, this is how
00399      long between this wakeup and the last wakeup.  For internal timers,
00400      this is how long we need to sleep to make it to the next interval
00401      on time. */
00402   interval = time_in - last_time;
00403   numcycles = interval / timeout;
00404 
00405   /* synchronize and set last_time correctly; update idle time */
00406   counts++;
00407   if (function != NULL)
00408     {
00409       missed = INT (numcycles - (clk_tck_val / timeout));
00410       idle += interval;
00411       last_time = time_done;
00412     }
00413   else
00414     {
00415       missed = INT (numcycles);
00416       remaining = timeout * (1.0 - FRAC (numcycles));
00417       idle += interval;
00418 #if 0
00419       if (counts_per_real_sleep > 0)
00420         {
00421           if (counts_since_real_sleep < counts_per_real_sleep)
00422             {
00423               counts_since_real_sleep++;
00424               if (sems != NULL && num_sems > 0)
00425                 {
00426                   for (i = id + 1; i < num_sems && !sem_posted; i++)
00427                     {
00428                       if (i != id && NULL != sems[i])
00429                         {
00430                           if (sems[i]->post () < 0)
00431                             {
00432                               delete sems[i];
00433                               sems[i] = NULL;
00434                               if (i == num_sems - 1)
00435                                 {
00436                                   num_sems--;
00437                                 }
00438                             }
00439                           else
00440                             {
00441                               sem_posted = 1;
00442                             }
00443                         }
00444                     }
00445                   for (i = 0; i < id && !sem_posted; i++)
00446                     {
00447                       if (i != id && NULL != sems[i])
00448                         {
00449                           if (sems[i]->post () < 0)
00450                             {
00451                               delete sems[i];
00452                               sems[i] = NULL;
00453                               if (i == num_sems - 1)
00454                                 {
00455                                   num_sems--;
00456                                 }
00457                             }
00458                           else
00459                             {
00460                               sem_posted = 1;
00461                             }
00462                         }
00463                     }
00464                   if (NULL != sems[id] && sem_posted)
00465                     {
00466                       if (sems[id]->wait () < 0)
00467                         {
00468                           delete sems[id];
00469                           sems[id] = NULL;
00470                           return 0;
00471                         }
00472                       while (etime () - time_in < remaining)
00473                         {
00474                           if (sems[id]->wait () < 0)
00475                             {
00476                               delete sems[id];
00477                               sems[id] = NULL;
00478                               break;
00479                             }
00480                         }
00481                       for (i = 0; i < num_sems; i++)
00482                         {
00483                           if (i != id && NULL != sems[i])
00484                             {
00485                               sems[i]->clear ();
00486                             }
00487                         }
00488                     }
00489                   return 0;
00490                 }
00491             }
00492           counts_since_real_sleep = 0;
00493           time_since_real_sleep = etime ();
00494           esleep (clk_tck_val);
00495           last_time = etime ();
00496           return missed;
00497         }
00498 #endif
00499     }
00500   esleep (remaining);
00501   last_time = etime ();
00502   return missed;
00503 }
00504 
00505 double
00506 RCS_TIMER::load ()
00507 {
00508   if (counts * timeout != 0.0)
00509     return idle / (counts * timeout);
00510   return -1.0;
00511 }
00512 
00513 RCS_TIMER::~RCS_TIMER ()
00514 {
00515 #if 0
00516   if (poller_pid > 0)
00517     {
00518       kill (poller_pid, SIGINT);
00519 #ifdef SUN
00520       waitpid (poller_pid, NULL, 0);
00521 #endif
00522       poller_pid = 0;
00523     }
00524   if (NULL != sems)
00525     {
00526       for (int i = 0; i < num_sems; i++)
00527         {
00528           if (sems[i] != NULL)
00529             {
00530               delete sems[i];
00531             }
00532           sems[i] = NULL;
00533         }
00534       DEBUG_FREE (sems);
00535     }
00536 #endif
00537 }

Generated on Sun Dec 2 15:56:53 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001