aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--timer.c175
-rw-r--r--timer.h9
2 files changed, 138 insertions, 46 deletions
diff --git a/timer.c b/timer.c
index c80e960..b0b1bc2 100644
--- a/timer.c
+++ b/timer.c
@@ -23,7 +23,7 @@
*/
/*
- * exported functions:
+ * Exported functions:
*
* int timer_add(void (*callback) (void *data), void *data, const int
* interval, const int one_shot)
@@ -39,9 +39,9 @@
* immediately (useful for scheduling things).
*
*
- * int timer_process (struct timespec *delay)
+ * int timer_process(struct timespec *delay)
*
- * process timer queue
+ * Process timer queue.
*
*
* int timer_remove(void (*callback) (void *data), void *data)
@@ -72,14 +72,35 @@
#include <dmalloc.h>
#endif
+/* delay in seconds between timer events that is considered as being
+ induced by clock skew */
#define CLOCK_SKEW_DETECT_TIME_IN_S 1
+/* structure for storing all relevant data of a single timer */
typedef struct TIMER {
+ /* function of type callback(void *data) that will be called when
+ the timer is processed; it will also be used to identify a
+ specific timer */
void (*callback) (void *data);
+
+ /* data which will be passed to the callback function; it will
+ also be used to identify a specific timer */
void *data;
+
+ /* struct to hold the time (in seconds and milliseconds since the
+ Epoch) when the timer will be processed for the next time */
struct timeval when;
+
+ /* specifies the timer's triggering interval in milliseconds */
int interval;
+
+ /* specifies whether the timer should trigger indefinitely until
+ it is deleted (value of 0) or only once (all other values) */
int one_shot;
+
+ /* marks timers as being active (so it will get processed) or
+ inactive (which means the timer has been deleted and its
+ allocated memory may be re-used) */
int active;
} TIMER;
@@ -94,18 +115,23 @@ TIMER *Timers = NULL;
static void timer_inc(struct timeval *tv, const int interval)
/* Update a timer's trigger by adding the given interval.
- tv (timeval pointer): struct holding current time
+ tv (timeval pointer): struct holding the last time the timer has
+ been processed
interval (integer): interval in milliseconds to be added to the
- timer's trigger
+ the last time the timer has been processed
- return value: void */
+ return value: void
+ */
{
+ /* split time interval to be added (given in milliseconds) into
+ microseconds and seconds */
struct timeval diff = {
.tv_sec = interval / 1000,
.tv_usec = (interval % 1000) * 1000
};
+ /* add interval to timer and store the result in the timer */
timeradd(tv, &diff, tv);
}
@@ -113,14 +139,15 @@ static void timer_inc(struct timeval *tv, const int interval)
int timer_remove(void (*callback) (void *data), void *data)
/* Remove a new timer with given callback and data.
- callback (void pointer): function of type callback(void *data);
+ callback (void pointer): function of type void func(void *data);
here, it will be used to identify the timer
data (void pointer): data which will be passed to the callback
function; here, it will be used to identify the timer
return value (integer): returns a value of 0 on successful timer
- deletion; otherwise returns a value of -1 */
+ deletion; otherwise returns a value of -1
+*/
{
int i; /* current timer's ID */
@@ -129,9 +156,11 @@ int timer_remove(void (*callback) (void *data), void *data)
for (i = 0; i < nTimers; i++) {
if (Timers[i].callback == callback && Timers[i].data == data && Timers[i].active) {
/* we have found the timer slot, so mark it as being inactive;
- we will not actually delete the timer, so its memory may be
- re-used */
+ we will not actually delete the timer, so its allocated
+ memory may be re-used */
Timers[i].active = 0;
+
+ /* signal successful timer removal */
return 0;
}
}
@@ -144,7 +173,7 @@ int timer_remove(void (*callback) (void *data), void *data)
int timer_add(void (*callback) (void *data), void *data, const int interval, const int one_shot)
/* Create a new timer and add it to the timer queue.
- callback (void pointer): function of type callback(void *data)
+ callback (void pointer): function of type void func(void *data)
which will be called whenever the timer triggers; this pointer
will also be used to identify a specific timer
@@ -160,7 +189,8 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
other values)
return value (integer): returns a value of 0 on successful timer
- creation; otherwise returns a value of -1 */
+ creation; otherwise returns a value of -1
+*/
{
int i; /* current timer's ID */
struct timeval now; /* struct to hold current time */
@@ -174,7 +204,8 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
break;
}
- /* no inactive timers found, so we have to add a new timer slot */
+ /* no inactive timers (or none at all) found, so we have to add a
+ new timer slot */
if (i >= nTimers) {
/* increment number of timers and (re-)allocate memory used for
storing the timer slots */
@@ -183,9 +214,10 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
/* realloc() has failed */
if (Timers == NULL) {
- /* restore old number of timers and signal unsuccessful timer
- creation */
+ /* restore old number of timers */
nTimers--;
+
+ /* signal unsuccessful timer creation */
return -1;
}
}
@@ -201,7 +233,7 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
Timers[i].one_shot = one_shot;
/* set timer to active so that it is processed and not overwritten
- by the memory optimisation above */
+ by the memory optimisation routine above */
Timers[i].active = 1;
/* one-shot timers should NOT fire immediately, so delay them by a
@@ -220,7 +252,7 @@ int timer_add_late(void (*callback) (void *data), void *data, const int interval
just as timer_add() does, but the timer will NOT be triggered
immediately (useful for scheduling things).
- callback (void pointer): function of type callback(void *data)
+ callback (void pointer): function of type void func(void *data)
which will be called whenever the timer triggers; this pointer
will also be used to identify a specific timer
@@ -236,7 +268,8 @@ int timer_add_late(void (*callback) (void *data), void *data, const int interval
other values)
return value (integer): returns a value of 0 on successful timer
- creation; otherwise returns a value of -1 */
+ creation; otherwise returns a value of -1
+*/
{
/* create new timer slot and add it to the timer queue; mask it as
one-shot timer for now, so the timer will be delayed by a
@@ -257,6 +290,8 @@ int timer_add_late(void (*callback) (void *data), void *data, const int interval
its "one_shot" variable to the REAL value; then signal
successful timer creation */
Timers[i].one_shot = one_shot;
+
+ /* signal successful timer creation */
return 0;
}
}
@@ -268,84 +303,138 @@ int timer_add_late(void (*callback) (void *data), void *data, const int interval
int timer_process(struct timespec *delay)
+/* Process timer queue.
+
+ delay (timespec pointer): struct holding delay till the next
+ upcoming timer event
+
+ return value (integer): returns a value of 0 when timers have been
+ processed successfully; otherwise returns a value of -1
+*/
{
- int i, min;
- struct timeval now;
+ struct timeval now; /* struct to hold current time */
- /* the current moment */
+ /* get current time to check which timers need processing */
gettimeofday(&now, NULL);
- /* sanity check */
+ /* sanity check; at least one timer should need processing */
if (nTimers == 0) {
- error("huh? not one single timer to process? dazed and confused...");
+ /* otherwise, print an error and return a value of -1 to
+ signal an error */
+ error("Huh? Not one single timer to process? Dazed and confused...");
return -1;
}
- /* process expired timers */
+ int i; /* current timer's ID */
+
+ /* process all expired timers */
for (i = 0; i < nTimers; i++) {
+ /* skip inactive (i.e. deleted) timers */
if (Timers[i].active == 0)
continue;
+ /* check whether current timer needs to be processed, i.e. the
+ timer's triggering time is less than or equal to the current
+ time; according to the man page of timercmp(), this avoids
+ using the operators ">=", "<=" and "==" which might be broken
+ on some systems */
if (!timercmp(&Timers[i].when, &now, >)) {
- /* callback */
+ /* if the timer's callback function has been set, call it and
+ pass the corresponding data */
if (Timers[i].callback != NULL) {
Timers[i].callback(Timers[i].data);
}
- /* respawn or delete timer */
+
+ /* check for one-shot timers */
if (Timers[i].one_shot) {
+ /* mark one-shot timer as inactive (which means the timer has
+ been deleted and its allocated memory may be re-used) */
Timers[i].active = 0;
} else {
+ /* otherwise, respawn timer by adding one triggering interval
+ to its triggering time */
timer_inc(&Timers[i].when, Timers[i].interval);
}
}
}
- /* find next timer */
- min = -1;
+ int min = -1; /* ID of the next upcoming timer */
+
+ /* loop through the timer slots and try to find the next upcoming
+ timer */
for (i = 0; i < nTimers; i++) {
+ /* skip inactive (i.e. deleted) timers */
if (Timers[i].active == 0)
continue;
- if ((min < 0) || timercmp(&Timers[i].when, &Timers[min].when, <))
+
+ /* if this is the first timer that we check, mark it as the next
+ upcoming timer; otherwise, we'll have nothing to compare
+ against in this loop */
+ if (min < 0)
+ min = i;
+ /* check whether current timer needs processing prior to the one
+ selected */
+ else if (timercmp(&Timers[i].when, &Timers[min].when, <))
+ /* if so, mark it as the next upcoming timer */
min = i;
}
+ /* sanity check; we should by now have found the next upcoming
+ timer */
if (min < 0) {
- error("huh? not one single timer left? dazed and confused...");
+ /* otherwise, print an error and return a value of -1 to signal an
+ error */
+ error("Huh? Not one single timer left? Dazed and confused...");
return -1;
}
- /* update the current moment to compensate for processing delay */
+ /* processing all the timers might have taken a while, so update
+ the current time to compensate for processing delay */
gettimeofday(&now, NULL);
- /* delay until next timer event */
- struct timeval diff;
+ struct timeval diff; /* struct holding the time difference
+ between current time and the triggering time of the
+ next upcoming timer event */
+
+ /* calculate delay to the next upcoming timer event and store it
+ in "diff" */
timersub(&Timers[min].when, &now, &diff);
- /* for negative delays, directly trigger next update */
+ /* for negative delays, set "diff" to the Epoch so the next update
+ is triggered immediately */
if (diff.tv_sec < 0)
timerclear(&diff);
- delay->tv_sec = diff.tv_sec;
- /* microseconds to nanoseconds!! */
- delay->tv_nsec = diff.tv_usec * 1000;
+ /* check whether the delay in "diff" has been induced by clock
+ skew */
+ if (diff.tv_sec > CLOCK_SKEW_DETECT_TIME_IN_S) {
+ /* set "diff" to the Epoch so the next update is triggered
+ directly */
+ timerclear(&diff);
- /* check if date changed */
- if ((delay->tv_sec) > CLOCK_SKEW_DETECT_TIME_IN_S) {
- delay->tv_sec = 0;
- delay->tv_nsec = 0;
+ /* display an info message to inform the user */
info("Oops, clock skewed, update timestamp");
+
+ /* update time stamp and timer */
+ /* FIXME: shouldn't we update *all* timers? */
gettimeofday(&now, NULL);
Timers[min].when = now;
}
- return 0;
+ /* finally, set passed timespec "delay" to "diff" ... */
+ delay->tv_sec = diff.tv_sec;
+ /* timespec uses nanoseconds instead of microseconds!!! */
+ delay->tv_nsec = diff.tv_usec * 1000;
+ /* signal successful timer processing */
+ return 0;
}
void timer_exit(void)
/* Release all timers and free the associated memory block.
- return value: void */
+ return value: void
+*/
{
/* reset number of allocated timer slots */
nTimers = 0;
diff --git a/timer.h b/timer.h
index 26f8674..70744d5 100644
--- a/timer.h
+++ b/timer.h
@@ -29,10 +29,13 @@
#define _TIMER_H_
int timer_add(void (*callback) (void *data), void *data, const int interval, const int one_shot);
-/* exactly the same as timer_add() but does not trigger immediately */
+
int timer_add_late(void (*callback) (void *data), void *data, const int interval, const int one_shot);
-int timer_remove(void (*callback) (void *data), void *data);
+
int timer_process(struct timespec *delay);
-void timer_exit();
+
+int timer_remove(void (*callback) (void *data), void *data);
+
+void timer_exit(void);
#endif