1 /*
2 * Watchdog timer management. These functions in this file provide a
3 * convenient interface to the timers library that manages a list of
4 * watchdog timers. All details of scheduling an alarm at the CLOCK task
5 * are hidden behind this interface.
6 *
7 * The entry points into this file are:
8 * init_timer: initialize a timer structure
9 * set_timer: reset and existing or set a new watchdog timer
10 * cancel_timer: remove a timer from the list of timers
11 * expire_timers: check for expired timers and run watchdog functions
12 *
13 */
14
15 #include "syslib.h"
16 #include <minix/timers.h>
17 #include <minix/sysutil.h>
18
19 static minix_timer_t *timers = NULL;
20 static int expiring = FALSE;
21
22 /*
23 * Initialize the timer 'tp'.
24 */
25 void
init_timer(minix_timer_t * tp)26 init_timer(minix_timer_t * tp)
27 {
28
29 tmr_inittimer(tp);
30 }
31
32 /*
33 * Set the timer 'tp' to trigger 'ticks' clock ticks in the future. When it
34 * triggers, call function 'watchdog' with argument 'arg'. The given timer
35 * object must have been initialized with init_timer(3) already. The given
36 * number of ticks must be between 0 and TMRDIFF_MAX inclusive. A ticks value
37 * of zero will cause the alarm to trigger on the next clock tick. If the
38 * timer was already set, it will be canceled first.
39 */
40 void
set_timer(minix_timer_t * tp,clock_t ticks,tmr_func_t watchdog,int arg)41 set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg)
42 {
43 clock_t prev_time, next_time;
44 int r, had_timers;
45
46 if (ticks > TMRDIFF_MAX)
47 panic("set_timer: ticks value too large: %u", (int)ticks);
48
49 /* Add the timer to the list. */
50 had_timers = tmrs_settimer(&timers, tp, getticks() + ticks, watchdog,
51 arg, &prev_time, &next_time);
52
53 /* Reschedule our synchronous alarm if necessary. */
54 if (!expiring && (!had_timers || next_time != prev_time)) {
55 if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
56 panic("set_timer: couldn't set alarm: %d", r);
57 }
58 }
59
60 /*
61 * Cancel the timer 'tp'. The timer object must have been initialized with
62 * init_timer(3) first. If the timer was not set before, the call is a no-op.
63 */
64 void
cancel_timer(minix_timer_t * tp)65 cancel_timer(minix_timer_t * tp)
66 {
67 clock_t next_time, prev_time;
68 int r, have_timers;
69
70 if (!tmr_is_set(tp))
71 return;
72
73 have_timers = tmrs_clrtimer(&timers, tp, &prev_time, &next_time);
74
75 /*
76 * If the earliest timer has been removed, we have to set the alarm to
77 * the next timer, or cancel the alarm altogether if the last timer
78 * has been canceled.
79 */
80 if (!expiring) {
81 if (!have_timers)
82 r = sys_setalarm(0, FALSE /*abs_time*/);
83 else if (prev_time != next_time)
84 r = sys_setalarm(next_time, TRUE /*abs_time*/);
85 else
86 r = OK;
87
88 if (r != OK)
89 panic("cancel_timer: couldn't set alarm: %d", r);
90 }
91 }
92
93 /*
94 * Expire all timers that were set to expire before/at the given current time.
95 */
96 void
expire_timers(clock_t now)97 expire_timers(clock_t now)
98 {
99 clock_t next_time;
100 int r, have_timers;
101
102 /*
103 * Check for expired timers. Use a global variable to indicate that
104 * watchdog functions are called, so that sys_setalarm() isn't called
105 * more often than necessary when set_timer or cancel_timer are called
106 * from these watchdog functions.
107 */
108 expiring = TRUE;
109 have_timers = tmrs_exptimers(&timers, now, &next_time);
110 expiring = FALSE;
111
112 /* Reschedule an alarm if necessary. */
113 if (have_timers) {
114 if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
115 panic("expire_timers: couldn't set alarm: %d", r);
116 }
117 }
118