17358Seric # include "sendmail.h"
27358Seric 
3*9373Seric SCCSID(@(#)clock.c	3.13		11/28/82);
47358Seric 
57358Seric /*
67684Seric **  SETEVENT -- set an event to happen at a specific time.
77684Seric **
8*9373Seric **	Events are stored in a sorted list for fast processing.
9*9373Seric **	An event only applies to the process that set it.
10*9373Seric **
117684Seric **	Parameters:
127684Seric **		intvl -- intvl until next event occurs.
137684Seric **		func -- function to call on event.
147684Seric **		arg -- argument to func on event.
157684Seric **
167684Seric **	Returns:
177684Seric **		none.
187684Seric **
197684Seric **	Side Effects:
207684Seric **		none.
217684Seric */
227684Seric 
237684Seric EVENT *
247684Seric setevent(intvl, func, arg)
257684Seric 	time_t intvl;
267684Seric 	int (*func)();
277684Seric 	int arg;
287684Seric {
297684Seric 	register EVENT **evp;
307684Seric 	register EVENT *ev;
317684Seric 	auto time_t now;
327684Seric 	extern tick();
337684Seric 
347757Seric # ifdef DEBUG
357757Seric 	if (intvl <= 0)
367757Seric 	{
377757Seric 		syserr("setevent: intvl=%ld\n", intvl);
389346Seric 		return (NULL);
397757Seric 	}
407757Seric # endif DEBUG
417757Seric 
427684Seric 	(void) time(&now);
437684Seric 
447684Seric 	/* search event queue for correct position */
457684Seric 	for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
467684Seric 	{
477684Seric 		if (ev->ev_time >= now + intvl)
487684Seric 			break;
497684Seric 	}
507684Seric 
517684Seric 	/* insert new event */
527684Seric 	ev = (EVENT *) xalloc(sizeof *ev);
537684Seric 	ev->ev_time = now + intvl;
547684Seric 	ev->ev_func = func;
557684Seric 	ev->ev_arg = arg;
567931Seric 	ev->ev_pid = getpid();
577684Seric 	ev->ev_link = *evp;
587684Seric 	*evp = ev;
597684Seric 
607684Seric # ifdef DEBUG
618063Seric 	if (tTd(5, 5))
627684Seric 		printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
637684Seric 			intvl, now + intvl, func, arg, ev);
647684Seric # endif DEBUG
657684Seric 
667939Seric 	tick();
677684Seric 	return (ev);
687684Seric }
697684Seric /*
707684Seric **  CLREVENT -- remove an event from the event queue.
717684Seric **
727684Seric **	Parameters:
737684Seric **		ev -- pointer to event to remove.
747684Seric **
757684Seric **	Returns:
767684Seric **		none.
777684Seric **
787684Seric **	Side Effects:
797684Seric **		arranges for event ev to not happen.
807684Seric */
817684Seric 
827684Seric clrevent(ev)
837684Seric 	register EVENT *ev;
847684Seric {
857684Seric 	register EVENT **evp;
867684Seric 
877684Seric # ifdef DEBUG
888063Seric 	if (tTd(5, 5))
897684Seric 		printf("clrevent: ev=%x\n", ev);
907684Seric # endif DEBUG
917757Seric 	if (ev == NULL)
927757Seric 		return;
937684Seric 
947684Seric 	/* find the parent event */
95*9373Seric 	(void) signal(SIGALRM, SIG_IGN);
967684Seric 	for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
977684Seric 	{
987684Seric 		if (*evp == ev)
997684Seric 			break;
1007684Seric 	}
1017684Seric 
1027684Seric 	/* now remove it */
1037939Seric 	if (*evp != NULL)
1047939Seric 	{
1057939Seric 		*evp = ev->ev_link;
1069346Seric 		free((char *) ev);
1077939Seric 	}
1087862Seric 
1097862Seric 	/* restore clocks and pick up anything spare */
1107862Seric 	tick();
1117684Seric }
1127684Seric /*
1137358Seric **  TICK -- take a clock tick
1147358Seric **
1157684Seric **	Called by the alarm clock.  This routine runs events as needed.
1167358Seric **
1177358Seric **	Parameters:
1187358Seric **		none.
1197358Seric **
1207358Seric **	Returns:
1217684Seric **		none.
1227358Seric **
1237358Seric **	Side Effects:
1247684Seric **		calls the next function in EventQueue.
1257358Seric */
1267358Seric 
1277358Seric tick()
1287358Seric {
1297889Seric 	register time_t now;
1307684Seric 	register EVENT *ev;
1317684Seric 
132*9373Seric 	(void) signal(SIGALRM, SIG_IGN);
133*9373Seric 	(void) alarm(0);
1347889Seric 	now = curtime();
1357684Seric 
1367358Seric # ifdef DEBUG
1378063Seric 	if (tTd(5, 4))
1387684Seric 		printf("tick: now=%ld\n", now);
1397358Seric # endif DEBUG
1407684Seric 
1418128Seric 	while ((ev = EventQueue) != NULL &&
1428128Seric 	       (ev->ev_time <= now || ev->ev_pid != getpid()))
1437684Seric 	{
1447862Seric 		int (*f)(), a;
1457862Seric 
1467684Seric 		/* process the event on the top of the queue */
1477684Seric 		ev = EventQueue;
1487684Seric 		EventQueue = EventQueue->ev_link;
1497684Seric # ifdef DEBUG
1508063Seric 		if (tTd(5, 6))
1517931Seric 			printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev,
1527931Seric 				ev->ev_func, ev->ev_arg, ev->ev_pid);
1537684Seric # endif DEBUG
1547862Seric 
1557862Seric 		/* we must be careful in here because ev_func may not return */
156*9373Seric 		(void) signal(SIGALRM, tick);
1577862Seric 		f = ev->ev_func;
1587862Seric 		a = ev->ev_arg;
1599346Seric 		free((char *) ev);
1608128Seric 		if (ev->ev_pid != getpid())
1617931Seric 			continue;
1627862Seric 		if (EventQueue != NULL)
1637862Seric 		{
1647862Seric 			if (EventQueue->ev_time > now)
1657862Seric 				(void) alarm(EventQueue->ev_time - now);
1667862Seric 			else
1677889Seric 				(void) alarm(3);
1687862Seric 		}
1697862Seric 		(*f)(a);
1707862Seric 		(void) alarm(0);
1717889Seric 		now = curtime();
1727684Seric 	}
173*9373Seric 	(void) signal(SIGALRM, tick);
1747889Seric 	if (EventQueue != NULL)
1757889Seric 		(void) alarm(EventQueue->ev_time - now);
1767358Seric }
1777690Seric /*
1787690Seric **  SLEEP -- a version of sleep that works with this stuff
1797690Seric **
1807690Seric **	Because sleep uses the alarm facility, I must reimplement
1817690Seric **	it here.
1827690Seric **
1837690Seric **	Parameters:
1847690Seric **		intvl -- time to sleep.
1857690Seric **
1867690Seric **	Returns:
1877690Seric **		none.
1887690Seric **
1897690Seric **	Side Effects:
1907690Seric **		waits for intvl time.  However, other events can
1917690Seric **		be run during that interval.
1927690Seric */
1937690Seric 
1947690Seric static bool	SleepDone;
1957690Seric 
1967690Seric sleep(intvl)
1977690Seric 	int intvl;
1987690Seric {
1997690Seric 	extern endsleep();
2007690Seric 
2017757Seric 	if (intvl == 0)
2027757Seric 		return;
2037690Seric 	SleepDone = FALSE;
2049346Seric 	(void) setevent(intvl, endsleep, 0);
2057690Seric 	while (!SleepDone)
2067690Seric 		pause();
2077690Seric }
2087690Seric 
2097690Seric static
2107690Seric endsleep()
2117690Seric {
2127690Seric 	SleepDone = TRUE;
2137690Seric }
214