timer.cc Source File

Back to the index.

timer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2018 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * Timer framework. This is used by emulated clocks.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/time.h>
37 
38 #include "misc.h"
39 #include "timer.h"
40 
41 
42 /* #define TEST */
43 
44 
45 struct timer {
46  struct timer *next;
47 
48  double freq;
49  void (*timer_tick)(struct timer *timer, void *extra);
50  void *extra;
51 
52  double interval;
53  double next_tick_at;
54 };
55 
56 static struct timer *first_timer = NULL;
57 struct timeval timer_start_tv;
58 static double timer_freq;
59 static int timer_countdown_to_next_gettimeofday;
60 static double timer_current_time;
61 static double timer_current_time_step;
62 
63 static int timer_is_running;
64 
65 #define SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH 1.65
66 
67 
68 /*
69  * timer_add():
70  *
71  * Adds a virtual timer to the list of timers.
72  *
73  * Return value is a pointer to a timer struct.
74  */
75 struct timer *timer_add(double freq, void (*timer_tick)(struct timer *timer,
76  void *extra), void *extra)
77 {
78  struct timer *newtimer;
79 
80  CHECK_ALLOCATION(newtimer = (struct timer *) malloc(sizeof(struct timer)));
81 
82  if (freq <= 0.00000001)
83  freq = 0.00000001;
84 
85  newtimer->freq = freq;
86  newtimer->timer_tick = timer_tick;
87  newtimer->extra = extra;
88 
89  newtimer->interval = 1.0 / freq;
90  newtimer->next_tick_at = timer_current_time + newtimer->interval;
91 
92  newtimer->next = first_timer;
93  first_timer = newtimer;
94 
95  return newtimer;
96 }
97 
98 
99 /*
100  * timer_remove():
101  *
102  * Removes a virtual timer from the list of timers.
103  */
104 void timer_remove(struct timer *t)
105 {
106  struct timer *prev = NULL, *cur = first_timer;
107 
108  while (cur != NULL && cur != t) {
109  prev = cur;
110  cur = cur->next;
111  }
112 
113  if (cur == t) {
114  if (prev == NULL)
115  first_timer = cur->next;
116  else
117  prev->next = cur->next;
118  free(cur);
119  } else {
120  fprintf(stderr, "attempt to remove timer %p which "
121  "doesn't exist. aborting\n", t);
122  exit(1);
123  }
124 }
125 
126 
127 /*
128  * timer_update_frequency():
129  *
130  * Changes the frequency of an existing timer.
131  */
132 void timer_update_frequency(struct timer *t, double new_freq)
133 {
134  if (t->freq == new_freq)
135  return;
136 
137  t->freq = new_freq;
138 
139  if (new_freq <= 0.00000001)
140  new_freq = 0.00000001;
141 
142  t->interval = 1.0 / new_freq;
143  t->next_tick_at = timer_current_time + t->interval;
144 }
145 
146 
147 /*
148  * timer_tick():
149  *
150  * Timer tick handler. This is where the interesting stuff happens.
151  */
152 static void timer_tick(int signal_nr)
153 {
154  struct timer *timer = first_timer;
155  struct timeval tv;
156 
157  timer_current_time += timer_current_time_step;
158 
159  if ((--timer_countdown_to_next_gettimeofday) < 0) {
160  gettimeofday(&tv, NULL);
161  tv.tv_sec -= timer_start_tv.tv_sec;
162  tv.tv_usec -= timer_start_tv.tv_usec;
163  if (tv.tv_usec < 0) {
164  tv.tv_usec += 1000000;
165  tv.tv_sec --;
166  }
167 
168 #ifdef TIMER_DEBUG
169  /* For debugging/testing: */
170  {
171  double diff = tv.tv_usec * 0.000001 + tv.tv_sec
172  - timer_current_time;
173  printf("timer: lagging behind %f seconds\n", diff);
174  }
175 #endif
176 
177  /* Get exponentially closer to the real time, instead of
178  just changing to it directly: */
179  timer_current_time = ( (tv.tv_usec * 0.000001 + tv.tv_sec) +
180  timer_current_time ) / 2;
181 
182  timer_countdown_to_next_gettimeofday = (int64_t) (timer_freq *
184  }
185 
186  while (timer != NULL) {
187  while (timer_current_time >= timer->next_tick_at) {
188  timer->timer_tick(timer, timer->extra);
189  timer->next_tick_at += timer->interval;
190  }
191 
192  timer = timer->next;
193  }
194 
195 #ifdef TEST
196  printf("T"); fflush(stdout);
197 #endif
198 }
199 
200 
201 /*
202  * timer_start():
203  *
204  * Set the interval timer to timer_freq Hz, and install the signal handler.
205  */
206 void timer_start(void)
207 {
208  struct timer *timer = first_timer;
209  struct itimerval val;
210  struct sigaction saction;
211 
212  if (timer_is_running)
213  return;
214 
215  timer_is_running = 1;
216 
217  gettimeofday(&timer_start_tv, NULL);
218  timer_current_time = 0.0;
219 
220  /* Reset all timers: */
221  while (timer != NULL) {
222  timer->next_tick_at = timer->interval;
223  timer = timer->next;
224  }
225  val.it_interval.tv_sec = 0;
226  val.it_interval.tv_usec = (int) (1000000.0 / timer_freq);
227  val.it_value.tv_sec = 0;
228  val.it_value.tv_usec = (int) (1000000.0 / timer_freq);
229 
230  memset(&saction, 0, sizeof(saction));
231  saction.sa_handler = timer_tick;
232 
233  sigaction(SIGALRM, &saction, NULL);
234 
235  setitimer(ITIMER_REAL, &val, NULL);
236 }
237 
238 
239 /*
240  * timer_stop():
241  *
242  * Deinstall the signal handler, and disable the interval timer.
243  */
244 void timer_stop(void)
245 {
246  struct itimerval val;
247  struct sigaction saction;
248 
249  if (!timer_is_running)
250  return;
251 
252  timer_is_running = 0;
253 
254  val.it_interval.tv_sec = 0;
255  val.it_interval.tv_usec = 0;
256  val.it_value.tv_sec = 0;
257  val.it_value.tv_usec = 0;
258 
259  setitimer(ITIMER_REAL, &val, NULL);
260 
261  memset(&saction, 0, sizeof(saction));
262  saction.sa_handler = NULL;
263 
264  sigaction(SIGALRM, &saction, NULL);
265 }
266 
267 
268 #ifdef TEST
269 static void timer_tick_test(struct timer *t, void *extra)
270 {
271  printf((char *) extra); fflush(stdout);
272 }
273 #endif
274 
275 
276 /*
277  * timer_init():
278  *
279  * Initialize the timer framework.
280  */
281 void timer_init(void)
282 {
283  first_timer = NULL;
284  timer_current_time = 0.0;
285  timer_is_running = 0;
286  timer_countdown_to_next_gettimeofday = 0;
287 
288  timer_freq = TIMER_BASE_FREQUENCY;
289  timer_current_time_step = 1.0 / timer_freq;
290 
291 #ifdef TEST
292  timer_add(0.5, timer_tick_test, "X");
293  timer_add(10.0, timer_tick_test, ".");
294  timer_add(200.0, timer_tick_test, " ");
295  timer_start();
296  while (1)
297  sleep(999999);
298 #endif
299 }
300 
void timer_stop(void)
Definition: timer.cc:244
void * extra
Definition: timer.cc:50
#define SECONDS_BETWEEN_GETTIMEOFDAY_SYNCH
Definition: timer.cc:65
void(* timer_tick)(struct timer *timer, void *extra)
Definition: timer.cc:49
Definition: timer.cc:45
void timer_start(void)
Definition: timer.cc:206
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
double freq
Definition: timer.cc:48
struct timer * timer_add(double freq, void(*timer_tick)(struct timer *timer, void *extra), void *extra)
Definition: timer.cc:75
double next_tick_at
Definition: timer.cc:53
struct timer * next
Definition: timer.cc:46
void timer_update_frequency(struct timer *t, double new_freq)
Definition: timer.cc:132
void timer_init(void)
Definition: timer.cc:281
#define TIMER_BASE_FREQUENCY
Definition: timer.h:33
double interval
Definition: timer.cc:52
struct timeval timer_start_tv
Definition: timer.cc:57
vmrs t
Definition: armreg.h:750
void timer_remove(struct timer *t)
Definition: timer.cc:104

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13