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