]> git.webhop.me Git - lcd4linux.git/commitdiff
commented, corrected and beautified both timer and timer group code
authormzuther <mzuther@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>
Sun, 28 Nov 2010 16:07:16 +0000 (16:07 +0000)
committermzuther <mzuther@3ae390bd-cb1e-0410-b409-cd5a39f66f1f>
Sun, 28 Nov 2010 16:07:16 +0000 (16:07 +0000)
git-svn-id: https://ssl.bulix.org/svn/lcd4linux/trunk@1136 3ae390bd-cb1e-0410-b409-cd5a39f66f1f

drv_T6963.c
indent.sh
plugin_button_exec.c
plugin_gps.c
plugin_iconv.c
plugin_seti.c
plugin_wireless.c
timer.c
timer.h
timer_group.c
timer_group.h

index ac472caca999985f49099d662f850309c4083996..fd7bd75d49169897f917626f2b9e3d99cc3242c0 100644 (file)
@@ -279,7 +279,7 @@ static void drv_T6_clear(const unsigned short addr, const int len)
        drv_T6_write_auto(0x0);
        if (bug) {
            bug = 0;
-           debug("bug occured at byte %d of %d", i, len);
+           debug("bug occurred at byte %d of %d", i, len);
        }
     }
     drv_T6_status2();
@@ -297,7 +297,7 @@ static void drv_T6_copy(const unsigned short addr, const unsigned char *data, co
        drv_T6_write_auto(*(data++));
        if (bug) {
            bug = 0;
-           debug("bug occured at byte %d of %d, addr=%d", i, len, addr);
+           debug("bug occurred at byte %d of %d, addr=%d", i, len, addr);
        }
     }
     drv_T6_status2();
index cadc14d2a5aa8eac4d09f4754c4ea06bc5d54780..e21a739ba40d664bebaded61a63c0bc9a210d7c3 100755 (executable)
--- a/indent.sh
+++ b/indent.sh
@@ -8,7 +8,7 @@
 # -l120  Set maximum line length for non-comment lines to 150.
 # -npro  Do not read ‘.indent.pro’ files.
 
-rm *.c~ *.h~
+rm *.c~ *.h~ 2>/dev/null  # trash "no such file or directory" warning messages 
 indent -kr -l120 -npro *.c *.h
 
 for i in *.c *.h; do
index 118ab113b252b8d69ed0b4d29fd468e7ed1ae020..768584102b0a7abf9139c11db59cf629683609be 100644 (file)
@@ -85,7 +85,7 @@ static void my_button_exec(RESULT * result, int argc, RESULT * argv[])
        info(strerror(errsv));
        exit(0);
     } else if (pid == -1) {
-       info("weird error has occured. couldn't fork.");
+       info("weird error has occurred. couldn't fork.");
     } else {
        SetResult(&result, R_STRING, "0");
     }
index 01ecf7dd1a718ee7396c1fbb754fbeec71a049d6..219c6e35c9c3cf5ca280355afe062230fa131257 100644 (file)
@@ -572,7 +572,7 @@ static void parse(RESULT * result, RESULT * theOptions, RESULT * displayOptions)
            status = nmeap_parseBuffer(&nmea, (const char *) &bufferTmp, &rem); //parse it
            if (status == -1) {
                errCounter++;
-               error("parser error occured! (cnt: %i)\n", errCounter);
+               error("parser error occurred! (cnt: %i)\n", errCounter);
            } else if (status == 0) {
                incomplCounter++;
            } else if (status > 0)
index bd01f265f1d75b72e3f1af54d8bb2c9e793889d7..5bf005bf128bc21fc6e13bf1c512abb7f1c6424a 100644 (file)
@@ -104,7 +104,7 @@ static void my_iconv(RESULT * result, RESULT * charset_from, RESULT * charset_to
                    source_left = 0;
                    break;
                default:
-                   error("plugin_iconv: strange errno state (%d) occured", errno);
+                   error("plugin_iconv: strange errno state (%d) occurred", errno);
                    source_left = 0;
                }
            }
index 4fe7aeae819f64443f85a3a6e3776d7c9bc38de5..ad115aa1ae1e845bbff9678403dfd7ccb5bb2333 100644 (file)
@@ -63,7 +63,7 @@ static int parse_seti(void)
     FILE *stream;
     int age;
 
-    /* if a fatal error occured, do nothing */
+    /* if a fatal error occurred, do nothing */
     if (fatal != 0)
        return -1;
 
