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 }