#include #include #include #include "externs.h" void nap(double sec) { struct timeval tv; struct timeval now; struct timeval then; int n; gettimeofday(&now,0); tv.tv_sec = (int) sec; tv.tv_usec = (int) (1000000 * (sec - tv.tv_sec)); then.tv_sec = now.tv_sec + tv.tv_sec; then.tv_usec = now.tv_usec + tv.tv_usec; while (then.tv_usec >= 1000000) { then.tv_usec -= 1000000; then.tv_sec ++; } while (1) { errno = 0; /* assume that if 0 != nil-pointer, then we have prototypes */ n = select(0,0,0,0,&tv); gettimeofday(&now,0); tv.tv_sec = then.tv_sec - now.tv_sec; tv.tv_usec = then.tv_usec - now.tv_usec; while (tv.tv_usec < 0) { tv.tv_usec += 1000000; tv.tv_sec --; } if (tv.tv_sec < 0) { return; } } } #ifndef OPTIMIZE_TIME #include #include extern unsigned int alarm(unsigned int); unsigned long int curtm(void) { return(time(0)); } void set_alarm(int sec) { alarm(sec); } void set_alarm_handler(void (*h)(int)) { signal(SIGALRM,h); } void block_alarm(void) { sigset_t s; sigemptyset(&s); sigaddset(&s,SIGALRM); sigprocmask(SIG_BLOCK,&s,0); } void unblock_alarm(void) { sigset_t s; sigemptyset(&s); sigaddset(&s,SIGALRM); sigprocmask(SIG_UNBLOCK,&s,0); } #else #define RESYNC_SEC 3600 #define INSTANT_WRAP_COUNT 25 #define MIN_WRAPPED_LOAD 3 #define MAX_UNWRAPPED_LOAD 6 #ifdef TIME_DEBUG #include static FILE *errf; static FILE *sigf; #endif #include #include "defs.h" /* This file is full of paranoid code. Most of it has to be there, to guard against wraps or unwraps happening at unhelpful points in the code. */ static int didinit = 0; static int wrapped = 0; static int curtm_count = 0; static double curtm_load = 0; static int insignal = 0; static struct timeval nowtv; static unsigned long int now; static int resync; static unsigned long int alarmtime; static void (*alarmhandler)(int); static int alarmblocked; static int alarmpending; static double load(void) { curtm_load = (curtm_load * .8) + (curtm_count * .2); curtm_count = 0; #ifdef TIME_DEBUG fprintf(errf,"load=%g\n",curtm_load); #endif return(curtm_load); } static void wrap(void) { int m; struct itimerval itv; struct itimerval oitv; m = sigblock(sigmask(SIGALRM)); close(-100); /* harmless distinctive call for syscall tracers */ #ifdef TIME_DEBUG fprintf(errf,"wrapping\n"); #endif resync = RESYNC_SEC; wrapped = 1; now = nowtv.tv_sec; itv.it_interval.tv_sec = 1; itv.it_interval.tv_usec = 0; if (nowtv.tv_usec) { itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 1000000 - nowtv.tv_usec; } else { itv.it_value = itv.it_interval; } setitimer(ITIMER_REAL,&itv,&oitv); if (oitv.it_value.tv_sec || oitv.it_value.tv_usec) { oitv.it_value.tv_usec += nowtv.tv_usec; alarmtime = oitv.it_value.tv_sec + nowtv.tv_sec + 1; if (oitv.it_value.tv_usec < 1000000) alarmtime --; } else { alarmtime = 0; } sigsetmask(m&~sigmask(SIGALRM)); } static void unwrap(void) { int m; struct itimerval itv; m = sigblock(sigmask(SIGALRM)); close(-101); /* harmless distinctive call for syscall tracers */ #ifdef TIME_DEBUG fprintf(errf,"unwrapping\n"); #endif wrapped = 0; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; if (alarmtime) { if (now >= alarmtime) { itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 1; } else { itv.it_value.tv_sec = alarmtime - now; itv.it_value.tv_usec = 0; } } else { itv.it_value = itv.it_interval; } setitimer(ITIMER_REAL,&itv,0); if (! alarmblocked) sigsetmask(m); } static void sigalrm(int sig) { #ifdef TIME_DEBUG errf = sigf; fprintf(errf,"sigalrm %d\n",wrapped); #endif if (wrapped) { now ++; resync --; if (resync < 1) { resync = RESYNC_SEC; gettimeofday(&nowtv,0); now = nowtv.tv_sec; } #ifdef TIME_DEBUG fprintf(errf,"now=%d resync=%d\n",now,resync); #endif if (alarmtime && (now >= alarmtime)) { alarmtime = 0; #ifdef TIME_DEBUG fprintf(errf,"alarm went off\n"); #endif if (alarmblocked) { alarmpending = 1; } else { insignal = 1; (*alarmhandler)(SIGALRM); insignal = 0; } } if (load() < MIN_WRAPPED_LOAD) unwrap(); } else { insignal = 1; (*alarmhandler)(SIGALRM); insignal = 0; } #ifdef TIME_DEBUG errf = stderr; #endif } static void inittime(void) { struct sigvec sv; if (didinit) return; didinit = 1; #ifdef TIME_DEBUG errf = stderr; sigf = fdopen(2,"w"); setbuf(sigf,0); #endif sv.sv_handler = sigalrm; sv.sv_mask = 0; sv.sv_flags = 0; sigvec(SIGALRM,&sv,0); } unsigned long int curtm(void) { inittime(); if (wrapped) { curtm_count ++; #ifdef TIME_DEBUG fprintf(errf,"curtm %d wrapped -> %d\n",curtm_count,now); #endif return(now); } else { int oldnow; oldnow = now; gettimeofday(&nowtv,0); now = nowtv.tv_sec; curtm_count ++; #ifdef TIME_DEBUG fprintf(errf,"curtm %d unwrapped -> %d\n",curtm_count,now); #endif if (curtm_count > INSTANT_WRAP_COUNT) { curtm_load = INSTANT_WRAP_COUNT; wrap(); } else { if (now != oldnow) { if (load() > MAX_UNWRAPPED_LOAD) { wrap(); } } } return(now); } } void set_alarm(int sec) { int m; inittime(); if (! insignal) m = sigblock(sigmask(SIGALRM)); #ifdef TIME_DEBUG fprintf(errf,"set_alarm %d\n",sec); #endif if (wrapped) { alarmtime = now + sec; } else { struct itimerval itv; itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = sec; itv.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itv,0); } if (! insignal) sigsetmask(m); } void set_alarm_handler(void (*h)(int)) { int m; inittime(); m = sigblock(sigmask(SIGALRM)); #ifdef TIME_DEBUG fprintf(errf,"set_alarm_handler 0x%x\n",(int)h); #endif alarmhandler = h; sigsetmask(m); } void block_alarm(void) { inittime(); alarmblocked = 1; #ifdef TIME_DEBUG fprintf(errf,"block_alarm\n"); #endif if (! wrapped) { int m; m = sigblock(sigmask(SIGALRM)); if (wrapped) sigsetmask(m); } } void unblock_alarm(void) { int m; inittime(); #ifdef TIME_DEBUG fprintf(errf,"unblock_alarm\n"); #endif if (! alarmblocked) return; while (1) { m = sigblock(sigmask(SIGALRM)); if (wrapped) { if (alarmpending) { alarmpending = 0; (*alarmhandler)(SIGALRM); continue; } if (alarmpending) { sigsetmask(m); continue; } alarmblocked = 0; sigsetmask(m); break; } else { sigsetmask(m&~sigmask(SIGALRM)); break; } } } #endif