1*cfd712b4SDavid van Moolenbroek /*
2*cfd712b4SDavid van Moolenbroek * Watchdog timer management. These functions in this file provide a
3433d6423SLionel Sambuc * convenient interface to the timers library that manages a list of
4433d6423SLionel Sambuc * watchdog timers. All details of scheduling an alarm at the CLOCK task
5433d6423SLionel Sambuc * are hidden behind this interface.
6433d6423SLionel Sambuc *
7433d6423SLionel Sambuc * The entry points into this file are:
8433d6423SLionel Sambuc * init_timer: initialize a timer structure
9433d6423SLionel Sambuc * set_timer: reset and existing or set a new watchdog timer
10433d6423SLionel Sambuc * cancel_timer: remove a timer from the list of timers
11433d6423SLionel Sambuc * expire_timers: check for expired timers and run watchdog functions
12433d6423SLionel Sambuc *
13433d6423SLionel Sambuc */
14433d6423SLionel Sambuc
15433d6423SLionel Sambuc #include "syslib.h"
16433d6423SLionel Sambuc #include <minix/timers.h>
17433d6423SLionel Sambuc #include <minix/sysutil.h>
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc static minix_timer_t *timers = NULL;
20*cfd712b4SDavid van Moolenbroek static int expiring = FALSE;
21433d6423SLionel Sambuc
22*cfd712b4SDavid van Moolenbroek /*
23*cfd712b4SDavid van Moolenbroek * Initialize the timer 'tp'.
24*cfd712b4SDavid van Moolenbroek */
25*cfd712b4SDavid van Moolenbroek void
init_timer(minix_timer_t * tp)26*cfd712b4SDavid van Moolenbroek init_timer(minix_timer_t * tp)
27433d6423SLionel Sambuc {
28*cfd712b4SDavid van Moolenbroek
29433d6423SLionel Sambuc tmr_inittimer(tp);
30433d6423SLionel Sambuc }
31433d6423SLionel Sambuc
32*cfd712b4SDavid van Moolenbroek /*
33*cfd712b4SDavid van Moolenbroek * Set the timer 'tp' to trigger 'ticks' clock ticks in the future. When it
34*cfd712b4SDavid van Moolenbroek * triggers, call function 'watchdog' with argument 'arg'. The given timer
35*cfd712b4SDavid van Moolenbroek * object must have been initialized with init_timer(3) already. The given
36*cfd712b4SDavid van Moolenbroek * number of ticks must be between 0 and TMRDIFF_MAX inclusive. A ticks value
37*cfd712b4SDavid van Moolenbroek * of zero will cause the alarm to trigger on the next clock tick. If the
38*cfd712b4SDavid van Moolenbroek * timer was already set, it will be canceled first.
39*cfd712b4SDavid van Moolenbroek */
40*cfd712b4SDavid van Moolenbroek void
set_timer(minix_timer_t * tp,clock_t ticks,tmr_func_t watchdog,int arg)41*cfd712b4SDavid van Moolenbroek set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg)
42433d6423SLionel Sambuc {
43*cfd712b4SDavid van Moolenbroek clock_t prev_time, next_time;
44*cfd712b4SDavid van Moolenbroek int r, had_timers;
45433d6423SLionel Sambuc
46*cfd712b4SDavid van Moolenbroek if (ticks > TMRDIFF_MAX)
47*cfd712b4SDavid van Moolenbroek panic("set_timer: ticks value too large: %u", (int)ticks);
48*cfd712b4SDavid van Moolenbroek
49*cfd712b4SDavid van Moolenbroek /* Add the timer to the list. */
50*cfd712b4SDavid van Moolenbroek had_timers = tmrs_settimer(&timers, tp, getticks() + ticks, watchdog,
51*cfd712b4SDavid van Moolenbroek arg, &prev_time, &next_time);
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc /* Reschedule our synchronous alarm if necessary. */
54*cfd712b4SDavid van Moolenbroek if (!expiring && (!had_timers || next_time != prev_time)) {
55*cfd712b4SDavid van Moolenbroek if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
56*cfd712b4SDavid van Moolenbroek panic("set_timer: couldn't set alarm: %d", r);
57433d6423SLionel Sambuc }
58433d6423SLionel Sambuc }
59433d6423SLionel Sambuc
60*cfd712b4SDavid van Moolenbroek /*
61*cfd712b4SDavid van Moolenbroek * Cancel the timer 'tp'. The timer object must have been initialized with
62*cfd712b4SDavid van Moolenbroek * init_timer(3) first. If the timer was not set before, the call is a no-op.
63*cfd712b4SDavid van Moolenbroek */
64*cfd712b4SDavid van Moolenbroek void
cancel_timer(minix_timer_t * tp)65*cfd712b4SDavid van Moolenbroek cancel_timer(minix_timer_t * tp)
66433d6423SLionel Sambuc {
67433d6423SLionel Sambuc clock_t next_time, prev_time;
68*cfd712b4SDavid van Moolenbroek int r, have_timers;
69433d6423SLionel Sambuc
70*cfd712b4SDavid van Moolenbroek if (!tmr_is_set(tp))
71*cfd712b4SDavid van Moolenbroek return;
72*cfd712b4SDavid van Moolenbroek
73*cfd712b4SDavid van Moolenbroek have_timers = tmrs_clrtimer(&timers, tp, &prev_time, &next_time);
74*cfd712b4SDavid van Moolenbroek
75*cfd712b4SDavid van Moolenbroek /*
76*cfd712b4SDavid van Moolenbroek * If the earliest timer has been removed, we have to set the alarm to
77433d6423SLionel Sambuc * the next timer, or cancel the alarm altogether if the last timer
78*cfd712b4SDavid van Moolenbroek * has been canceled.
79433d6423SLionel Sambuc */
80*cfd712b4SDavid van Moolenbroek if (!expiring) {
81*cfd712b4SDavid van Moolenbroek if (!have_timers)
82*cfd712b4SDavid van Moolenbroek r = sys_setalarm(0, FALSE /*abs_time*/);
83*cfd712b4SDavid van Moolenbroek else if (prev_time != next_time)
84*cfd712b4SDavid van Moolenbroek r = sys_setalarm(next_time, TRUE /*abs_time*/);
85*cfd712b4SDavid van Moolenbroek else
86*cfd712b4SDavid van Moolenbroek r = OK;
87*cfd712b4SDavid van Moolenbroek
88*cfd712b4SDavid van Moolenbroek if (r != OK)
89*cfd712b4SDavid van Moolenbroek panic("cancel_timer: couldn't set alarm: %d", r);
90433d6423SLionel Sambuc }
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc
93*cfd712b4SDavid van Moolenbroek /*
94*cfd712b4SDavid van Moolenbroek * Expire all timers that were set to expire before/at the given current time.
95*cfd712b4SDavid van Moolenbroek */
96*cfd712b4SDavid van Moolenbroek void
expire_timers(clock_t now)97*cfd712b4SDavid van Moolenbroek expire_timers(clock_t now)
98433d6423SLionel Sambuc {
99433d6423SLionel Sambuc clock_t next_time;
100*cfd712b4SDavid van Moolenbroek int r, have_timers;
101433d6423SLionel Sambuc
102*cfd712b4SDavid van Moolenbroek /*
103*cfd712b4SDavid van Moolenbroek * Check for expired timers. Use a global variable to indicate that
104433d6423SLionel Sambuc * watchdog functions are called, so that sys_setalarm() isn't called
105433d6423SLionel Sambuc * more often than necessary when set_timer or cancel_timer are called
106*cfd712b4SDavid van Moolenbroek * from these watchdog functions.
107*cfd712b4SDavid van Moolenbroek */
108*cfd712b4SDavid van Moolenbroek expiring = TRUE;
109*cfd712b4SDavid van Moolenbroek have_timers = tmrs_exptimers(&timers, now, &next_time);
110*cfd712b4SDavid van Moolenbroek expiring = FALSE;
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc /* Reschedule an alarm if necessary. */
113*cfd712b4SDavid van Moolenbroek if (have_timers) {
114*cfd712b4SDavid van Moolenbroek if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
115*cfd712b4SDavid van Moolenbroek panic("expire_timers: couldn't set alarm: %d", r);
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc }
118