index 25adf2669aad949c7e1be4fa0aef48195e241887..2eb5bc022263a8173a22ed13847813e4546b4424 100644 (file)
@@ -490,7 +490,7 @@ static int get_stats(const char *dev, const char *key)
     } else {
 
        qprintf(qprintf_buffer, sizeof(qprintf_buffer), "%d/%d", stats.qual.level, range.max_qual.level);
-       qprintf(key_buffer, sizeof(key_buffer), "%s.%s", dev, KEY_LEVEL);;
+       qprintf(key_buffer, sizeof(key_buffer), "%s.%s", dev, KEY_LEVEL);
        hash_put(&wireless, key_buffer, qprintf_buffer);
 
        qprintf(qprintf_buffer, sizeof(qprintf_buffer), "%d/%d", stats.qual.noise, range.max_qual.noise);
diff --git a/timer.c b/timer.c
index b0b1bc2c4b37b8ef1a3b003ac4c063b00d7725af..cb259ee2d4b6ccb884be48b26857764a5c3c3e21 100644 (file)
--- a/timer.c
+++ b/timer.c
@@ -1,7 +1,7 @@
 /* $Id$
  * $URL$
  *
- * generic timer handling
+ * Generic timer handling.
  *
  * Copyright (C) 2003, 2004 Michael Reinelt <michael@reinelt.co.at>
  * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 #include <dmalloc.h>
 #endif
 
+/* FIXME: CLOCK_SKEW_DETECT_TIME_IN_S should have a higher value */
+
 /* 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 */
+    /* pointer to function of type void func(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 */
+    /* pointer to 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
@@ -98,17 +100,16 @@ typedef struct TIMER {
        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
+    /* marks timer 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;
 
-
 /* number of allocated timer slots */
 int nTimers = 0;
 
-/* pointer to memory used for storing the timer slots */
+/* pointer to memory allocated for storing the timer slots */
 TIMER *Timers = NULL;
 
 
@@ -137,7 +138,7 @@ 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.
+/*  Remove a timer with given callback and data.
 
     callback (void pointer): function of type void func(void *data);
     here, it will be used to identify the timer
@@ -146,24 +147,29 @@ int timer_remove(void (*callback) (void *data), void *data)
        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
+       removal; otherwise returns a value of -1
 */
 {
-    int i;                     /* current timer's ID */
+    int timer;                 /* current timer's ID */
 
     /* loop through the timer slots and try to find the specified
        timer slot by looking for its settings */
-    for (i = 0; i < nTimers; i++) {
-       if (Timers[i].callback == callback && Timers[i].data == data && Timers[i].active) {
+    for (timer = 0; timer < nTimers; timer++) {
+       /* skip inactive (i.e. deleted) timers */
+       if (Timers[timer].active == 0)
+           continue;
+
+       if (Timers[timer].callback == callback && Timers[timer].data == data) {
            /* we have found the timer slot, so mark it as being inactive;
-              we will not actually delete the timer, so its allocated
+              we will not actually delete the slot, so its allocated
               memory may be re-used */
-           Timers[i].active = 0;
+           Timers[timer].active = 0;
 
            /* signal successful timer removal */
            return 0;
        }
     }
+
     /* we have NOT found the timer slot, so signal failure by
        returning a value of -1 */
     return -1;
@@ -192,26 +198,30 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
        creation; otherwise returns a value of -1
 */
 {
-    int i;                     /* current timer's ID */
+    int timer;                 /* current timer's ID */
     struct timeval now;                /* struct to hold current time */
 
     /* try to minimize memory usage by looping through the timer slots
        and looking for an inactive timer */
-    for (i = 0; i < nTimers; i++) {
-       if (Timers[i].active == 0)
-           /* we've just found one, so let's reuse it ("i" holds its ID)
-              by breaking the loop */
+    for (timer = 0; timer < nTimers; timer++) {
+       if (Timers[timer].active == 0) {
+           /* we've just found one, so let's reuse it ("timer" holds its
+              ID) by breaking the loop */
            break;
+       }
     }
 
     /* no inactive timers (or none at all) found, so we have to add a
        new timer slot */
-    if (i >= nTimers) {
+    if (timer >= nTimers) {
        /* increment number of timers and (re-)allocate memory used for
           storing the timer slots */
        nTimers++;
        Timers = realloc(Timers, nTimers * sizeof(*Timers));
 
+       /* make sure "timer" points to valid memory */
+       timer = nTimers - 1;
+
        /* realloc() has failed */
        if (Timers == NULL) {
            /* restore old number of timers */
@@ -225,21 +235,21 @@ int timer_add(void (*callback) (void *data), void *data, const int interval, con
     /* get current time so the timer triggers immediately */
     gettimeofday(&now, NULL);
 
-    /* fill in timer data */
-    Timers[i].callback = callback;
-    Timers[i].data = data;
-    Timers[i].when = now;
-    Timers[i].interval = interval;
-    Timers[i].one_shot = one_shot;
+    /* initialize timer data */
+    Timers[timer].callback = callback;
+    Timers[timer].data = data;
+    Timers[timer].when = now;
+    Timers[timer].interval = interval;
+    Timers[timer].one_shot = one_shot;
 
     /* set timer to active so that it is processed and not overwritten
-       by the memory optimisation routine above */
-    Timers[i].active = 1;
+       by the memory optimization routine above */
+    Timers[timer].active = 1;
 
     /* one-shot timers should NOT fire immediately, so delay them by a
        single timer interval */
     if (one_shot) {
-       timer_inc(&Timers[i].when, interval);
+       timer_inc(&Timers[timer].when, interval);
     }
 
     /* signal successful timer creation */
@@ -279,17 +289,20 @@ int timer_add_late(void (*callback) (void *data), void *data, const int interval
        return -1;
     }
 
-    int i;                     /* current timer's ID */
+    int timer;                 /* current timer's ID */
 
     /* loop through the timer slots and try to find the new timer slot
        by looking for its settings */
-    for (i = 0; i < nTimers; i++) {
-       if (Timers[i].callback == callback && Timers[i].data == data && Timers[i].active
-           && Timers[i].interval == interval) {
+    for (timer = 0; timer < nTimers; timer++) {
+       /* skip inactive (i.e. deleted) timers */
+       if (Timers[timer].active == 0)
+           continue;
+
+       if (Timers[timer].callback == callback && Timers[timer].data == data && Timers[timer].interval == interval) {
            /* we have found the new timer slot, so unmask it by setting
               its "one_shot" variable to the REAL value; then signal
               successful timer creation */
-           Timers[i].one_shot = one_shot;
+           Timers[timer].one_shot = one_shot;
 
            /* signal successful timer creation */
            return 0;
@@ -317,73 +330,76 @@ int timer_process(struct timespec *delay)
     /* get current time to check which timers need processing */
     gettimeofday(&now, NULL);
 
-    /* sanity check; at least one timer should need processing */
-    if (nTimers == 0) {
+    /* sanity check; by now, at least one timer should be
+       instantiated */
+    if (nTimers <= 0) {
        /* 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...");
+       error("Huh? Not even a single timer to process? Dazed and confused...");
        return -1;
     }
 
-    int i;                     /* current timer's ID */
+    int timer;                 /* current timer's ID */
 
     /* process all expired timers */
-    for (i = 0; i < nTimers; i++) {
+    for (timer = 0; timer < nTimers; timer++) {
        /* skip inactive (i.e. deleted) timers */
-       if (Timers[i].active == 0)
+       if (Timers[timer].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, >)) {
+       if (!timercmp(&Timers[timer].when, &now, >)) {
            /* 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);
+           if (Timers[timer].callback != NULL) {
+               Timers[timer].callback(Timers[timer].data);
            }
 
            /* check for one-shot timers */
-           if (Timers[i].one_shot) {
+           if (Timers[timer].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;
+               Timers[timer].active = 0;
            } else {
                /* otherwise, respawn timer by adding one triggering interval
                   to its triggering time */
-               timer_inc(&Timers[i].when, Timers[i].interval);
+               timer_inc(&Timers[timer].when, Timers[timer].interval);
            }
        }
     }
 
-    int min = -1;              /* ID of the next upcoming timer */
+    int next_timer = -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++) {
+    for (timer = 0; timer < nTimers; timer++) {
        /* skip inactive (i.e. deleted) timers */
-       if (Timers[i].active == 0)
+       if (Timers[timer].active == 0)
            continue;
 
        /* 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;
+       if (next_timer < 0)
+           next_timer = timer;
        /* check whether current timer needs processing prior to the one
           selected */
-       else if (timercmp(&Timers[i].when, &Timers[min].when, <))
+       else if (timercmp(&Timers[timer].when, &Timers[next_timer].when, <)) {
            /* if so, mark it as the next upcoming timer */
-           min = i;
+           next_timer = timer;
+       }
     }
 
     /* sanity check; we should by now have found the next upcoming
        timer */
-    if (min < 0) {
+    if (next_timer < 0) {
        /* otherwise, print an error and return a value of -1 to signal an
           error */
-       error("Huh? Not one single timer left? Dazed and confused...");
+       error("Huh? Not even a single timer left? Dazed and confused...");
        return -1;
     }
 
@@ -397,7 +413,7 @@ int timer_process(struct timespec *delay)
 
     /* calculate delay to the next upcoming timer event and store it
        in "diff" */
-    timersub(&Timers[min].when, &now, &diff);
+    timersub(&Timers[next_timer].when, &now, &diff);
 
     /* for negative delays, set "diff" to the Epoch so the next update
        is triggered immediately */
@@ -417,7 +433,7 @@ int timer_process(struct timespec *delay)
        /* update time stamp and timer */
        /* FIXME: shouldn't we update *all* timers? */
        gettimeofday(&now, NULL);
-       Timers[min].when = now;
+       Timers[next_timer].when = now;
     }
 
     /* finally, set passed timespec "delay" to "diff" ... */
@@ -439,8 +455,8 @@ void timer_exit(void)
     /* reset number of allocated timer slots */
     nTimers = 0;
 
-    if (Timers != NULL) {
        /* free memory used for storing the timer slots */
+    if (Timers != NULL) {
        free(Timers);
        Timers = NULL;
     }
diff --git a/timer.h b/timer.h
index 70744d517d89e362d76d16a693abc3ad56a4cd15..127099da5141542453ed936ab6005dd7717fa6ae 100644 (file)
--- a/timer.h
+++ b/timer.h
@@ -28,6 +28,7 @@
 #ifndef _TIMER_H_
 #define _TIMER_H_
 
+
 int timer_add(void (*callback) (void *data), void *data, const int interval, const int one_shot);
 
 int timer_add_late(void (*callback) (void *data), void *data, const int interval, const int one_shot);
index 0a72e84567e1250b5175207ebcf459971f7b3299..893e085cae25afe1efb9262d3ee40791000a2b20 100644 (file)
@@ -1,10 +1,11 @@
 /* $Id$
  * $URL$
  *
- * generic grouping of widget timers that have been set to the same
- * update interval, thus allowing synchronized updates
+ * Generic grouping of widgets that have been set to the same update
+ * interval, thus allowing synchronized updates.
  *
  * Copyright (C) 2010 Martin Zuther <code@mzuther.de>
+ * Copyright (C) 2010 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
  *
  * Based on "timer.c" which is
  * Copyright (C) 2003, 2004 Michael Reinelt <michael@reinelt.co.at>
  *
  */
 
-/* 
- * exported functions:
+/*
+ * Exported functions:
  *
- * int timer_add_group(void (*callback) (void *data), const int interval)
- *   make sure that generic timer exists for given update interval
+ * void timer_process_group(void *data)
  *
- * int timer_remove_group(void (*callback) (void *data), const int interval)
- *   remove generic timer for given update interval
+ *  Process all widgets of a timer group; if the timer group only
+ *  contains one-shot timers, it will be deleted after processing.
  *
- * void timer_process_group(void *data)
- *   process all widgets of a given update interval (*data)
  *
  * void timer_exit_group(void)
- *   release all timers and free reserved memory
  *
- * int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot)
- *  add widget to group of the given update interval (creates a new group if
- *  necessary)
+ *   Release all timer groups and widgets and free the associated
+ *   memory blocks.
+ *
+ *
+ * int timer_add_widget(void (*callback) (void *data), void *data,
+ *     const int interval, const int one_shot)
+ *
+ *   Add widget to timer group of the specified update interval
+ *   (also creates a new timer group if necessary).
+ *
  *
  * int timer_remove_widget(void (*callback) (void *data), void *data)
- *  remove widget from group of the given update interval (als removes emtpy
- *  groups)
+ *
+ *   Remove widget from the timer group with the specified update
+ *   interval (also removes corresponding timer group if empty).
  *
  */
 
 #endif
 
 
-/* contains the actual timers, one for each update interval */
+/* structure for storing all relevant data of a single timer group */
 typedef struct TIMER_GROUP {
-    void (*callback) (void *data);
+    /* pointer to the group's triggering interval in milliseconds;
+       this will be used to identify a specific timer group and also
+       as callback data for the underlying generic timer */
     int *interval;
+
+    /* marks timer group as being active (so it will get processed) or
+       inactive (which means the timer group has been deleted and its
+       allocated memory may be re-used) */
     int active;
 } TIMER_GROUP;
 
-TIMER_GROUP *GroupTimers = NULL;
-int nGroupTimers = 0;
+/* number of allocated timer group slots */
+int nTimerGroups = 0;
+
+/* pointer to memory allocated for storing the timer group slots */
+TIMER_GROUP *TimerGroups = NULL;
 
-/* contains callback and data for each widget */
-typedef struct SINGLE_TIMER {
+
+/* structure for storing all relevant timer data of a single widget */
+typedef struct TIMER_GROUP_WIDGET {
+    /* pointer to function of type void func(void *data) that will be
+       called when the timer is processed; it will also be used to
+       identify a specific widget */
     void (*callback) (void *data);
+
+    /* pointer to data which will be passed to the callback function;
+       it will also be used to identify a specific widget */
     void *data;
+
+    /* specifies the timer's triggering interval in milliseconds; it
+       will also be used to identify a specific widget */
     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 timer 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;
-} SINGLE_TIMER;
+} TIMER_GROUP_WIDGET;
+
+/* number of allocated widget slots */
+int nTimerGroupWidgets = 0;
+
+/* pointer to memory allocated for storing the widget slots */
+TIMER_GROUP_WIDGET *TimerGroupWidgets = NULL;
+
+
+int timer_group_exists(const int interval)
+/*  Check whether a timer group for the specified interval exists.
 
-SINGLE_TIMER *SingleTimers = NULL;
-int nSingleTimers = 0;
+    interval (integer): the sought-after triggering interval in
+    milliseconds
 
-int timer_add_group(void (*callback) (void *data), const int interval)
+       return value (integer): returns a value of 1 if timer group
+       exists; otherwise returns a value of 0
+*/
 {
-    int group;
+    int group;                 /* current timer group's ID */
 
-    /* check whether timer exists for given update interval */
-    for (group = 0; group < nGroupTimers; group++) {
-       if (*GroupTimers[group].interval == interval)
-           return 0;
+    /* loop through the timer group slots to search for one that
+       matches the specified interval */
+    for (group = 0; group < nTimerGroups; group++) {
+       /* skip inactive (i.e. deleted) timer groups */
+       if (TimerGroups[group].active == 0)
+           continue;
+
+       if (*TimerGroups[group].interval == interval) {
+           /* matching timer group found, so signal success by returning
+              a value of 1 */
+           return 1;
+       }
     }
 
-    /* otherwise look for a free group */
-    for (group = 0; group < nGroupTimers; group++) {
-       if (GroupTimers[group].active == 0)
+    /* matching timer group not found, so signal failure by returning
+       a value of 0 */
+    return 0;
+}
+
+
+int timer_add_group(const int interval)
+/*  Create a new timer group (unless it already exists) and link it to
+       the timer queue.
+
+       interval (integer): the new timer group's triggering interval in
+       milliseconds
+
+       return value (integer): returns a value of 0 on successful timer
+       group creation; otherwise returns a value of -1
+*/
+{
+    /* if timer group for update interval already exists, signal
+       success by returning a value of 0 */
+    if (timer_group_exists(interval))
+       return 0;
+
+    /* display an info message to inform the user that a new timer
+       group is being created */
+    info("Creating new timer group (%d ms)", interval);
+
+    int group;                 /* current timer group's ID */
+
+    /* try to minimize memory usage by looping through timer group
+       slots and looking for an inactive timer group */
+    for (group = 0; group < nTimerGroups; group++) {
+       if (TimerGroups[group].active == 0) {
+           /* we've just found one, so let's reuse it ("group" holds its
+              ID) by breaking the loop */
            break;
+       }
     }
 
-    /* none found, allocate a new group */
-    if (group >= nGroupTimers) {
-       nGroupTimers++;
-       GroupTimers = realloc(GroupTimers, nGroupTimers * sizeof(*GroupTimers));
+    /* no inactive timer groups (or none at all) found, so we have to
+       add a new timer group slot */
+    if (group >= nTimerGroups) {
+       /* increment number of timer groups and (re-)allocate memory used
+          for storing the timer group slots */
+       nTimerGroups++;
+       TimerGroups = realloc(TimerGroups, nTimerGroups * sizeof(*TimerGroups));
 
-       /* also allocate memory for callback data */
-       GroupTimers[group].interval = malloc(sizeof(int));
+       /* make sure "group" points to valid memory */
+       group = nTimerGroups - 1;
+
+       /* realloc() has failed */
+       if (TimerGroups == NULL) {
+           /* restore old number of timer groups */
+           nTimerGroups--;
+
+           /* signal unsuccessful timer group creation */
+           return -1;
+       }
+
+       /* allocate memory for the underlying generic timer's callback
+          data (i.e. the group's triggering interval in milliseconds) */
+       TimerGroups[group].interval = malloc(sizeof(int));
+
+       /* malloc() has failed */
+       if (TimerGroups[group].interval == NULL) {
+           /* signal unsuccessful timer group creation */
+           return -1;
+       }
     }
 
-    /* initialize group */
-    info("Creating new timer group (%d ms)", interval);
+    /* initialize timer group's interval */
+    *TimerGroups[group].interval = interval;
 
-    GroupTimers[group].callback = callback;
-    *GroupTimers[group].interval = interval;
-    GroupTimers[group].active = 1;
+    /* set timer group to active so that it is processed and not
+       overwritten by the memory optimization routine above */
+    TimerGroups[group].active = 1;
 
-    /* finally, request a generic timer */
-    return timer_add(GroupTimers[group].callback, GroupTimers[group].interval, interval, 0);
+    /* finally, request a generic timer that calls this group and
+       signal success or failure */
+    return timer_add(timer_process_group, TimerGroups[group].interval, interval, 0);
 }
 
-int timer_remove_group(void (*callback) (void *data), const int interval)
+
+int timer_remove_group(const int interval)
+/*  Remove a timer group and unlink it from the timer queue (also
+       removes all remaining widget slots in this timer group).
+
+       interval (integer): triggering interval in milliseconds; here, it
+    will be used to identify the timer group
+
+       return value (integer): returns a value of 0 on successful timer
+       group removal; otherwise returns a value of -1
+*/
 {
-    int group;
+    /* display an info message to inform the user that a timer group
+       is being removed */
+    info("Removing timer group (%d ms)", interval);
+
+    int group;                 /* current timer group's ID */
+    int widget;                        /* current widget's ID */
+
+    /* loop through the widget slots to look for remaining widgets
+       with the specified update interval */
+    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
+       /* skip inactive (i.e. deleted) widget slots */
+       if (TimerGroupWidgets[widget].active == 0)
+           continue;
+
+       if (TimerGroupWidgets[widget].interval == interval) {
+           /* we have found a matching widget slot, so mark it as being
+              inactive; we will not actually delete the slot, so its
+              allocated memory may be re-used */
+           TimerGroupWidgets[widget].active = 0;
+       }
+    }
 
-    /* look for group with given callback function and update interval */
-    for (group = 0; group < nGroupTimers; group++) {
-       if (GroupTimers[group].callback == callback && *GroupTimers[group].interval == interval
-           && GroupTimers[group].active) {
-           /* inactivate group */
-           GroupTimers[group].active = 0;
+    /* loop through timer group slots and try to find the specified
+       timer group slot by looking for its settings */
+    for (group = 0; group < nTimerGroups; group++) {
+       /* skip inactive (i.e. deleted) timer groups */
+       if (TimerGroups[group].active == 0)
+           continue;
 
-           /* remove generic timer */
-           return timer_remove(GroupTimers[group].callback, GroupTimers[group].interval);
+       if (*TimerGroups[group].interval == interval) {
+           /* we have found the timer group slot, so mark it as being
+              inactive; we will not actually delete the slot, so its
+              allocated memory may be re-used */
+           TimerGroups[group].active = 0;
+
+           /* remove the generic timer that calls this group */
+           if (timer_remove(timer_process_group, TimerGroups[group].interval)) {
+               /* signal successful removal of timer group */
+               return 0;
+           } else {
+               /* an error occurred on generic timer removal, so signal
+                  failure by returning a value of -1 */
+               return -1;
+           }
        }
     }
+
+    /* we have NOT found the timer group slot, so signal failure by
+       returning a value of -1 */
     return -1;
 }
 
+
+int timer_remove_empty_group(const int interval)
+/*  Remove timer group *only* if it contains no more widget slots.
+
+       interval (integer): triggering interval in milliseconds; here, it
+    will be used to identify the timer group
+
+       return value (integer): returns a value of 0 on successful
+       processing; otherwise returns a value of -1
+*/
+{
+    int widget;                        /* current widget's ID */
+
+    /* loop through the widget slots to look for widgets with the
+       specified update interval */
+    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
+       /* skip inactive (i.e. deleted) widget slots */
+       if (TimerGroupWidgets[widget].active == 0)
+           continue;
+
+       /* at least one other widget with specified update interval
+          exists, so signal success by returning a value of 0 */
+       if (TimerGroupWidgets[widget].interval == interval)
+           return 0;
+    }
+
+    /* no other widgets with specified update interval exist, so
+       remove corresponding timer group and signal success or
+       failure */
+    return timer_remove_group(interval);
+}
+
+
 void timer_process_group(void *data)
+/*  Process all widgets of a timer group; if the timer group only
+       contains one-shot timers, it will be deleted after processing.
+
+       data (void pointer): points to an integer holding the triggering
+    interval in milliseconds; here, it will be used to identify the
+    timer group
+
+       return value: void
+*/
 {
-    int slot;
-    int *interval = (int *) data;
+    int widget;                        /* current widget's ID */
+
+    /* convert callback data to integer (triggering interval in
+       milliseconds) */
+    int interval = *((int *) data);
+
+    /* sanity check; by now, at least one timer group should be
+       instantiated */
+    if (nTimerGroups <= 0) {
+       /* otherwise, print an error and return early */
+       error("Huh? Not even a single timer group to process? Dazed and confused...");
+       return;
+    }
 
-    /* sanity check */
-    if (nSingleTimers == 0) {
-       error("huh? not even a single widget timer to process? dazed and confused...");
+    /* sanity check; by now, at least one widget slot should be
+       instantiated */
+    if (nTimerGroupWidgets <= 0) {
+       /* otherwise, print an error and return early */
+       error("Huh? Not even a single widget slot to process? Dazed and confused...");
        return;
     }
 
-    /* process every (active) widget associated with given update interval */
-    for (slot = 0; slot < nSingleTimers; slot++) {
-       if (SingleTimers[slot].active == 0)
+    /* loop through widgets and search for those matching the timer
+       group's update interval */
+    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
+       /* skip inactive (i.e. deleted) widgets */
+       if (TimerGroupWidgets[widget].active == 0)
            continue;
 
-       if (SingleTimers[slot].interval == *interval) {
-           /* call one-shot timers only once */
-           if (SingleTimers[slot].one_shot)
-               SingleTimers[slot].active = 0;
-           /* execute callback function */
-           if (SingleTimers[slot].callback != NULL)
-               SingleTimers[slot].callback(SingleTimers[slot].data);
+       /* the current widget belongs to the specified timer group */
+       if (TimerGroupWidgets[widget].interval == interval) {
+           /* if the widget's callback function has been set, call it and
+              pass the corresponding data */
+           if (TimerGroupWidgets[widget].callback != NULL)
+               TimerGroupWidgets[widget].callback(TimerGroupWidgets[widget].data);
+
+           /* mark one-shot widget as inactive (which means the it has
+              been deleted and its allocated memory may be re-used) */
+           if (TimerGroupWidgets[widget].one_shot) {
+               TimerGroupWidgets[widget].active = 0;
+
+               /* also remove the corresponding timer group if it is empty */
+               timer_remove_empty_group(interval);
+           }
        }
     }
 }
 
+
 int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot)
-{
-    int slot;
+/*  Add widget to timer group of the specified update interval
+    (also creates a new timer group if necessary).
 
-    /* make sure that group for update interval exists or can be created */
-    if (timer_add_group(timer_process_group, interval) != 0)
-       return -1;
+    callback (void pointer): function of type void func(void *data)
+       which will be called whenever the timer group triggers; this
+       pointer will also be used to identify a specific widget
+
+       data (void pointer): data which will be passed to the callback
+       function; this pointer will also be used to identify a specific
+       widget
+
+       interval (integer): specifies the timer's triggering interval in
+       milliseconds
 
-    /* find a free slot for callback data */
-    for (slot = 0; slot < nSingleTimers; slot++) {
-       if (SingleTimers[slot].active == 0)
+       one_shot (integer): specifies whether the timer should trigger
+       indefinitely until it is deleted (value of 0) or only once (all
+       other values)
+
+       return value (integer): returns a value of 0 on successful widget
+       addition; otherwise returns a value of -1
+*/
+{
+    int widget;                        /* current widget's ID */
+
+    /* if no timer group for update interval exists, create one */
+    if (!timer_group_exists(interval)) {
+       /* creation of new timer group failed, so signal failure by
+          returning a value of -1 */
+       if (timer_add_group(interval) != 0)
+           return -1;
+    }
+
+    /* try to minimize memory usage by looping through the widget
+       slots and looking for an inactive widget slot */
+    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
+       if (TimerGroupWidgets[widget].active == 0) {
+           /* we've just found one, so let's reuse it ("widget" holds its
+              ID) by breaking the loop */
            break;
+       }
     }
 
-    /* none found, allocate a new slot */
-    if (slot >= nSingleTimers) {
-       nSingleTimers++;
-       SingleTimers = realloc(SingleTimers, nSingleTimers * sizeof(*SingleTimers));
+    /* no inactive widget slots (or none at all) found, so we have to
+       add a new widget slot */
+    if (widget >= nTimerGroupWidgets) {
+       /* increment number of widget slots and (re-)allocate memory used
+          for storing the widget slots */
+       nTimerGroupWidgets++;
+       TimerGroupWidgets = realloc(TimerGroupWidgets, nTimerGroupWidgets * sizeof(*TimerGroupWidgets));
+
+       /* make sure "widget" points to valid memory */
+       widget = nTimerGroupWidgets - 1;
+
+       /* realloc() has failed */
+       if (TimerGroupWidgets == NULL) {
+           /* restore old number of widget slots */
+           nTimerGroupWidgets--;
+
+           /* signal unsuccessful creation of widget slot */
+           return -1;
+       }
     }
 
-    /* fill slot with callback data */
-    SingleTimers[slot].callback = callback;
-    SingleTimers[slot].data = data;
-    SingleTimers[slot].interval = interval;
-    SingleTimers[slot].one_shot = one_shot;
-    SingleTimers[slot].active = 1;
+    /* initialize widget slot */
+    TimerGroupWidgets[widget].callback = callback;
+    TimerGroupWidgets[widget].data = data;
+    TimerGroupWidgets[widget].interval = interval;
+    TimerGroupWidgets[widget].one_shot = one_shot;
 
+    /* set widget slot to active so that it is processed and not
+       overwritten by the memory optimization routine above */
+    TimerGroupWidgets[widget].active = 1;
+
+    /* signal successful addition of widget slot */
     return 0;
 }
 
+
 int timer_remove_widget(void (*callback) (void *data), void *data)
+/*  Remove widget from the timer group with the specified update
+    interval (also removes corresponding timer group if empty).
+
+    callback (void pointer): function of type void func(void *data);
+       here, it will be used to identify a specific widget
+
+       data (void pointer): data which will be passed to the callback
+       function; here, it will be used to identify a specific widget
+
+       return value (integer): returns a value of 0 on successful widget
+       removal; otherwise returns a value of -1
+*/
 {
-    int slot, interval;
-
-    interval = 0;
-    /* look for (active) widget with given callback function and data */
-    for (slot = 0; slot < nSingleTimers; slot++) {
-       if (SingleTimers[slot].callback == callback && SingleTimers[slot].data == data && SingleTimers[slot].active) {
-           /* deactivate widget */
-           SingleTimers[slot].active = 0;
-           interval = SingleTimers[slot].interval;
+    int widget;                        /* current widget's ID */
+    int interval = -1;         /* specified widget's triggering interval in
+                                  milliseconds */
+
+    /* loop through the widget slots and try to find the specified
+       widget slot by looking for its settings */
+    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
+       /* skip inactive (i.e. deleted) widget slots */
+       if (TimerGroupWidgets[widget].active == 0)
+           continue;
+
+       if (TimerGroupWidgets[widget].callback == callback && TimerGroupWidgets[widget].data == data) {
+           /* we have found the widget slot, so mark it as being
+              inactive; we will not actually delete the slot, so its
+              allocated memory may be re-used */
+           TimerGroupWidgets[widget].active = 0;
+
+           /* store the widget's triggering interval for later use and
+              break the loop */
+           interval = TimerGroupWidgets[widget].interval;
            break;
        }
     }
 
-    /* signal an error if no matching widget was found */
-    if (interval == 0)
+    /* if no matching widget was found, signal an error by returning
+       a value of -1 */
+    if (interval < 0)
        return -1;
 
-    /* look for other widgets with given update interval */
-    for (slot = 0; slot < nSingleTimers; slot++) {
-       if (SingleTimers[slot].active == 0)
-           continue;
-       /* at least one other widget with given update interval exists */
-       if (SingleTimers[slot].interval == interval)
-           return 0;
-    }
-
-    /* remove group with given update interval */
-    return timer_remove_group(timer_process_group, interval);
+    /* if no other widgets with specified update interval exist,
+       remove corresponding timer group and signal success or
+       failure */
+    return timer_remove_empty_group(interval);
 }
 
+
 void timer_exit_group(void)
+/*  Release all timer groups and widgets and free the associated
+       memory blocks.
+
+       return value: void
+*/
 {
-    int group;
+    int group;                 /* current timer group's ID */
+
+    /* loop through all timer groups and remove them one by one */
+    for (group = 0; group < nTimerGroups; group++) {
+       /* remove generic timer */
+       timer_remove(timer_process_group, TimerGroups[group].interval);
 
-    /* remove generic timer and free memory for callback data */
-    for (group = 0; group < nGroupTimers; group++) {
-       timer_remove(GroupTimers[group].callback, GroupTimers[group].interval);
-       free(GroupTimers[group].interval);
+       /* free memory allocated for callback data (i.e. the group's
+          triggering interval in milliseconds) */
+       free(TimerGroups[group].interval);
     }
 
-    /* free memory for groups */
-    nGroupTimers = 0;
+    /* reset number of allocated timer groups */
+    nTimerGroups = 0;
 
-    if (GroupTimers != NULL) {
-       free(GroupTimers);;
-       GroupTimers = NULL;
+    /* free allocated memory containing the timer group slots */
+    if (TimerGroups != NULL) {
+       free(TimerGroups);
+       TimerGroups = NULL;
     }
 
-    /* free memory for widget callback data */
-    nSingleTimers = 0;
+    /* reset number of allocated widget slots */
+    nTimerGroupWidgets = 0;
 
-    if (SingleTimers != NULL) {
-       free(SingleTimers);;
-       SingleTimers = NULL;
+    /* free allocated memory containing the widget slots */
+    if (TimerGroupWidgets != NULL) {
+       free(TimerGroupWidgets);
+       TimerGroupWidgets = NULL;
     }
 }
index 36d9057a3e483251f56c6398039f1bfb704e8978..ab9b835fe0bf57a6dcabeefaf44766d55bfbbd93 100644 (file)
 #ifndef _TIMER_GROUP_H_
 #define _TIMER_GROUP_H_
 
-int timer_add_group(void (*callback) (void *data), const int interval);
-int timer_remove_group(void (*callback) (void *data), const int interval);
+
 void timer_process_group(void *data);
+
 void timer_exit_group(void);
 
 int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot);
+
 int timer_remove_widget(void (*callback) (void *data), void *data);
 
 #endif