xref: /minix3/minix/include/minix/timers.h (revision cfd712b4245f67a5631cc14e950ce43b18455602)
1433d6423SLionel Sambuc /* This library provides generic watchdog timer management functionality.
2433d6423SLionel Sambuc  * The functions operate on a timer queue provided by the caller. Note that
3433d6423SLionel Sambuc  * the timers must use absolute time to allow sorting. The library provides:
4433d6423SLionel Sambuc  *
5433d6423SLionel Sambuc  *    tmrs_settimer:     (re)set a new watchdog timer in the timers queue
6433d6423SLionel Sambuc  *    tmrs_clrtimer:     remove a timer from both the timers queue
7433d6423SLionel Sambuc  *    tmrs_exptimers:    check for expired timers and run watchdog functions
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  * Author:
10433d6423SLionel Sambuc  *    Jorrit N. Herder <jnherder@cs.vu.nl>
11433d6423SLionel Sambuc  *    Adapted from tmr_settimer and tmr_clrtimer in src/kernel/clock.c.
12433d6423SLionel Sambuc  *    Last modified: September 30, 2004.
13433d6423SLionel Sambuc  */
14433d6423SLionel Sambuc #ifndef _MINIX_TIMERS_H
15433d6423SLionel Sambuc #define _MINIX_TIMERS_H
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc #include <limits.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include <sys/types.h>
20*cfd712b4SDavid van Moolenbroek #include <minix/const.h>
21433d6423SLionel Sambuc #include <minix/u64.h>
22433d6423SLionel Sambuc #include <minix/minlib.h>
23433d6423SLionel Sambuc #include <minix/endpoint.h>
24433d6423SLionel Sambuc 
25*cfd712b4SDavid van Moolenbroek typedef void (*tmr_func_t)(int arg);
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc /* A minix_timer_t variable must be declare for each distinct timer to be used.
28433d6423SLionel Sambuc  * The timers watchdog function and expiration time are automatically set
29*cfd712b4SDavid van Moolenbroek  * by the library function tmrs_settimer, but its argument is not.  In general,
30*cfd712b4SDavid van Moolenbroek  * the timer is in use when it has a callback function.
31433d6423SLionel Sambuc  */
32433d6423SLionel Sambuc typedef struct minix_timer
33433d6423SLionel Sambuc {
34433d6423SLionel Sambuc   struct minix_timer	*tmr_next;	/* next in a timer chain */
35*cfd712b4SDavid van Moolenbroek   clock_t 		tmr_exp_time;	/* expiration time (absolute) */
36433d6423SLionel Sambuc   tmr_func_t		tmr_func;	/* function to call when expired */
37*cfd712b4SDavid van Moolenbroek   int			tmr_arg;	/* integer argument */
38433d6423SLionel Sambuc } minix_timer_t;
39433d6423SLionel Sambuc 
40*cfd712b4SDavid van Moolenbroek /*
41*cfd712b4SDavid van Moolenbroek  * Clock times may wrap.  Thus, we must only ever compare relative times, which
42*cfd712b4SDavid van Moolenbroek  * means they must be no more than half the total maximum time value apart.
43*cfd712b4SDavid van Moolenbroek  * The clock_t type is unsigned (int or long), thus we take half that.
44*cfd712b4SDavid van Moolenbroek  */
45*cfd712b4SDavid van Moolenbroek #define TMRDIFF_MAX		(INT_MAX)
46*cfd712b4SDavid van Moolenbroek 
47*cfd712b4SDavid van Moolenbroek /* This value must be used only instead of a timer difference value. */
48*cfd712b4SDavid van Moolenbroek #define TMR_NEVER		((clock_t)TMRDIFF_MAX + 1)
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc /* These definitions can be used to set or get data from a timer variable. */
51*cfd712b4SDavid van Moolenbroek #define tmr_exp_time(tp)	((tp)->tmr_exp_time)
52*cfd712b4SDavid van Moolenbroek #define tmr_is_set(tp)		((tp)->tmr_func != NULL)
53*cfd712b4SDavid van Moolenbroek /*
54*cfd712b4SDavid van Moolenbroek  * tmr_is_first() returns TRUE iff the first given absolute time is sooner than
55*cfd712b4SDavid van Moolenbroek  * or equal to the second given time.
56*cfd712b4SDavid van Moolenbroek  */
57*cfd712b4SDavid van Moolenbroek #define tmr_is_first(a,b)	((clock_t)(b) - (clock_t)(a) <= TMRDIFF_MAX)
58*cfd712b4SDavid van Moolenbroek #define tmr_has_expired(tp,now)	tmr_is_first((tp)->tmr_exp_time, (now))
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc /* Timers should be initialized once before they are being used. Be careful
61433d6423SLionel Sambuc  * not to reinitialize a timer that is in a list of timers, or the chain
62433d6423SLionel Sambuc  * will be broken.
63433d6423SLionel Sambuc  */
64*cfd712b4SDavid van Moolenbroek #define tmr_inittimer(tp) (void)((tp)->tmr_func = NULL, (tp)->tmr_next = NULL)
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc /* The following generic timer management functions are available. They
67433d6423SLionel Sambuc  * can be used to operate on the lists of timers. Adding a timer to a list
68433d6423SLionel Sambuc  * automatically takes care of removing it.
69433d6423SLionel Sambuc  */
70*cfd712b4SDavid van Moolenbroek int tmrs_settimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t exp_time,
71*cfd712b4SDavid van Moolenbroek 	tmr_func_t watchdog, int arg, clock_t *old_head, clock_t *new_head);
72*cfd712b4SDavid van Moolenbroek int tmrs_clrtimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t *old_head,
73*cfd712b4SDavid van Moolenbroek 	clock_t *new_head);
74*cfd712b4SDavid van Moolenbroek int tmrs_exptimers(minix_timer_t **tmrs, clock_t now, clock_t *new_head);
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc #define PRINT_STATS(cum_spenttime, cum_instances) {		\
77433d6423SLionel Sambuc 		if(ex64hi(cum_spenttime)) { util_stacktrace(); printf(" ( ??? %lu %lu)\n",	\
78433d6423SLionel Sambuc 			ex64hi(cum_spenttime), ex64lo(cum_spenttime)); } \
79433d6423SLionel Sambuc 		printf("%s:%d,%lu,%lu\n", \
80433d6423SLionel Sambuc 			__FILE__, __LINE__, cum_instances,	\
81433d6423SLionel Sambuc 			 ex64lo(cum_spenttime)); \
82433d6423SLionel Sambuc 	}
83433d6423SLionel Sambuc 
84433d6423SLionel Sambuc #define RESET_STATS(starttime, cum_instances, cum_spenttime, cum_starttime) { \
85433d6423SLionel Sambuc 		cum_instances = 0;				\
86433d6423SLionel Sambuc 		cum_starttime = starttime;			\
87433d6423SLionel Sambuc 		cum_spenttime = make64(0,0);			\
88433d6423SLionel Sambuc }
89433d6423SLionel Sambuc 
90433d6423SLionel Sambuc #define TIME_BLOCK_VAR(timed_code_block, time_interval) do {	\
91433d6423SLionel Sambuc 	static u64_t _cum_spenttime, _cum_starttime;		\
92433d6423SLionel Sambuc 	static int _cum_instances;				\
93433d6423SLionel Sambuc 	u64_t _next_cum_spent, _starttime, _endtime, _dt, _cum_dt;	\
94433d6423SLionel Sambuc 	u32_t _dt_micros;					\
95433d6423SLionel Sambuc 	read_tsc_64(&_starttime);				\
96433d6423SLionel Sambuc 	do { timed_code_block } while(0);			\
97433d6423SLionel Sambuc 	read_tsc_64(&_endtime);					\
98433d6423SLionel Sambuc 	_dt = _endtime - _starttime;				\
99433d6423SLionel Sambuc 	if(_cum_instances == 0) {				\
100433d6423SLionel Sambuc 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); \
101433d6423SLionel Sambuc 	 }							\
102433d6423SLionel Sambuc 	_next_cum_spent = add64(_cum_spenttime, _dt);		\
103433d6423SLionel Sambuc 	if(ex64hi(_next_cum_spent)) { 				\
104433d6423SLionel Sambuc 		PRINT_STATS(_cum_spenttime, _cum_instances);	\
105433d6423SLionel Sambuc 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); \
106433d6423SLionel Sambuc 	} 							\
107433d6423SLionel Sambuc 	_cum_spenttime = add64(_cum_spenttime, _dt);		\
108433d6423SLionel Sambuc 	_cum_instances++;					\
109433d6423SLionel Sambuc 	_cum_dt = _endtime - _cum_starttime;			\
110433d6423SLionel Sambuc 	if(_cum_dt > make64(0, 120)) {				\
111433d6423SLionel Sambuc 		PRINT_STATS(_cum_spenttime, _cum_instances);	\
112433d6423SLionel Sambuc 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); 	\
113433d6423SLionel Sambuc 	} 							\
114433d6423SLionel Sambuc } while(0)
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc #define TIME_BLOCK(timed_code_block) TIME_BLOCK_VAR(timed_code_block, 100)
117433d6423SLionel Sambuc #define TIME_BLOCK_T(timed_code_block, t) TIME_BLOCK_VAR(timed_code_block, t)
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc /* Timers abstraction for system processes. This would be in minix/sysutil.h
120433d6423SLionel Sambuc  * if it weren't for naming conflicts.
121433d6423SLionel Sambuc  */
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc void init_timer(minix_timer_t *tp);
124*cfd712b4SDavid van Moolenbroek void set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg);
125433d6423SLionel Sambuc void cancel_timer(minix_timer_t *tp);
126433d6423SLionel Sambuc void expire_timers(clock_t now);
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc #endif /* _MINIX_TIMERS_H */
129