xref: /csrg-svn/usr.sbin/sendmail/src/clock.c (revision 24955)
122696Sdist /*
222696Sdist **  Sendmail
322696Sdist **  Copyright (c) 1983  Eric P. Allman
422696Sdist **  Berkeley, California
522696Sdist **
622696Sdist **  Copyright (c) 1983 Regents of the University of California.
722696Sdist **  All rights reserved.  The Berkeley software License Agreement
822696Sdist **  specifies the terms and conditions for redistribution.
922696Sdist */
1022696Sdist 
1122696Sdist #ifndef lint
12*24955Seric static char	SccsId[] = "@(#)clock.c	5.3 (Berkeley) 09/19/85";
1322696Sdist #endif not lint
1422696Sdist 
157358Seric # include "sendmail.h"
1611728Seric # include <signal.h>
177358Seric 
187358Seric /*
197684Seric **  SETEVENT -- set an event to happen at a specific time.
207684Seric **
219373Seric **	Events are stored in a sorted list for fast processing.
229373Seric **	An event only applies to the process that set it.
239373Seric **
247684Seric **	Parameters:
257684Seric **		intvl -- intvl until next event occurs.
267684Seric **		func -- function to call on event.
277684Seric **		arg -- argument to func on event.
287684Seric **
297684Seric **	Returns:
307684Seric **		none.
317684Seric **
327684Seric **	Side Effects:
337684Seric **		none.
347684Seric */
357684Seric 
367684Seric EVENT *
377684Seric setevent(intvl, func, arg)
387684Seric 	time_t intvl;
397684Seric 	int (*func)();
407684Seric 	int arg;
417684Seric {
427684Seric 	register EVENT **evp;
437684Seric 	register EVENT *ev;
447684Seric 	auto time_t now;
457684Seric 	extern tick();
467684Seric 
477757Seric # ifdef DEBUG
487757Seric 	if (intvl <= 0)
497757Seric 	{
507757Seric 		syserr("setevent: intvl=%ld\n", intvl);
519346Seric 		return (NULL);
527757Seric 	}
537757Seric # endif DEBUG
547757Seric 
557684Seric 	(void) time(&now);
567684Seric 
577684Seric 	/* search event queue for correct position */
587684Seric 	for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
597684Seric 	{
607684Seric 		if (ev->ev_time >= now + intvl)
617684Seric 			break;
627684Seric 	}
637684Seric 
647684Seric 	/* insert new event */
657684Seric 	ev = (EVENT *) xalloc(sizeof *ev);
667684Seric 	ev->ev_time = now + intvl;
677684Seric 	ev->ev_func = func;
687684Seric 	ev->ev_arg = arg;
697931Seric 	ev->ev_pid = getpid();
707684Seric 	ev->ev_link = *evp;
717684Seric 	*evp = ev;
727684Seric 
737684Seric # ifdef DEBUG
748063Seric 	if (tTd(5, 5))
757684Seric 		printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
767684Seric 			intvl, now + intvl, func, arg, ev);
777684Seric # endif DEBUG
787684Seric 
797939Seric 	tick();
807684Seric 	return (ev);
817684Seric }
827684Seric /*
837684Seric **  CLREVENT -- remove an event from the event queue.
847684Seric **
857684Seric **	Parameters:
867684Seric **		ev -- pointer to event to remove.
877684Seric **
887684Seric **	Returns:
897684Seric **		none.
907684Seric **
917684Seric **	Side Effects:
927684Seric **		arranges for event ev to not happen.
937684Seric */
947684Seric 
957684Seric clrevent(ev)
967684Seric 	register EVENT *ev;
977684Seric {
987684Seric 	register EVENT **evp;
997684Seric 
1007684Seric # ifdef DEBUG
1018063Seric 	if (tTd(5, 5))
1027684Seric 		printf("clrevent: ev=%x\n", ev);
1037684Seric # endif DEBUG
1047757Seric 	if (ev == NULL)
1057757Seric 		return;
1067684Seric 
1077684Seric 	/* find the parent event */
1089373Seric 	(void) signal(SIGALRM, SIG_IGN);
1097684Seric 	for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
1107684Seric 	{
1117684Seric 		if (*evp == ev)
1127684Seric 			break;
1137684Seric 	}
1147684Seric 
1157684Seric 	/* now remove it */
1167939Seric 	if (*evp != NULL)
1177939Seric 	{
1187939Seric 		*evp = ev->ev_link;
1199346Seric 		free((char *) ev);
1207939Seric 	}
1217862Seric 
1227862Seric 	/* restore clocks and pick up anything spare */
1237862Seric 	tick();
1247684Seric }
1257684Seric /*
1267358Seric **  TICK -- take a clock tick
1277358Seric **
1287684Seric **	Called by the alarm clock.  This routine runs events as needed.
1297358Seric **
1307358Seric **	Parameters:
1317358Seric **		none.
1327358Seric **
1337358Seric **	Returns:
1347684Seric **		none.
1357358Seric **
1367358Seric **	Side Effects:
1377684Seric **		calls the next function in EventQueue.
1387358Seric */
1397358Seric 
1407358Seric tick()
1417358Seric {
1427889Seric 	register time_t now;
1437684Seric 	register EVENT *ev;
144*24955Seric 	int mypid = getpid();
1457684Seric 
1469373Seric 	(void) signal(SIGALRM, SIG_IGN);
1479373Seric 	(void) alarm(0);
1487889Seric 	now = curtime();
1497684Seric 
1507358Seric # ifdef DEBUG
1518063Seric 	if (tTd(5, 4))
1527684Seric 		printf("tick: now=%ld\n", now);
1537358Seric # endif DEBUG
1547684Seric 
1558128Seric 	while ((ev = EventQueue) != NULL &&
156*24955Seric 	       (ev->ev_time <= now || ev->ev_pid != mypid))
1577684Seric 	{
15816141Seric 		int (*f)();
15916141Seric 		int arg;
16016141Seric 		int pid;
1617862Seric 
1627684Seric 		/* process the event on the top of the queue */
1637684Seric 		ev = EventQueue;
1647684Seric 		EventQueue = EventQueue->ev_link;
1657684Seric # ifdef DEBUG
1668063Seric 		if (tTd(5, 6))
1677931Seric 			printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev,
1687931Seric 				ev->ev_func, ev->ev_arg, ev->ev_pid);
1697684Seric # endif DEBUG
1707862Seric 
1717862Seric 		/* we must be careful in here because ev_func may not return */
1729373Seric 		(void) signal(SIGALRM, tick);
17320844Seric #ifdef SIGVTALRM
17420844Seric 		/* reset 4.2bsd signal mask to allow future alarms */
17520844Seric 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM));
17620844Seric #endif SIGVTALRM
17720844Seric 
1787862Seric 		f = ev->ev_func;
17916141Seric 		arg = ev->ev_arg;
18016141Seric 		pid = ev->ev_pid;
1819346Seric 		free((char *) ev);
18216141Seric 		if (pid != getpid())
1837931Seric 			continue;
1847862Seric 		if (EventQueue != NULL)
1857862Seric 		{
1867862Seric 			if (EventQueue->ev_time > now)
18712635Seric 				(void) alarm((unsigned) (EventQueue->ev_time - now));
1887862Seric 			else
1897889Seric 				(void) alarm(3);
1907862Seric 		}
19116141Seric 		(*f)(arg);
1927862Seric 		(void) alarm(0);
1937889Seric 		now = curtime();
1947684Seric 	}
1959373Seric 	(void) signal(SIGALRM, tick);
1967889Seric 	if (EventQueue != NULL)
19712635Seric 		(void) alarm((unsigned) (EventQueue->ev_time - now));
1987358Seric }
1997690Seric /*
2007690Seric **  SLEEP -- a version of sleep that works with this stuff
2017690Seric **
2027690Seric **	Because sleep uses the alarm facility, I must reimplement
2037690Seric **	it here.
2047690Seric **
2057690Seric **	Parameters:
2067690Seric **		intvl -- time to sleep.
2077690Seric **
2087690Seric **	Returns:
2097690Seric **		none.
2107690Seric **
2117690Seric **	Side Effects:
2127690Seric **		waits for intvl time.  However, other events can
2137690Seric **		be run during that interval.
2147690Seric */
2157690Seric 
2167690Seric static bool	SleepDone;
2177690Seric 
2187690Seric sleep(intvl)
2197690Seric 	int intvl;
2207690Seric {
2217690Seric 	extern endsleep();
2227690Seric 
2237757Seric 	if (intvl == 0)
2247757Seric 		return;
2257690Seric 	SleepDone = FALSE;
22612635Seric 	(void) setevent((time_t) intvl, endsleep, 0);
2277690Seric 	while (!SleepDone)
2287690Seric 		pause();
2297690Seric }
2307690Seric 
2317690Seric static
2327690Seric endsleep()
2337690Seric {
2347690Seric 	SleepDone = TRUE;
2357690Seric }
236