~siretart/lcd4linux/debian

« back to all changes in this revision

Viewing changes to timer_group.c

  • Committer: Reinhard Tartler
  • Date: 2011-04-27 17:28:49 UTC
  • mfrom: (0.1.1 upstream)
  • Revision ID: siretart@tauware.de-20110427172849-mj5cj5a0igpcc9fn
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: timer_group.c 1136 2010-11-28 16:07:16Z mzuther $
 
2
 * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/timer_group.c $
 
3
 *
 
4
 * Generic grouping of widgets that have been set to the same update
 
5
 * interval, thus allowing synchronized updates.
 
6
 *
 
7
 * Copyright (C) 2010 Martin Zuther <code@mzuther.de>
 
8
 * Copyright (C) 2010 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 
9
 *
 
10
 * Based on "timer.c" which is
 
11
 * Copyright (C) 2003, 2004 Michael Reinelt <michael@reinelt.co.at>
 
12
 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or modify
 
15
 * it under the terms of the GNU General Public License as published by
 
16
 * the Free Software Foundation; either version 2, or (at your option)
 
17
 * any later version.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program; if not, write to the Free Software
 
26
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
27
 *
 
28
 */
 
29
 
 
30
/*
 
31
 * Exported functions:
 
32
 *
 
33
 * void timer_process_group(void *data)
 
34
 *
 
35
 *  Process all widgets of a timer group; if the timer group only
 
36
 *  contains one-shot timers, it will be deleted after processing.
 
37
 *
 
38
 *
 
39
 * void timer_exit_group(void)
 
40
 *
 
41
 *   Release all timer groups and widgets and free the associated
 
42
 *   memory blocks.
 
43
 *
 
44
 *
 
45
 * int timer_add_widget(void (*callback) (void *data), void *data,
 
46
 *     const int interval, const int one_shot)
 
47
 *
 
48
 *   Add widget to timer group of the specified update interval
 
49
 *   (also creates a new timer group if necessary).
 
50
 *
 
51
 *
 
52
 * int timer_remove_widget(void (*callback) (void *data), void *data)
 
53
 *
 
54
 *   Remove widget from the timer group with the specified update
 
55
 *   interval (also removes corresponding timer group if empty).
 
56
 *
 
57
 */
 
58
 
 
59
 
 
60
#include "config.h"
 
61
 
 
62
#include <stdlib.h>
 
63
#include <stdio.h>
 
64
#include <string.h>
 
65
 
 
66
#include "debug.h"
 
67
#include "cfg.h"
 
68
#include "timer.h"
 
69
#include "timer_group.h"
 
70
 
 
71
#ifdef WITH_DMALLOC
 
72
#include <dmalloc.h>
 
73
#endif
 
74
 
 
75
 
 
76
/* structure for storing all relevant data of a single timer group */
 
77
typedef struct TIMER_GROUP {
 
78
    /* pointer to the group's triggering interval in milliseconds;
 
79
       this will be used to identify a specific timer group and also
 
80
       as callback data for the underlying generic timer */
 
81
    int *interval;
 
82
 
 
83
    /* marks timer group as being active (so it will get processed) or
 
84
       inactive (which means the timer group has been deleted and its
 
85
       allocated memory may be re-used) */
 
86
    int active;
 
87
} TIMER_GROUP;
 
88
 
 
89
/* number of allocated timer group slots */
 
90
int nTimerGroups = 0;
 
91
 
 
92
/* pointer to memory allocated for storing the timer group slots */
 
93
TIMER_GROUP *TimerGroups = NULL;
 
94
 
 
95
 
 
96
/* structure for storing all relevant timer data of a single widget */
 
97
typedef struct TIMER_GROUP_WIDGET {
 
98
    /* pointer to function of type void func(void *data) that will be
 
99
       called when the timer is processed; it will also be used to
 
100
       identify a specific widget */
 
101
    void (*callback) (void *data);
 
102
 
 
103
    /* pointer to data which will be passed to the callback function;
 
104
       it will also be used to identify a specific widget */
 
105
    void *data;
 
106
 
 
107
    /* specifies the timer's triggering interval in milliseconds; it
 
108
       will also be used to identify a specific widget */
 
109
    int interval;
 
110
 
 
111
    /* specifies whether the timer should trigger indefinitely until
 
112
       it is deleted (value of 0) or only once (all other values) */
 
113
    int one_shot;
 
114
 
 
115
    /* marks timer as being active (so it will get processed) or
 
116
       inactive (which means the timer has been deleted and its
 
117
       allocated memory may be re-used) */
 
118
    int active;
 
119
} TIMER_GROUP_WIDGET;
 
