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