14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * David Korn <dgk@research.att.com> * 184887Schin * * 194887Schin ***********************************************************************/ 204887Schin #pragma prototyped 214887Schin 224887Schin #include <ast.h> 234887Schin #include <sig.h> 244887Schin #include <error.h> 254887Schin #include "fault.h" 264887Schin #include "defs.h" 274887Schin #include "FEATURE/sigfeatures" 284887Schin #include "FEATURE/time" 294887Schin 304887Schin typedef struct _timer 314887Schin { 324887Schin double wakeup; 334887Schin double incr; 344887Schin struct _timer *next; 354887Schin void (*action)(void*); 364887Schin void *handle; 374887Schin } Timer_t; 384887Schin 394887Schin #define IN_ADDTIMEOUT 1 404887Schin #define IN_SIGALRM 2 414887Schin #define DEFER_SIGALRM 4 424887Schin #define SIGALRM_CALL 8 434887Schin 444887Schin static Timer_t *tptop, *tpmin, *tpfree; 454887Schin static char time_state; 464887Schin 474887Schin static double getnow(void) 484887Schin { 494887Schin register double now; 504887Schin #ifdef timeofday 514887Schin struct timeval tp; 524887Schin timeofday(&tp); 534887Schin now = tp.tv_sec + 1.e-6*tp.tv_usec; 544887Schin 554887Schin #else 564887Schin now = (double)time((time_t*)0); 574887Schin #endif /* timeofday */ 584887Schin return(now+.001); 594887Schin } 604887Schin 614887Schin /* 624887Schin * set an alarm for <t> seconds 634887Schin */ 644887Schin static double setalarm(register double t) 654887Schin { 664887Schin #if defined(_lib_setitimer) && defined(ITIMER_REAL) 674887Schin struct itimerval tnew, told; 684887Schin tnew.it_value.tv_sec = t; 694887Schin tnew.it_value.tv_usec = 1.e6*(t- (double)tnew.it_value.tv_sec); 704887Schin if(t && tnew.it_value.tv_sec==0 && tnew.it_value.tv_usec<1000) 714887Schin tnew.it_value.tv_usec = 1000; 724887Schin tnew.it_interval.tv_sec = 0; 734887Schin tnew.it_interval.tv_usec = 0; 744887Schin if(setitimer(ITIMER_REAL,&tnew,&told) < 0) 754887Schin errormsg(SH_DICT,ERROR_system(1),e_alarm); 764887Schin t = told.it_value.tv_sec + 1.e-6*told.it_value.tv_usec; 774887Schin #else 784887Schin unsigned seconds = (unsigned)t; 794887Schin if(t && seconds<1) 804887Schin seconds=1; 814887Schin t = (double)alarm(seconds); 824887Schin #endif 834887Schin return(t); 844887Schin } 854887Schin 864887Schin /* signal handler for alarm call */ 874887Schin static void sigalrm(int sig) 884887Schin { 894887Schin register Timer_t *tp, *tplast, *tpold, *tpnext; 904887Schin double now; 914887Schin static double left; 924887Schin NOT_USED(sig); 934887Schin left = 0; 944887Schin if(time_state&SIGALRM_CALL) 954887Schin time_state &= ~SIGALRM_CALL; 964887Schin else if(alarm(0)) 974887Schin sh_fault(SIGALRM|SH_TRAP); 984887Schin if(time_state) 994887Schin { 1004887Schin if(time_state&IN_ADDTIMEOUT) 1014887Schin time_state |= DEFER_SIGALRM; 1024887Schin errno = EINTR; 1034887Schin return; 1044887Schin } 1054887Schin time_state |= IN_SIGALRM; 1064887Schin sigrelease(SIGALRM); 1074887Schin while(1) 1084887Schin { 1094887Schin now = getnow(); 1104887Schin tpold = tpmin = 0; 1114887Schin for(tplast=0,tp=tptop; tp; tp=tpnext) 1124887Schin { 1134887Schin tpnext = tp->next; 1144887Schin if(tp->action) 1154887Schin { 1164887Schin if(tp->wakeup <=now) 1174887Schin { 1184887Schin if(!tpold || tpold->wakeup>tp->wakeup) 1194887Schin tpold = tp; 1204887Schin } 1214887Schin else 1224887Schin { 1234887Schin if(!tpmin || tpmin->wakeup>tp->wakeup) 1244887Schin tpmin=tp; 1254887Schin } 1264887Schin tplast = tp; 1274887Schin } 1284887Schin else 1294887Schin { 1304887Schin if(tplast) 1314887Schin tplast->next = tp->next; 1324887Schin else 1334887Schin tptop = tp->next; 1344887Schin tp->next = tpfree; 1354887Schin tpfree = tp; 1364887Schin } 1374887Schin } 1384887Schin if((tp=tpold) && tp->incr) 1394887Schin { 1404887Schin while((tp->wakeup += tp->incr) <= now); 1414887Schin if(!tpmin || tpmin->wakeup>tp->wakeup) 1424887Schin tpmin=tp; 1434887Schin } 1444887Schin if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left)))) 1454887Schin { 1464887Schin if(left==0) 1474887Schin signal(SIGALRM,sigalrm); 1484887Schin left = setalarm(tpmin->wakeup-now); 1494887Schin if(left && (now+left) < tpmin->wakeup) 1504887Schin setalarm(left); 1514887Schin else 1524887Schin left=tpmin->wakeup-now; 1534887Schin } 1544887Schin if(tp) 1554887Schin { 1564887Schin void (*action)(void*); 1574887Schin action = tp->action; 1584887Schin if(!tp->incr) 1594887Schin tp->action = 0; 1604887Schin errno = EINTR; 1614887Schin time_state &= ~IN_SIGALRM; 1624887Schin (*action)(tp->handle); 1634887Schin time_state |= IN_SIGALRM; 1644887Schin } 1654887Schin else 1664887Schin break; 1674887Schin } 1684887Schin if(!tpmin) 1694887Schin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL); 1704887Schin time_state &= ~IN_SIGALRM; 1714887Schin errno = EINTR; 1724887Schin } 1734887Schin 1744887Schin static void oldalrm(void *handle) 1754887Schin { 1764887Schin Handler_t fn = *(Handler_t*)handle; 1774887Schin free(handle); 1784887Schin (*fn)(SIGALRM); 1794887Schin } 1804887Schin 1814887Schin void *sh_timeradd(unsigned long msec,int flags,void (*action)(void*),void *handle) 1824887Schin { 1834887Schin register Timer_t *tp; 1844887Schin double t; 1854887Schin Handler_t fn; 1864887Schin t = ((double)msec)/1000.; 1874887Schin if(t<=0 || !action) 1884887Schin return((void*)0); 1894887Schin if(tp=tpfree) 1904887Schin tpfree = tp->next; 1914887Schin else if(!(tp=(Timer_t*)malloc(sizeof(Timer_t)))) 1924887Schin return((void*)0); 1934887Schin tp->wakeup = getnow() + t; 1944887Schin tp->incr = (flags?t:0); 1954887Schin tp->action = action; 1964887Schin tp->handle = handle; 1974887Schin time_state |= IN_ADDTIMEOUT; 1984887Schin tp->next = tptop; 1994887Schin tptop = tp; 2004887Schin if(!tpmin || tp->wakeup < tpmin->wakeup) 2014887Schin { 2024887Schin tpmin = tp; 2034887Schin fn = (Handler_t)signal(SIGALRM,sigalrm); 2044887Schin if((t= setalarm(t))>0 && fn && fn!=(Handler_t)sigalrm) 2054887Schin { 2064887Schin Handler_t *hp = (Handler_t*)malloc(sizeof(Handler_t)); 2074887Schin if(hp) 2084887Schin { 2094887Schin *hp = fn; 2104887Schin sh_timeradd((long)(1000*t), 0, oldalrm, (void*)hp); 2114887Schin } 2124887Schin } 2134887Schin tp = tptop; 2144887Schin } 2154887Schin else if(tpmin && !tpmin->action) 2164887Schin time_state |= DEFER_SIGALRM; 2174887Schin time_state &= ~IN_ADDTIMEOUT; 2184887Schin if(time_state&DEFER_SIGALRM) 2194887Schin { 2204887Schin time_state=SIGALRM_CALL; 2214887Schin sigalrm(SIGALRM); 2224887Schin if(tp!=tptop) 2234887Schin tp=0; 2244887Schin } 2254887Schin return((void*)tp); 2264887Schin } 2274887Schin 2284887Schin /* 2294887Schin * delete timer <tp>. If <tp> is NULL, all timers are deleted 2304887Schin */ 2314887Schin void timerdel(void *handle) 2324887Schin { 2334887Schin register Timer_t *tp = (Timer_t*)handle; 2344887Schin if(tp) 2354887Schin tp->action = 0; 2364887Schin else 2374887Schin { 2384887Schin for(tp=tptop; tp; tp=tp->next) 2394887Schin tp->action = 0; 2404887Schin if(tpmin) 2414887Schin { 2424887Schin tpmin = 0; 2434887Schin setalarm((double)0); 2444887Schin } 2454887Schin signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL); 2464887Schin } 2474887Schin } 2484887Schin 249