120
 
 
121
/* number of allocated widget slots */
 
122
int nTimerGroupWidgets = 0;
 
123
 
 
124
/* pointer to memory allocated for storing the widget slots */
 
125
TIMER_GROUP_WIDGET *TimerGroupWidgets = NULL;
 
126
 
 
127
 
 
128
int timer_group_exists(const int interval)
 
129
/*  Check whether a timer group for the specified interval exists.
 
130
 
 
131
    interval (integer): the sought-after triggering interval in
 
132
    milliseconds
 
133
 
 
134
        return value (integer): returns a value of 1 if timer group
 
135
        exists; otherwise returns a value of 0
 
136
*/
 
137
{
 
138
    int group;                  /* current timer group's ID */
 
139
 
 
140
    /* loop through the timer group slots to search for one that
 
141
       matches the specified interval */
 
142
    for (group = 0; group < nTimerGroups; group++) {
 
143
        /* skip inactive (i.e. deleted) timer groups */
 
144
        if (TimerGroups[group].active == 0)
 
145
            continue;
 
146
 
 
147
        if (*TimerGroups[group].interval == interval) {
 
148
            /* matching timer group found, so signal success by returning
 
149
               a value of 1 */
 
150
            return 1;
 
151
        }
 
152
    }
 
153
 
 
154
    /* matching timer group not found, so signal failure by returning
 
155
       a value of 0 */
 
156
    return 0;
 
157
}
 
158
 
 
159
 
 
160
int timer_add_group(const int interval)
 
161
/*  Create a new timer group (unless it already exists) and link it to
 
162
        the timer queue.
 
163
 
 
164
        interval (integer): the new timer group's triggering interval in
 
165
        milliseconds
 
166
 
 
167
        return value (integer): returns a value of 0 on successful timer
 
168
        group creation; otherwise returns a value of -1
 
169
*/
 
170
{
 
171
    /* if timer group for update interval already exists, signal
 
172
       success by returning a value of 0 */
 
173
    if (timer_group_exists(interval))
 
174
        return 0;
 
175
 
 
176
    /* display an info message to inform the user that a new timer
 
177
       group is being created */
 
178
    info("Creating new timer group (%d ms)", interval);
 
179
 
 
180
    int group;                  /* current timer group's ID */
 
181
 
 
182
    /* try to minimize memory usage by looping through timer group
 
183
       slots and looking for an inactive timer group */
 
184
    for (group = 0; group < nTimerGroups; group++) {
 
185
        if (TimerGroups[group].active == 0) {
 
186
            /* we've just found one, so let's reuse it ("group" holds its
 
187
               ID) by breaking the loop */
 
188
            break;
 
189
        }
 
190
    }
 
191
 
 
192
    /* no inactive timer groups (or none at all) found, so we have to
 
193
       add a new timer group slot */
 
194
    if (group >= nTimerGroups) {
 
195
        /* increment number of timer groups and (re-)allocate memory used
 
196
           for storing the timer group slots */
 
197
        nTimerGroups++;
 
198
        TimerGroups = realloc(TimerGroups, nTimerGroups * sizeof(*TimerGroups));
 
199
 
 
200
        /* make sure "group" points to valid memory */
 
201
        group = nTimerGroups - 1;
 
202
 
 
203
        /* realloc() has failed */
 
204
        if (TimerGroups == NULL) {
 
205
            /* restore old number of timer groups */
 
206
            nTimerGroups--;
 
207
 
 
208
            /* signal unsuccessful timer group creation */
 
209
            return -1;
 
210
        }
 
211
 
 
212
        /* allocate memory for the underlying generic timer's callback
 
213
           data (i.e. the group's triggering interval in milliseconds) */
 
214
        TimerGroups[group].interval = malloc(sizeof(int));
 
215
 
 
216
        /* malloc() has failed */
 
217
        if (TimerGroups[group].interval == NULL) {
 
218
            /* signal unsuccessful timer group creation */
 
219
            return -1;
 
220
        }
 
221
    }
 
222
 
 
223
    /* initialize timer group's interval */
 
224
    *TimerGroups[group].interval = interval;
 
225
 
 
226
    /* set timer group to active so that it is processed and not
 
227
       overwritten by the memory optimization routine above */
 
228
    TimerGroups[group].active = 1;
 
229
 
 
230
    /* finally, request a generic timer that calls this group and
 
231
       signal success or failure */
 
232
    return timer_add(timer_process_group, TimerGroups[group].interval, interval, 0);
 
233
}
 
