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