xref: /onnv-gate/usr/src/lib/libshell/common/sh/timers.c (revision 12068:08a39a083754)
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