234
 
 
235
 
 
236
int timer_remove_group(const int interval)
 
237
/*  Remove a timer group and unlink it from the timer queue (also
 
238
        removes all remaining widget slots in this timer group).
 
239
 
 
240
        interval (integer): triggering interval in milliseconds; here, it
 
241
    will be used to identify the timer group
 
242
 
 
243
        return value (integer): returns a value of 0 on successful timer
 
244
        group removal; otherwise returns a value of -1
 
245
*/
 
246
{
 
247
    /* display an info message to inform the user that a timer group
 
248
       is being removed */
 
249
    info("Removing timer group (%d ms)", interval);
 
250
 
 
251
    int group;                  /* current timer group's ID */
 
252
    int widget;                 /* current widget's ID */
 
253
 
 
254
    /* loop through the widget slots to look for remaining widgets
 
255
       with the specified update interval */
 
256
    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
 
257
        /* skip inactive (i.e. deleted) widget slots */
 
258
        if (TimerGroupWidgets[widget].active == 0)
 
259
            continue;
 
260
 
 
261
        if (TimerGroupWidgets[widget].interval == interval) {
 
262
            /* we have found a matching widget slot, so mark it as being
 
263
               inactive; we will not actually delete the slot, so its
 
264
               allocated memory may be re-used */
 
265
            TimerGroupWidgets[widget].active = 0;
 
266
        }
 
267
    }
 
268
 
 
269
    /* loop through timer group slots and try to find the specified
 
270
       timer group slot by looking for its settings */
 
271
    for (group = 0; group < nTimerGroups; group++) {
 
272
        /* skip inactive (i.e. deleted) timer groups */
 
273
        if (TimerGroups[group].active == 0)
 
274
            continue;
 
275
 
 
276
        if (*TimerGroups[group].interval == interval) {
 
277
            /* we have found the timer group slot, so mark it as being
 
278
               inactive; we will not actually delete the slot, so its
 
279
               allocated memory may be re-used */
 
280
            TimerGroups[group].active = 0;
 
281
 
 
282
            /* remove the generic timer that calls this group */
 
283
            if (timer_remove(timer_process_group, TimerGroups[group].interval)) {
 
284
                /* signal successful removal of timer group */
 
285
                return 0;
 
286
            } else {
 
287
                /* an error occurred on generic timer removal, so signal
 
288
                   failure by returning a value of -1 */
 
289
                return -1;
 
290
            }
 
291
        }
 
292
    }
 
293
 
 
294
    /* we have NOT found the timer group slot, so signal failure by
 
295
       returning a value of -1 */
 
296
    return -1;
 
297
}
 
298
 
 
299
 
 
300
int timer_remove_empty_group(const int interval)
 
301
/*  Remove timer group *only* if it contains no more widget slots.
 
302
 
 
303
        interval (integer): triggering interval in milliseconds; here, it
 
304
    will be used to identify the timer group
 
305
 
 
306
        return value (integer): returns a value of 0 on successful
 
307
        processing; otherwise returns a value of -1
 
308
*/
 
309
{
 
310
    int widget;                 /* current widget's ID */
 
311
 
 
312
    /* loop through the widget slots to look for widgets with the
 
313
       specified update interval */
 
314
    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
 
315
        /* skip inactive (i.e. deleted) widget slots */
 
316
        if (TimerGroupWidgets[widget].active == 0)
 
317
            continue;
 
318
 
 
319
        /* at least one other widget with specified update interval
 
320
           exists, so signal success by returning a value of 0 */
 
321
        if (TimerGroupWidgets[widget].interval == interval)
 
322
            return 0;
 
323
    }
 
324
 
 
325
    /* no other widgets with specified update interval exist, so
 
326
       remove corresponding timer group and signal success or
 
327
       failure */
 
328
    return timer_remove_group(interval);
 
329
}
 
330
 
 
331
 
 
332
void timer_process_group(void *data)
 
333
/*  Process all widgets of a timer group; if the timer group only
 
334
        contains one-shot timers, it will be deleted after processing.
 
335
 
 
336
        data (void pointer): points to an integer holding the triggering
 
337
    interval in milliseconds; here, it will be used to identify the
 
338
    timer group
 
339
 
 
340
        return value: void
 
341
*/
 
