/ src / libnml / os_intf / timer.cc
timer.cc
  1  /********************************************************************
  2  * Description: timer.cc
  3  *   A TIMER object lets you wait on the expiration of a cyclic
  4  *   period, to the resolution of the system clock.
  5  *
  6  *   Derived from a work by Fred Proctor & Will Shackleford
  7  *
  8  * Author:
  9  * License: LGPL Version 2
 10  * System: Linux
 11  *    
 12  * Copyright (c) 2004 All rights reserved.
 13  *
 14  * Last change: 
 15  ********************************************************************/
 16  
 17  extern "C" {
 18  #include <stdlib.h>		// atof()
 19  #include <string.h>		// strtok(), strncmp()
 20  #include <stdio.h>		/* NULL */
 21  
 22  #include <stdlib.h>		/* exit() */
 23  #include <signal.h>		/* struct sigaction, sigaction(), SIGALRM,
 24  				   sigset_t */
 25  #include <errno.h>		/* perror(), EINTR */
 26  #include <unistd.h>		/* select(), sysconf(), _SC_CLK_TCK */
 27  #include <sys/time.h>		/* struct timeval, gettimeofday(), struct
 28  				   itimerval, setitimer(), ITIMER_REAL */
 29  #include <sys/types.h>
 30  #include <sys/wait.h>		// waitpid()
 31  }
 32  
 33  #include "timer.hh"
 34  #include "_timer.h"
 35  
 36  /* RCS_TIMER class */
 37  RCS_TIMER::RCS_TIMER(const char *process_name, const char *config_file)
 38  {
 39      zero_timer();
 40      set_timeout(0);
 41  }
 42  
 43  RCS_TIMER::RCS_TIMER(double _timeout, const char *process_name, const char *config_file)
 44  {
 45      zero_timer();
 46      set_timeout(_timeout);
 47  }
 48  
 49  void
 50    RCS_TIMER::set_timeout(double _timeout)
 51  {
 52      timeout = _timeout;
 53      if (timeout < clk_tck()) {
 54  	counts_per_real_sleep = (int) (clk_tck() / _timeout) + 1;
 55      } else {
 56  	counts_per_real_sleep = 0;
 57      }
 58  }
 59  
 60  
 61  void RCS_TIMER::zero_timer()
 62  {
 63      num_sems = 0;
 64  #if USE_SEMS_FOR_TIMER
 65      sems = NULL;
 66  #endif
 67      id = 0;
 68      function = NULL;
 69      arg = NULL;
 70      last_time = etime();	/* initialize start time and last time called
 71  				   to current time since epoch */
 72      idle = 0.0;			/* set accumulated idle time to 0.0 */
 73      counts = 0;			/* set accumulated waits to 0 */
 74      start_time = etime();	/* set creation time to now */
 75      time_since_real_sleep = start_time;
 76      counts_per_real_sleep = 0;
 77      counts_since_real_sleep = 0;
 78      clk_tck_val = clk_tck();
 79      timeout = clk_tck_val;
 80  }
 81  
 82  void RCS_TIMER::init(double _timeout, int _id)
 83  {
 84      zero_timer();
 85      id = _id;
 86      set_timeout(_timeout);
 87  
 88  }
 89  
 90  RCS_TIMER::RCS_TIMER(double _timeout, RCS_TIMERFUNC _function, void *_arg)
 91  {
 92      zero_timer();
 93      counts_per_real_sleep = 0;
 94      counts_since_real_sleep = 0;
 95  
 96      if (_timeout < clk_tck_val) {
 97  	counts_per_real_sleep = (int) (clk_tck_val / _timeout);
 98  	/* bump interval up to minimum system clock tick */
 99  	timeout = clk_tck_val;
100      } else {
101  	timeout = _timeout;
102      }
103      function = _function;
104      arg = _arg;
105      time_since_real_sleep = start_time;
106  }
107  
108  /* Restart the timing interval. */
109  void
110    RCS_TIMER::sync()
111  {
112      last_time = etime();	/* initialize start time and last time called
113  				   to current time since epoch */
114  }
115  
116  int RCS_TIMER::wait()
117  {
118      double interval;		/* interval between this and last wakeup */
119      double numcycles;		/* interval, in units of timeout */
120      int missed = 0;		/* cycles missed */
121      double remaining = 0.0;	/* time remaining until timeout */
122      double time_in = 0.0;	/* time wait() was entered */
123      double time_done = 0.0;	/* time user function finished */
124      /* first call the user timing function, if any */
125      if (function != NULL) {
126  	/* set time in */
127  	time_in = etime();
128  
129  	if ((*function) (arg) == -1) {
130  	    return -1;		/* fatal error in timing function */
131  	}
132  	time_done = etime();
133      } else {
134  	/* set time in, time done not used */
135  	time_in = etime();
136      }
137  
138      /* calculate the interval-- for user timing functions, this is how long
139         between this wakeup and the last wakeup.  For internal timers, this is 
140         how long we need to sleep to make it to the next interval on time. */
141      interval = time_in - last_time;
142      numcycles = interval / timeout;
143  
144      /* synchronize and set last_time correctly; update idle time */
145      counts++;
146      if (function != NULL) {
147  	missed = (int) (numcycles - (clk_tck_val / timeout));
148  	idle += interval;
149  	last_time = time_done;
150          remaining = 0.0;
151      } else {
152  	missed = (int) (numcycles); 
153  	remaining = timeout * (1.0 - (numcycles - (int) numcycles));
154  	idle += interval;
155      }
156      esleep(remaining);
157      last_time = etime();
158      return missed;
159  }
160  
161  double RCS_TIMER::load()
162  {
163      if (counts * timeout != 0.0)
164  	return idle / (counts * timeout);
165      return -1.0;
166  }
167  
168  RCS_TIMER::~RCS_TIMER()
169  {
170  }