#ifndef __timer_h_ #define __timer_h_ /* * general drawback: only supports one outstanding timeout at any time. * as partial consolation, the handler may chain another set_timeout. */ #include #include "mhz.h" void clock_handler(struct clockframe *frame); unsigned lapic_start; #if defined(PIT) # include "pit.h" #elif defined(APIC) # include "apic.h" #else # error define _some_ timer facility #endif volatile u_int64_t timeout_start = 0, timeout_duration = 0; void (*timeout_handler)(void) = 0; volatile int timeout_verbose = 0; /* call with >= splclock */ static __inline__ int timeout_error(void) /* in microseconds */ { int error = ((rdtsc() - timeout_start) - timeout_duration) / MHz; return error; } static __inline__ void cancel_timeout() { int s = splhigh(); if (timeout_handler || timeout_duration) { timeout_handler = NULL; timeout_duration = 0; } splx(s); } /* call with >= splclock */ static __inline__ void timeout_invoke() { int err = timeout_verbose ? timeout_error() : 0; void (*tmp_handler)(void) = timeout_handler; u_int64_t tmp_duration = timeout_duration; timeout_duration = 0; timeout_handler = NULL; if (timeout_verbose) printf("invoking %d us handler. error = %d us\n", (int)(tmp_duration / MHz), err); tmp_handler(); } void clock_handler(struct clockframe *frame) { int s = splhigh(); if (timeout_duration && timeout_handler && (rdtsc() - timeout_start) > timeout_duration) { timeout_invoke(); } splx(s); } static __inline__ void set_timeout(int microsecs, void (*handler)(void)) { if (microsecs && handler) { if (timeout_duration || timeout_handler) printf("timeout already set! retriggering.\n"); timeout_duration = microsecs; timeout_duration *= MHz; timeout_handler = handler; timeout_start = rdtsc(); } else { timeout_handler = NULL; timeout_duration = 0; } } void timeout_init(int freq) { int s = splhigh(); _timeout_init(freq); splx(s); DELAY(50000); } void timeout_deinit(void) { int s = splhigh(); if (timeout_duration && timeout_handler) timeout_invoke(); /* rather invoke early than never */ _timeout_deinit(); splx(s); DELAY(50000); } #endif