342
{
 
343
    int widget;                 /* current widget's ID */
 
344
 
 
345
    /* convert callback data to integer (triggering interval in
 
346
       milliseconds) */
 
347
    int interval = *((int *) data);
 
348
 
 
349
    /* sanity check; by now, at least one timer group should be
 
350
       instantiated */
 
351
    if (nTimerGroups <= 0) {
 
352
        /* otherwise, print an error and return early */
 
353
        error("Huh? Not even a single timer group to process? Dazed and confused...");
 
354
        return;
 
355
    }
 
356
 
 
357
    /* sanity check; by now, at least one widget slot should be
 
358
       instantiated */
 
359
    if (nTimerGroupWidgets <= 0) {
 
360
        /* otherwise, print an error and return early */
 
361
        error("Huh? Not even a single widget slot to process? Dazed and confused...");
 
362
        return;
 
363
    }
 
364
 
 
365
    /* loop through widgets and search for those matching the timer
 
366
       group's update interval */
 
367
    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
 
368
        /* skip inactive (i.e. deleted) widgets */
 
369
        if (TimerGroupWidgets[widget].active == 0)
 
370
            continue;
 
371
 
 
372
        /* the current widget belongs to the specified timer group */
 
373
        if (TimerGroupWidgets[widget].interval == interval) {
 
374
            /* if the widget's callback function has been set, call it and
 
375
               pass the corresponding data */
 
376
            if (TimerGroupWidgets[widget].callback != NULL)
 
377
                TimerGroupWidgets[widget].callback(TimerGroupWidgets[widget].data);
 
378
 
 
379
            /* mark one-shot widget as inactive (which means the it has
 
380
               been deleted and its allocated memory may be re-used) */
 
381
            if (TimerGroupWidgets[widget].one_shot) {
 
382
                TimerGroupWidgets[widget].active = 0;
 
383
 
 
384
                /* also remove the corresponding timer group if it is empty */
 
385
                timer_remove_empty_group(interval);
 
386
            }
 
387
        }
 
388
    }
 
389
}
 
390
 
 
391
 
 
392
int timer_add_widget(void (*callback) (void *data), void *data, const int interval, const int one_shot)
 
393
/*  Add widget to timer group of the specified update interval
 
394
    (also creates a new timer group if necessary).
 
395
 
 
396
    callback (void pointer): function of type void func(void *data)
 
397
        which will be called whenever the timer group triggers; this
 
398
        pointer will also be used to identify a specific widget
 
399
 
 
400
        data (void pointer): data which will be passed to the callback
 
401
        function; this pointer will also be used to identify a specific
 
402
        widget
 
403
 
 
404
        interval (integer): specifies the timer's triggering interval in
 
405
        milliseconds
 
406
 
 
407
        one_shot (integer): specifies whether the timer should trigger
 
408
        indefinitely until it is deleted (value of 0) or only once (all
 
409
        other values)
 
410
 
 
411
        return value (integer): returns a value of 0 on successful widget
 
412
        addition; otherwise returns a value of -1
 
413
*/
 
414
{
 
415
    int widget;                 /* current widget's ID */
 
416
 
 
417
    /* if no timer group for update interval exists, create one */
 
418
    if (!timer_group_exists(interval)) {
 
419
        /* creation of new timer group failed, so signal failure by
 
420
           returning a value of -1 */
 
421
        if (timer_add_group(interval) != 0)
 
422
            return -1;
 
423
    }
 
424
 
 
425
    /* try to minimize memory usage by looping through the widget
 
426
       slots and looking for an inactive widget slot */
 
427
    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
 
428
        if (TimerGroupWidgets[widget].active == 0) {
 
429
            /* we've just found one, so let's reuse it ("widget" holds its
 
430
               ID) by breaking the loop */
 
431
            break;
 
432
        }
 
433
    }
 
434
 
 
435
    /* no inactive widget slots (or none at all) found, so we have to
 
436
       add a new widget slot */
 
437
    if (widget >= nTimerGroupWidgets) {
 
438
        /* increment number of widget slots and (re-)allocate memory used
 
439
           for storing the widget slots */
 
440
        nTimerGroupWidgets++;
 
441
        TimerGroupWidgets = realloc(TimerGroupWidgets, nTimerGroupWidgets * sizeof(*TimerGroupWidgets));
 
442
 
 
443
        /* make sure "widget" points to valid memory */
 
444
        widget = nTimerGroupWidgets - 1;
 
445
 
 
446
        /* realloc() has failed */
 
447
        if (TimerGroupWidgets == NULL) {
 
448
            /* restore old number of widget slots */
 
449
            nTimerGroupWidgets--;
 
450
 
 
451
            /* signal unsuccessful creation of widget slot */
 
452
            return -1;
 
453
        }
 
454
    }
 
