14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1982-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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
getnow(void)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 */
setalarm(register double t)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 */
sigalrm(int sig)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
oldalrm(void * handle)1744887Schin static void oldalrm(void *handle)
1754887Schin {
1764887Schin Handler_t fn = *(Handler_t*)handle;
1774887Schin free(handle);
1784887Schin (*fn)(SIGALRM);
1794887Schin }
1804887Schin
sh_timeradd(unsigned long msec,int flags,void (* action)(void *),void * handle)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 */
timerdel(void * handle)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