xref: /minix3/minix/lib/libsys/timers.c (revision cfd712b4245f67a5631cc14e950ce43b18455602)
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