455
 
 
456
    /* initialize widget slot */
 
457
    TimerGroupWidgets[widget].callback = callback;
 
458
    TimerGroupWidgets[widget].data = data;
 
459
    TimerGroupWidgets[widget].interval = interval;
 
460
    TimerGroupWidgets[widget].one_shot = one_shot;
 
461
 
 
462
    /* set widget slot to active so that it is processed and not
 
463
       overwritten by the memory optimization routine above */
 
464
    TimerGroupWidgets[widget].active = 1;
 
465
 
 
466
    /* signal successful addition of widget slot */
 
467
    return 0;
 
468
}
 
469
 
 
470
 
 
471
int timer_remove_widget(void (*callback) (void *data), void *data)
 
472
/*  Remove widget from the timer group with the specified update
 
473
    interval (also removes corresponding timer group if empty).
 
474
 
 
475
    callback (void pointer): function of type void func(void *data);
 
476
        here, it will be used to identify a specific widget
 
477
 
 
478
        data (void pointer): data which will be passed to the callback
 
479
        function; here, it will be used to identify a specific widget
 
480
 
 
481
        return value (integer): returns a value of 0 on successful widget
 
482
        removal; otherwise returns a value of -1
 
483
*/
 
484
{
 
485
    int widget;                 /* current widget's ID */
 
486
    int interval = -1;          /* specified widget's triggering interval in
 
487
                                   milliseconds */
 
488
 
 
489
    /* loop through the widget slots and try to find the specified
 
490
       widget slot by looking for its settings */
 
491
    for (widget = 0; widget < nTimerGroupWidgets; widget++) {
 
492
        /* skip inactive (i.e. deleted) widget slots */
 
493
        if (TimerGroupWidgets[widget].active == 0)
 
494
            continue;
 
495
 
 
496
        if (TimerGroupWidgets[widget].callback == callback && TimerGroupWidgets[widget].data == data) {
 
497
            /* we have found the widget slot, so mark it as being
 
498
               inactive; we will not actually delete the slot, so its
 
499
               allocated memory may be re-used */
 
500
            TimerGroupWidgets[widget].active = 0;
 
501
 
 
502
            /* store the widget's triggering interval for later use and
 
503
               break the loop */
 
504
            interval = TimerGroupWidgets[widget].interval;
 
505
            break;
 
506
        }
 
507
    }
 
508
 
 
509
    /* if no matching widget was found, signal an error by returning
 
510
       a value of -1 */
 
511
    if (interval < 0)
 
512
        return -1;
 
513
 
 
514
    /* if no other widgets with specified update interval exist,
 
515
       remove corresponding timer group and signal success or
 
516
       failure */
 
517
    return timer_remove_empty_group(interval);
 
518
}
 
519
 
 
520
 
 
521
void timer_exit_group(void)
 
522
/*  Release all timer groups and widgets and free the associated
 
523
        memory blocks.
 
524
 
 
525
        return value: void
 
526
*/
 
527
{
 
528
    int group;                  /* current timer group's ID */
 
529
 
 
530
    /* loop through all timer groups and remove them one by one */
 
531
    for (group = 0; group < nTimerGroups; group++) {
 
532
        /* remove generic timer */
 
533
        timer_remove(timer_process_group, TimerGroups[group].interval);
 
534
 
 
535
        /* free memory allocated for callback data (i.e. the group's
 
536
           triggering interval in milliseconds) */
 
537
        free(TimerGroups[group].interval);
 
538
    }
 
539
 
 
540
    /* reset number of allocated timer groups */
 
541
    nTimerGroups = 0;
 
542
 
 
543
    /* free allocated memory containing the timer group slots */
 
544
    if (TimerGroups != NULL) {
 
545
        free(TimerGroups);
 
546
        TimerGroups = NULL;
 
547
    }
 
548
 
 
549
    /* reset number of allocated widget slots */
 
550
    nTimerGroupWidgets = 0;
 
551
 
 
552
    /* free allocated memory containing the widget slots */
 
553
    if (TimerGroupWidgets != NULL) {
 
554
        free(TimerGroupWidgets);
 
555
        TimerGroupWidgets = NULL;
 
556
    }
 
557
}