1
/* $Id: timer.c 1143 2011-02-12 22:46:19Z mzuther $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/timer.c $
4
* Generic timer handling.
6
* Copyright (C) 2003, 2004 Michael Reinelt <michael@reinelt.co.at>
7
* Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 2, or (at your option)
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software
21
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
* int timer_add(void (*callback) (void *data), void *data, const int
29
* interval, const int one_shot)
31
* Create a new timer and add it to the timer queue.
34
* int timer_add_late(void (*callback) (void *data), void *data, const
35
* int interval, const int one_shot)
37
* This function creates a new timer and adds it to the timer queue
38
* just as timer_add() does, but the timer will NOT be triggered
39
* immediately (useful for scheduling things).
42
* int timer_process(struct timespec *delay)
44
* Process timer queue.
47
* int timer_remove(void (*callback) (void *data), void *data)
49
* Remove a new timer with given callback and data.
52
* void timer_exit(void)
54
* Release all timers and free the associated memory block.
75
/* threshold in milliseconds that differentiates between clock skew
77
#define CLOCK_SKEW_DETECT_TIME_IN_MS 1000
79
/* structure for storing all relevant data of a single timer */
80
typedef struct TIMER {
81
/* pointer to function of type void func(void *data) that will be
82
called when the timer is processed; it will also be used to
83
identify a specific timer */
84
void (*callback) (void *data);
86
/* pointer to data which will be passed to the callback function;
87
it will also be used to identify a specific timer */
90
/* struct to hold the time (in seconds and milliseconds since the
91
Epoch) when the timer will be processed for the next time */
94
/* specifies the timer's triggering interval in milliseconds */
97
/* specifies whether the timer should trigger indefinitely until
98
it is deleted (value of 0) or only once (all other values) */
101
/* marks timer as being active (so it will get processed) or
102
inactive (which means the timer has been deleted and its
103
allocated memory may be re-used) */
107
/* number of allocated timer slots */
110
/* pointer to memory allocated for storing the timer slots */
111
TIMER *Timers = NULL;
114
static void timer_inc(const int timer, struct timeval *now)
115
/* Update the time a given timer updates next.
117
timer (integer): internal ID of timer that is to be updated
119
now (timeval pointer): struct holding the "current" time
124
/* calculate the time difference between the last time the given
125
timer has been processed and the current time */
127
timersub(now, &Timers[timer].when, &diff);
129
/* convert this time difference to fractional seconds */
130
float time_difference = diff.tv_sec + diff.tv_usec / 1000000.0f;
132
/* convert time difference to fractional milliseconds */
133
time_difference = time_difference * 1000.0f;
135
/* calculate the number of timer intervals that have passed since
136
the last timer the given timer has been processed -- value is
137
truncated (rounded down) to an integer */
138
int number_of_intervals = (int) (time_difference / Timers[timer].interval);
140
/* notify the user in case one or more timer intervals have been
142
if (number_of_intervals > 0)
143
info("Timer #%d skipped %d interval(s) or %d ms.", timer, number_of_intervals,
144
number_of_intervals * Timers[timer].interval);
146
/* increment the number of passed intervals in order to skip all
147
missed intervals -- thereby avoiding that unprocessed timers
148
stack up, continuously update and are notoriously late (certain
149
railway companies might learn a lesson from us <g>) */
150
number_of_intervals++;
152
/* calculate time difference between the last time the timer has
153
been processed and the next time it will be processed */
154
int interval = Timers[timer].interval * number_of_intervals;
156
/* convert time difference (in milliseconds) to a "timeval"
157
struct (in seconds and microseconds) */
158
struct timeval tv_interval = {
159
.tv_sec = interval / 1000,
160
.tv_usec = (interval % 1000) * 1000
163
/* finally, add time difference to the timer's trigger */
164
timeradd(&Timers[timer].when, &tv_interval, &Timers[timer].when);
168
int timer_remove(void (*callback) (void *data), void *data)
169
/* Remove a timer with given callback and data.
171
callback (void pointer): function of type void func(void *data);
172
here, it will be used to identify the timer
174
data (void pointer): data which will be passed to the callback
175
function; here, it will be used to identify the timer
177
return value (integer): returns a value of 0 on successful timer
178
removal; otherwise returns a value of -1
181
int timer; /* current timer's ID */
183
/* loop through the timer slots and try to find the specified
184
timer slot by looking for its settings */
185
for (timer = 0; timer < nTimers; timer++) {
186
/* skip inactive (i.e. deleted) timers */
187
if (Timers[timer].active == 0)
190
if (Timers[timer].callback == callback && Timers[timer].data == data) {
191
/* we have found the timer slot, so mark it as being inactive;
192
we will not actually delete the slot, so its allocated
193
memory may be re-used */
194
Timers[timer].active = 0;
196
/* signal successful timer removal */
201
/* we have NOT found the timer slot, so signal failure by
202
returning a value of -1 */
207
int timer_add(void (*callback) (void *data), void *data, const int interval, const int one_shot)
208
/* Create a new timer and add it to the timer queue.
210
callback (void pointer): function of type void func(void *data)
211
which will be called whenever the timer triggers; this pointer
212
will also be used to identify a specific timer
214
data (void pointer): data which will be passed to the callback
215
function; this pointer will also be used to identify a specific
218
interval (integer): specifies the timer's triggering interval in
221
one_shot (integer): specifies whether the timer should trigger
222
indefinitely until it is deleted (value of 0) or only once (all
225
return value (integer): returns a value of 0 on successful timer
226
creation; otherwise returns a value of -1
229
int timer; /* current timer's ID */
230
struct timeval now; /* struct to hold current time */
232
/* try to minimize memory usage by looping through the timer slots
233
and looking for an inactive timer */
234
for (timer = 0; timer < nTimers; timer++) {
235
if (Timers[timer].active == 0) {
236
/* we've just found one, so let's reuse it ("timer" holds its
237
ID) by breaking the loop */
242
/* no inactive timers (or none at all) found, so we have to add a
244
if (timer >= nTimers) {
245
/* increment number of timers and (re-)allocate memory used for
246
storing the timer slots */
248
Timers = realloc(Timers, nTimers * sizeof(*Timers));
250
/* make sure "timer" points to valid memory */
253
/* realloc() has failed */
254
if (Timers == NULL) {
255
/* restore old number of timers */
258
/* signal unsuccessful timer creation */
263
/* get current time so the timer triggers immediately */
264
gettimeofday(&now, NULL);
266
/* initialize timer data */
267
Timers[timer].callback = callback;
268
Timers[timer].data = data;
269
Timers[timer].when = now;
270
Timers[timer].interval = interval;
271
Timers[timer].one_shot = one_shot;
273
/* set timer to active so that it is processed and not overwritten
274
by the memory optimization routine above */
275
Timers[timer].active = 1;
277
/* one-shot timers should NOT fire immediately, so delay them by a
278
single timer interval */
280
timer_inc(timer, &now);
283
/* signal successful timer creation */
288
int timer_add_late(void (*callback) (void *data), void *data, const int interval, const int one_shot)
289
/* This function creates a new timer and adds it to the timer queue
290
just as timer_add() does, but the timer will NOT be triggered
291
immediately (useful for scheduling things).
293
callback (void pointer): function of type void func(void *data)
294
which will be called whenever the timer triggers; this pointer
295
will also be used to identify a specific timer
297
data (void pointer): data which will be passed to the callback
298
function; this pointer will also be used to identify a specific
301
interval (integer): specifies the timer's triggering interval in
304
one_shot (integer): specifies whether the timer should trigger
305
indefinitely until it is deleted (value of 0) or only once (all
308
return value (integer): returns a value of 0 on successful timer
309
creation; otherwise returns a value of -1
312
/* create new timer slot and add it to the timer queue; mask it as
313
one-shot timer for now, so the timer will be delayed by a
314
single timer interval */
315
if (!timer_add(callback, data, interval, 1)) {
316
/* signal unsuccessful timer creation */
320
int timer; /* current timer's ID */
322
/* loop through the timer slots and try to find the new timer slot
323
by looking for its settings */
324
for (timer = 0; timer < nTimers; timer++) {
325
/* skip inactive (i.e. deleted) timers */
326
if (Timers[timer].active == 0)
329
if (Timers[timer].callback == callback && Timers[timer].data == data && Timers[timer].interval == interval) {
330
/* we have found the new timer slot, so unmask it by setting
331
its "one_shot" variable to the REAL value; then signal
332
successful timer creation */
333
Timers[timer].one_shot = one_shot;
335
/* signal successful timer creation */
340
/* we have NOT found the new timer slot for some reason, so signal
341
failure by returning a value of -1 */
346
int timer_process(struct timespec *delay)
347
/* Process timer queue.
349
delay (timespec pointer): struct holding delay till the next
352
return value (integer): returns a value of 0 when timers have been
353
processed successfully; otherwise returns a value of -1
356
struct timeval now; /* struct to hold current time */
358
/* get current time to check which timers need processing */
359
gettimeofday(&now, NULL);
361
/* sanity check; by now, at least one timer should be
364
/* otherwise, print an error and return a value of -1 to
366
error("Huh? Not even a single timer to process? Dazed and confused...");
370
int timer; /* current timer's ID */
372
/* process all expired timers */
373
for (timer = 0; timer < nTimers; timer++) {
374
/* skip inactive (i.e. deleted) timers */
375
if (Timers[timer].active == 0)
378
/* check whether current timer needs to be processed, i.e. the
379
timer's triggering time is less than or equal to the current
380
time; according to the man page of timercmp(), this avoids
381
using the operators ">=", "<=" and "==" which might be broken
383
if (!timercmp(&Timers[timer].when, &now, >)) {
384
/* if the timer's callback function has been set, call it and
385
pass the corresponding data */
386
if (Timers[timer].callback != NULL) {
387
Timers[timer].callback(Timers[timer].data);
390
/* check for one-shot timers */
391
if (Timers[timer].one_shot) {
392
/* mark one-shot timer as inactive (which means the timer has
393
been deleted and its allocated memory may be re-used) */
394
Timers[timer].active = 0;
396
/* otherwise, re-spawn timer by adding one triggering interval
397
to its triggering time */
398
timer_inc(timer, &now);
403
int next_timer = -1; /* ID of the next upcoming timer */
405
/* loop through the timer slots and try to find the next upcoming
407
for (timer = 0; timer < nTimers; timer++) {
408
/* skip inactive (i.e. deleted) timers */
409
if (Timers[timer].active == 0)
412
/* if this is the first timer that we check, mark it as the next
413
upcoming timer; otherwise, we'll have nothing to compare
414
against in this loop */
417
/* check whether current timer needs processing prior to the one
419
else if (timercmp(&Timers[timer].when, &Timers[next_timer].when, <)) {
420
/* if so, mark it as the next upcoming timer */
425
/* sanity check; we should by now have found the next upcoming
427
if (next_timer < 0) {
428
/* otherwise, print an error and return a value of -1 to signal an
430
error("Huh? Not even a single timer left? Dazed and confused...");
434
/* processing all the timers might have taken a while, so update
435
the current time to compensate for processing delay */
436
gettimeofday(&now, NULL);
438
struct timeval diff; /* struct holding the time difference
439
between current time and the triggering time of the
440
next upcoming timer event */
442
/* calculate delay to the next upcoming timer event and store it
444
timersub(&Timers[next_timer].when, &now, &diff);
446
/* a negative delay has occurred (positive clock skew or some
447
timers are faster than the time needed for processing their
449
if (diff.tv_sec < 0) {
450
/* zero "diff" so the next update is triggered immediately */
453
/* convert "diff" to milliseconds */
454
int time_difference = diff.tv_sec * 1000 + diff.tv_usec / 1000;
456
/* if there is a notable difference between "time_difference" and
457
the next upcoming timer's interval, assume clock skew */
458
if (time_difference > (Timers[next_timer].interval + CLOCK_SKEW_DETECT_TIME_IN_MS)) {
459
/* extract clock skew from "time_difference" by eliminating
460
the timer's triggering interval */
461
int skew = time_difference - Timers[next_timer].interval;
463
/* display an info message to inform the user */
464
info("Oops, clock skewed by %d ms, updating timestamps...", skew);
466
/* convert clock skew from milliseconds to "timeval"
468
struct timeval clock_skew = {
469
.tv_sec = skew / 1000,
470
.tv_usec = (skew % 1000) * 1000
473
/* process all timers */
474
for (timer = 0; timer < nTimers; timer++) {
475
/* skip inactive (i.e. deleted) timers */
476
if (Timers[timer].active == 0)
479
/* correct timer's time stamp by clock skew */
480
timersub(&Timers[timer].when, &clock_skew, &Timers[timer].when);
483
/* finally, zero "diff" so the next update is triggered
489
/* set timespec "delay" passed by calling function to "diff" */
490
delay->tv_sec = diff.tv_sec;
491
/* timespec uses nanoseconds instead of microseconds!!! */
492
delay->tv_nsec = diff.tv_usec * 1000;
494
/* signal successful timer processing */
499
void timer_exit(void)
500
/* Release all timers and free the associated memory block.
505
/* reset number of allocated timer slots */
508
/* free memory used for storing the timer slots */
509
if (Timers != NULL) {