summaryrefslogtreecommitdiff
path: root/minix/lib/libsys/timers.c
blob: d403bf0c6b2b9428865ce17bc51f3b81b77cc678 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Watchdog timer management. These functions in this file provide a
 * convenient interface to the timers library that manages a list of
 * watchdog timers. All details of scheduling an alarm at the CLOCK task
 * are hidden behind this interface.
 *
 * The entry points into this file are:
 *   init_timer:     initialize a timer structure
 *   set_timer:      reset and existing or set a new watchdog timer
 *   cancel_timer:   remove a timer from the list of timers
 *   expire_timers:  check for expired timers and run watchdog functions
 *
 */

#include "syslib.h"
#include <minix/timers.h>
#include <minix/sysutil.h>

static minix_timer_t *timers = NULL;
static int expiring = FALSE;

/*
 * Initialize the timer 'tp'.
 */
void
init_timer(minix_timer_t * tp)
{

	tmr_inittimer(tp);
}

/*
 * Set the timer 'tp' to trigger 'ticks' clock ticks in the future.  When it
 * triggers, call function 'watchdog' with argument 'arg'.  The given timer
 * object must have been initialized with init_timer(3) already.  The given
 * number of ticks must be between 0 and TMRDIFF_MAX inclusive.  A ticks value
 * of zero will cause the alarm to trigger on the next clock tick.  If the
 * timer was already set, it will be canceled first.
 */
void
set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg)
{
	clock_t prev_time, next_time;
	int r, had_timers;

	if (ticks > TMRDIFF_MAX)
		panic("set_timer: ticks value too large: %u", (int)ticks);

	/* Add the timer to the list. */
	had_timers = tmrs_settimer(&timers, tp, getticks() + ticks, watchdog,
	    arg, &prev_time, &next_time);

	/* Reschedule our synchronous alarm if necessary. */
	if (!expiring && (!had_timers || next_time != prev_time)) {
		if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
			panic("set_timer: couldn't set alarm: %d", r);
        }
}

/*
 * Cancel the timer 'tp'.  The timer object must have been initialized with
 * init_timer(3) first.  If the timer was not set before, the call is a no-op.
 */
void
cancel_timer(minix_timer_t * tp)
{
	clock_t next_time, prev_time;
	int r, have_timers;

	if (!tmr_is_set(tp))
		return;

	have_timers = tmrs_clrtimer(&timers, tp, &prev_time, &next_time);

	/*
	 * If the earliest timer has been removed, we have to set the alarm to
	 * the next timer, or cancel the alarm altogether if the last timer
	 * has been canceled.
	 */
        if (!expiring) {
		if (!have_timers)
			r = sys_setalarm(0, FALSE /*abs_time*/);
		else if (prev_time != next_time)
			r = sys_setalarm(next_time, TRUE /*abs_time*/);
		else
			r = OK;

		if (r != OK)
                        panic("cancel_timer: couldn't set alarm: %d", r);
        }
}

/*
 * Expire all timers that were set to expire before/at the given current time.
 */
void
expire_timers(clock_t now)
{
        clock_t next_time;
	int r, have_timers;

	/*
	 * Check for expired timers. Use a global variable to indicate that
	 * watchdog functions are called, so that sys_setalarm() isn't called
	 * more often than necessary when set_timer or cancel_timer are called
	 * from these watchdog functions.
	 */
	expiring = TRUE;
	have_timers = tmrs_exptimers(&timers, now, &next_time);
	expiring = FALSE;

	/* Reschedule an alarm if necessary. */
	if (have_timers) {
		if ((r = sys_setalarm(next_time, TRUE /*abs_time*/)) != OK)
			panic("expire_timers: couldn't set alarm: %d", r);
	}
}