1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1982-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * David Korn <dgk@research.att.com> * 18*4887Schin * * 19*4887Schin ***********************************************************************/ 20*4887Schin #pragma prototyped 21*4887Schin 22*4887Schin #include <ast.h> 23*4887Schin #include <sig.h> 24*4887Schin #include <error.h> 25*4887Schin #include "fault.h" 26*4887Schin #include "defs.h" 27*4887Schin #include "FEATURE/sigfeatures" 28*4887Schin #include "FEATURE/time" 29*4887Schin 30*4887Schin typedef struct _timer 31*4887Schin { 32*4887Schin double wakeup; 33*4887Schin double incr; 34*4887Schin struct _timer *next; 35*4887Schin void (*action)(void*); 36*4887Schin void *handle; 37*4887Schin } Timer_t; 38*4887Schin 39*4887Schin #define IN_ADDTIMEOUT 1 40*4887Schin #define IN_SIGALRM 2 41*4887Schin #define DEFER_SIGALRM 4 42*4887Schin #define SIGALRM_CALL 8 43*4887Schin 44*4887Schin static Timer_t *tptop, *tpmin, *tpfree; 45*4887Schin static char time_state; 46*4887Schin 47*4887Schin static double getnow(void) 48*4887Schin { 49*4887Schin register double now; 50*4887Schin #ifdef timeofday 51*4887Schin struct timeval tp; 52*4887Schin timeofday(&tp); 53*4887Schin now = tp.tv_sec + 1.e-6*tp.tv_usec; 54*4887Schin 55*4887Schin #else 56*4887Schin now = (double)time((time_t*)0); 57*4887Schin #endif /* timeofday */ 58*4887Schin return(now+.001); 59*4887Schin } 60*4887Schin 61*4887Schin /* 62*4887Schin * set an alarm for <t> seconds 63*4887Schin */ 64*4887Schin static double setalarm(register double t) 65*4887Schin { 66*4887Schin #if defined(_lib_setitimer) && defined(ITIMER_REAL) 67*4887Schin struct itimerval tnew, told; 68*4887Schin tnew.it_value.tv_sec = t; 69*4887Schin tnew.it_value.tv_usec = 1.e6*(t- (double)tnew.it_value.tv_sec); 70*4887Schin if(t && tnew.it_value.tv_sec==0 && tnew.it_value.tv_usec<1000) 71*4887Schin tnew.it_value.tv_usec = 1000; 72*4887Schin tnew.it_interval.tv_sec = 0; 73*4887Schin tnew.it_interval.tv_usec = 0; 74*4887Schin if(setitimer(ITIMER_REAL,&tnew,&told) < 0) 75*4887Schin errormsg(SH_DICT,ERROR_system(1),e_alarm); 76*4887Schin t = told.it_value.tv_sec + 1.e-6*told.it_value.tv_usec; 77*4887Schin #else 78*4887Schin unsigned seconds = (unsigned)t; 79*4887Schin if(t && seconds<1) 80*4887Schin seconds=1; 81*4887Schin t = (double)alarm(seconds); 82*4887Schin #endif 83*4887Schin return(t); 84*4887Schin } 85*4887Schin 86*4887Schin /* signal handler for alarm call */ 87*4887Schin static void sigalrm(int sig) 88*4887Schin { 89*4887Schin register Timer_t *tp, *tplast, *tpold, *tpnext; 90*4887Schin double now; 91*4887Schin static double left; 92*4887Schin NOT_USED(sig); 93*4887Schin left = 0; 94*4887Schin if(time_state&SIGALRM_CALL) 95*4887Schin time_state &= ~SIGALRM_CALL; 96*4887Schin else if(alarm(0)) 97*4887Schin sh_fault(SIGALRM|SH_TRAP); 98*4887Schin if(time_state) 99*4887Schin { 100*4887Schin if(time_state&IN_ADDTIMEOUT) 101*4887Schin time_state |= DEFER_SIGALRM; 102*4887Schin errno = EINTR; 103*4887Schin return; 104*4887Schin } 105*4887Schin time_state |= IN_SIGALRM; 106*4887Schin sigrelease(SIGALRM); 107*4887Schin while(1) 108*4887Schin { 109*4887Schin now = getnow(); 110*4887Schin tpold = tpmin = 0; 111*4887Schin for(tplast=0,tp=tptop; tp; tp=tpnext) 112*4887Schin { 113*4887Schin tpnext = tp->next; 114*4887Schin if(tp->action) 115*4887Schin { 116*4887Schin if(tp->wakeup <=now) 117*4887Schin { 118*4887Schin if(!tpold || tpold->wakeup>tp->wakeup) 119*4887Schin tpold = tp; 120*4887Schin } 121*4887Schin else 122*4887Schin { 123*4887Schin if(!tpmin || tpmin->wakeup>tp->wakeup) 124*4887Schin tpmin=tp; 125*4887Schin } 126*4887Schin tplast = tp; 127*4887Schin } 128*4887Schin else 129*4887Schin { 130*4887Schin if(tplast) 131*4887Schin tplast->next = tp->next; 132*4887Schin else 133*4887Schin tptop = tp->next; 134*4887Schin tp->next = tpfree; 135*4887Schin tpfree = tp; 136*4887Schin } 137*4887Schin } 138*4887Schin if((tp=tpold) && tp->incr) 139*4887Schin { 140*4887Schin while((tp->wakeup += tp->incr) <= now); 141*4887Schin if(!tpmin || tpmin->wakeup>tp->wakeup) 142*4887Schin tpmin=tp; 143*4887Schin } 144*4887Schin if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left)))) 145*4887Schin { 146*4887Schin if(left==0) 147*4887Schin signal(SIGALRM,sigalrm); 148*4887Schin left = setalarm(tpmin->wakeup-now); 149*4887Schin if(left && (now+left) < tpmin->wakeup) 150*4887Schin setalarm(left); 151*4887Schin else 152*4887Schin left=tpmin->wakeup-now; 153*4887Schin } 154*4887Schin if(tp) 155*4887Schin { 156*4887Schin void (*action)(void*); 157*4887Schin action = tp->action; 158*4887Schin if(!tp->incr) 159*4887Schin tp->action = 0; 160*4887Schin errno = EINTR; 161*4887Schin time_state &= ~IN_SIGALRM; 162*4887Schin (*action)(tp->handle); 163*4887Schin time_state |= IN_SIGALRM; 164*4887Schin } 165*4887Schin else 166*4887Schin break; 167*4887Schin } 168*4887Schin if(!tpmin) 169*4887Schin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL); 170*4887Schin time_state &= ~IN_SIGALRM; 171*4887Schin errno = EINTR; 172*4887Schin } 173*4887Schin 174*4887Schin static void oldalrm(void *handle) 175*4887Schin { 176*4887Schin Handler_t fn = *(Handler_t*)handle; 177*4887Schin free(handle); 178*4887Schin (*fn)(SIGALRM); 179*4887Schin } 180*4887Schin 181*4887Schin void *sh_timeradd(unsigned long msec,int flags,void (*action)(void*),void *handle) 182*4887Schin { 183*4887Schin register Timer_t *tp; 184*4887Schin double t; 185*4887Schin Handler_t fn; 186*4887Schin t = ((double)msec)/1000.; 187*4887Schin if(t<=0 || !action) 188*4887Schin return((void*)0); 189*4887Schin if(tp=tpfree) 190*4887Schin tpfree = tp->next; 191*4887Schin else if(!(tp=(Timer_t*)malloc(sizeof(Timer_t)))) 192*4887Schin return((void*)0); 193*4887Schin tp->wakeup = getnow() + t; 194*4887Schin tp->incr = (flags?t:0); 195*4887Schin tp->action = action; 196*4887Schin tp->handle = handle; 197*4887Schin time_state |= IN_ADDTIMEOUT; 198*4887Schin tp->next = tptop; 199*4887Schin tptop = tp; 200*4887Schin if(!tpmin || tp->wakeup < tpmin->wakeup) 201*4887Schin { 202*4887Schin tpmin = tp; 203*4887Schin fn = (Handler_t)signal(SIGALRM,sigalrm); 204*4887Schin if((t= setalarm(t))>0 && fn && fn!=(Handler_t)sigalrm) 205*4887Schin { 206*4887Schin Handler_t *hp = (Handler_t*)malloc(sizeof(Handler_t)); 207*4887Schin if(hp) 208*4887Schin { 209*4887Schin *hp = fn; 210*4887Schin sh_timeradd((long)(1000*t), 0, oldalrm, (void*)hp); 211*4887Schin } 212*4887Schin } 213*4887Schin tp = tptop; 214*4887Schin } 215*4887Schin else if(tpmin && !tpmin->action) 216*4887Schin time_state |= DEFER_SIGALRM; 217*4887Schin time_state &= ~IN_ADDTIMEOUT; 218*4887Schin if(time_state&DEFER_SIGALRM) 219*4887Schin { 220*4887Schin time_state=SIGALRM_CALL; 221*4887Schin sigalrm(SIGALRM); 222*4887Schin if(tp!=tptop) 223*4887Schin tp=0; 224*4887Schin } 225*4887Schin return((void*)tp); 226*4887Schin } 227*4887Schin 228*4887Schin /* 229*4887Schin * delete timer <tp>. If <tp> is NULL, all timers are deleted 230*4887Schin */ 231*4887Schin void timerdel(void *handle) 232*4887Schin { 233*4887Schin register Timer_t *tp = (Timer_t*)handle; 234*4887Schin if(tp) 235*4887Schin tp->action = 0; 236*4887Schin else 237*4887Schin { 238*4887Schin for(tp=tptop; tp; tp=tp->next) 239*4887Schin tp->action = 0; 240*4887Schin if(tpmin) 241*4887Schin { 242*4887Schin tpmin = 0; 243*4887Schin setalarm((double)0); 244*4887Schin } 245*4887Schin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL); 246*4887Schin } 247*4887Schin } 248*4887Schin 249