xref: /minix/minix/include/minix/timers.h (revision 00e393ca)
1 /* This library provides generic watchdog timer management functionality.
2  * The functions operate on a timer queue provided by the caller. Note that
3  * the timers must use absolute time to allow sorting. The library provides:
4  *
5  *    tmrs_settimer:     (re)set a new watchdog timer in the timers queue
6  *    tmrs_clrtimer:     remove a timer from both the timers queue
7  *    tmrs_exptimers:    check for expired timers and run watchdog functions
8  *
9  * Author:
10  *    Jorrit N. Herder <jnherder@cs.vu.nl>
11  *    Adapted from tmr_settimer and tmr_clrtimer in src/kernel/clock.c.
12  *    Last modified: September 30, 2004.
13  */
14 #ifndef _MINIX_TIMERS_H
15 #define _MINIX_TIMERS_H
16 
17 #include <limits.h>
18 
19 #include <sys/types.h>
20 #include <minix/const.h>
21 #include <minix/u64.h>
22 #include <minix/minlib.h>
23 #include <minix/endpoint.h>
24 
25 typedef void (*tmr_func_t)(int arg);
26 
27 /* A minix_timer_t variable must be declare for each distinct timer to be used.
28  * The timers watchdog function and expiration time are automatically set
29  * by the library function tmrs_settimer, but its argument is not.  In general,
30  * the timer is in use when it has a callback function.
31  */
32 typedef struct minix_timer
33 {
34   struct minix_timer	*tmr_next;	/* next in a timer chain */
35   clock_t 		tmr_exp_time;	/* expiration time (absolute) */
36   tmr_func_t		tmr_func;	/* function to call when expired */
37   int			tmr_arg;	/* integer argument */
38 } minix_timer_t;
39 
40 /*
41  * Clock times may wrap.  Thus, we must only ever compare relative times, which
42  * means they must be no more than half the total maximum time value apart.
43  * The clock_t type is unsigned (int or long), thus we take half that.
44  */
45 #define TMRDIFF_MAX		(INT_MAX)
46 
47 /* This value must be used only instead of a timer difference value. */
48 #define TMR_NEVER		((clock_t)TMRDIFF_MAX + 1)
49 
50 /* These definitions can be used to set or get data from a timer variable. */
51 #define tmr_exp_time(tp)	((tp)->tmr_exp_time)
52 #define tmr_is_set(tp)		((tp)->tmr_func != NULL)
53 /*
54  * tmr_is_first() returns TRUE iff the first given absolute time is sooner than
55  * or equal to the second given time.
56  */
57 #define tmr_is_first(a,b)	((clock_t)(b) - (clock_t)(a) <= TMRDIFF_MAX)
58 #define tmr_has_expired(tp,now)	tmr_is_first((tp)->tmr_exp_time, (now))
59 
60 /* Timers should be initialized once before they are being used. Be careful
61  * not to reinitialize a timer that is in a list of timers, or the chain
62  * will be broken.
63  */
64 #define tmr_inittimer(tp) (void)((tp)->tmr_func = NULL, (tp)->tmr_next = NULL)
65 
66 /* The following generic timer management functions are available. They
67  * can be used to operate on the lists of timers. Adding a timer to a list
68  * automatically takes care of removing it.
69  */
70 int tmrs_settimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t exp_time,
71 	tmr_func_t watchdog, int arg, clock_t *old_head, clock_t *new_head);
72 int tmrs_clrtimer(minix_timer_t **tmrs, minix_timer_t *tp, clock_t *old_head,
73 	clock_t *new_head);
74 int tmrs_exptimers(minix_timer_t **tmrs, clock_t now, clock_t *new_head);
75 
76 #define PRINT_STATS(cum_spenttime, cum_instances) {		\
77 		if(ex64hi(cum_spenttime)) { util_stacktrace(); printf(" ( ??? %lu %lu)\n",	\
78 			ex64hi(cum_spenttime), ex64lo(cum_spenttime)); } \
79 		printf("%s:%d,%lu,%lu\n", \
80 			__FILE__, __LINE__, cum_instances,	\
81 			 ex64lo(cum_spenttime)); \
82 	}
83 
84 #define RESET_STATS(starttime, cum_instances, cum_spenttime, cum_starttime) { \
85 		cum_instances = 0;				\
86 		cum_starttime = starttime;			\
87 		cum_spenttime = make64(0,0);			\
88 }
89 
90 #define TIME_BLOCK_VAR(timed_code_block, time_interval) do {	\
91 	static u64_t _cum_spenttime, _cum_starttime;		\
92 	static int _cum_instances;				\
93 	u64_t _next_cum_spent, _starttime, _endtime, _dt, _cum_dt;	\
94 	u32_t _dt_micros;					\
95 	read_tsc_64(&_starttime);				\
96 	do { timed_code_block } while(0);			\
97 	read_tsc_64(&_endtime);					\
98 	_dt = _endtime - _starttime;				\
99 	if(_cum_instances == 0) {				\
100 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); \
101 	 }							\
102 	_next_cum_spent = add64(_cum_spenttime, _dt);		\
103 	if(ex64hi(_next_cum_spent)) { 				\
104 		PRINT_STATS(_cum_spenttime, _cum_instances);	\
105 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); \
106 	} 							\
107 	_cum_spenttime = add64(_cum_spenttime, _dt);		\
108 	_cum_instances++;					\
109 	_cum_dt = _endtime - _cum_starttime;			\
110 	if(_cum_dt > make64(0, 120)) {				\
111 		PRINT_STATS(_cum_spenttime, _cum_instances);	\
112 		RESET_STATS(_starttime, _cum_instances, _cum_spenttime, _cum_starttime); 	\
113 	} 							\
114 } while(0)
115 
116 #define TIME_BLOCK(timed_code_block) TIME_BLOCK_VAR(timed_code_block, 100)
117 #define TIME_BLOCK_T(timed_code_block, t) TIME_BLOCK_VAR(timed_code_block, t)
118 
119 /* Timers abstraction for system processes. This would be in minix/sysutil.h
120  * if it weren't for naming conflicts.
121  */
122 
123 void init_timer(minix_timer_t *tp);
124 void set_timer(minix_timer_t *tp, clock_t ticks, tmr_func_t watchdog, int arg);
125 void cancel_timer(minix_timer_t *tp);
126 void expire_timers(clock_t now);
127 
128 #endif /* _MINIX_TIMERS_H */
129