xref: /freebsd/contrib/sendmail/libsm/clock.c (revision 2fb4f839f3fc72ce2bab12f9ba4760f97f73e97f)
140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *	All rights reserved.
440266059SGregory Neil Shapiro  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
540266059SGregory Neil Shapiro  * Copyright (c) 1988, 1993
640266059SGregory Neil Shapiro  *	The Regents of the University of California.  All rights reserved.
740266059SGregory Neil Shapiro  *
840266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
940266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
1040266059SGregory Neil Shapiro  * the sendmail distribution.
1140266059SGregory Neil Shapiro  *
1240266059SGregory Neil Shapiro  */
1340266059SGregory Neil Shapiro 
1440266059SGregory Neil Shapiro #include <sm/gen.h>
154313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: clock.c,v 1.48 2013-11-22 20:51:42 ca Exp $")
1640266059SGregory Neil Shapiro #include <unistd.h>
1740266059SGregory Neil Shapiro #include <time.h>
1840266059SGregory Neil Shapiro #include <errno.h>
1940266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
204e4196cbSGregory Neil Shapiro # include <sm/time.h>
215b0945b5SGregory Neil Shapiro #endif
2240266059SGregory Neil Shapiro #include <sm/heap.h>
2340266059SGregory Neil Shapiro #include <sm/debug.h>
2440266059SGregory Neil Shapiro #include <sm/bitops.h>
2540266059SGregory Neil Shapiro #include <sm/clock.h>
2640266059SGregory Neil Shapiro #include "local.h"
27a7ec597cSGregory Neil Shapiro #if _FFR_SLEEP_USE_SELECT > 0
28a7ec597cSGregory Neil Shapiro # include <sys/types.h>
295b0945b5SGregory Neil Shapiro #endif
30a7ec597cSGregory Neil Shapiro #if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
31a7ec597cSGregory Neil Shapiro # include <syslog.h>
325b0945b5SGregory Neil Shapiro #endif
3340266059SGregory Neil Shapiro 
3440266059SGregory Neil Shapiro #ifndef sigmask
3540266059SGregory Neil Shapiro # define sigmask(s)	(1 << ((s) - 1))
365b0945b5SGregory Neil Shapiro #endif
3740266059SGregory Neil Shapiro 
3840266059SGregory Neil Shapiro 
3940266059SGregory Neil Shapiro /*
4040266059SGregory Neil Shapiro **  SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
4140266059SGregory Neil Shapiro **
4240266059SGregory Neil Shapiro **	Events are stored in a sorted list for fast processing.
4340266059SGregory Neil Shapiro **	An event only applies to the process that set it.
4440266059SGregory Neil Shapiro **	Source is #ifdef'd to work with older OS's that don't have setitimer()
4540266059SGregory Neil Shapiro **	(that is, don't have a timer granularity less than 1 second).
4640266059SGregory Neil Shapiro **
4740266059SGregory Neil Shapiro **	Parameters:
4840266059SGregory Neil Shapiro **		intvl -- interval until next event occurs (milliseconds).
4940266059SGregory Neil Shapiro **		func -- function to call on event.
5040266059SGregory Neil Shapiro **		arg -- argument to func on event.
5140266059SGregory Neil Shapiro **
5240266059SGregory Neil Shapiro **	Returns:
5340266059SGregory Neil Shapiro **		On success returns the SM_EVENT entry created.
5440266059SGregory Neil Shapiro **		On failure returns NULL.
5540266059SGregory Neil Shapiro **
5640266059SGregory Neil Shapiro **	Side Effects:
5740266059SGregory Neil Shapiro **		none.
5840266059SGregory Neil Shapiro */
5940266059SGregory Neil Shapiro 
6040266059SGregory Neil Shapiro static SM_EVENT	*volatile SmEventQueue;		/* head of event queue */
6140266059SGregory Neil Shapiro static SM_EVENT	*volatile SmFreeEventList;	/* list of free events */
6240266059SGregory Neil Shapiro 
6340266059SGregory Neil Shapiro SM_EVENT *
sm_seteventm(intvl,func,arg)6440266059SGregory Neil Shapiro sm_seteventm(intvl, func, arg)
6540266059SGregory Neil Shapiro 	int intvl;
66b6bacd31SGregory Neil Shapiro 	void (*func)__P((int));
6740266059SGregory Neil Shapiro 	int arg;
6840266059SGregory Neil Shapiro {
6940266059SGregory Neil Shapiro 	ENTER_CRITICAL();
7040266059SGregory Neil Shapiro 	if (SmFreeEventList == NULL)
7140266059SGregory Neil Shapiro 	{
7240266059SGregory Neil Shapiro 		SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
7340266059SGregory Neil Shapiro 		SmFreeEventList->ev_link = NULL;
7440266059SGregory Neil Shapiro 	}
7540266059SGregory Neil Shapiro 	LEAVE_CRITICAL();
7640266059SGregory Neil Shapiro 
7740266059SGregory Neil Shapiro 	return sm_sigsafe_seteventm(intvl, func, arg);
7840266059SGregory Neil Shapiro }
7940266059SGregory Neil Shapiro 
8040266059SGregory Neil Shapiro /*
8140266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
8240266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
8340266059SGregory Neil Shapiro **		DOING.
8440266059SGregory Neil Shapiro */
8540266059SGregory Neil Shapiro 
8640266059SGregory Neil Shapiro SM_EVENT *
sm_sigsafe_seteventm(intvl,func,arg)8740266059SGregory Neil Shapiro sm_sigsafe_seteventm(intvl, func, arg)
8840266059SGregory Neil Shapiro 	int intvl;
89b6bacd31SGregory Neil Shapiro 	void (*func)__P((int));
9040266059SGregory Neil Shapiro 	int arg;
9140266059SGregory Neil Shapiro {
9240266059SGregory Neil Shapiro 	register SM_EVENT **evp;
9340266059SGregory Neil Shapiro 	register SM_EVENT *ev;
9440266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
9540266059SGregory Neil Shapiro 	auto struct timeval now, nowi, ival;
9640266059SGregory Neil Shapiro 	auto struct itimerval itime;
975b0945b5SGregory Neil Shapiro #else
9840266059SGregory Neil Shapiro 	auto time_t now, nowi;
995b0945b5SGregory Neil Shapiro #endif
10040266059SGregory Neil Shapiro 	int wasblocked;
10140266059SGregory Neil Shapiro 
10240266059SGregory Neil Shapiro 	/* negative times are not allowed */
10340266059SGregory Neil Shapiro 	if (intvl <= 0)
10440266059SGregory Neil Shapiro 		return NULL;
10540266059SGregory Neil Shapiro 
10640266059SGregory Neil Shapiro 	wasblocked = sm_blocksignal(SIGALRM);
10740266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
10840266059SGregory Neil Shapiro 	ival.tv_sec = intvl / 1000;
10940266059SGregory Neil Shapiro 	ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
11040266059SGregory Neil Shapiro 	(void) gettimeofday(&now, NULL);
11140266059SGregory Neil Shapiro 	nowi = now;
11240266059SGregory Neil Shapiro 	timeradd(&now, &ival, &nowi);
11340266059SGregory Neil Shapiro #else /*  SM_CONF_SETITIMER */
11440266059SGregory Neil Shapiro 	now = time(NULL);
11540266059SGregory Neil Shapiro 	nowi = now + (time_t)(intvl / 1000);
11640266059SGregory Neil Shapiro #endif /*  SM_CONF_SETITIMER */
11740266059SGregory Neil Shapiro 
11840266059SGregory Neil Shapiro 	/* search event queue for correct position */
11940266059SGregory Neil Shapiro 	for (evp = (SM_EVENT **) (&SmEventQueue);
12040266059SGregory Neil Shapiro 	     (ev = *evp) != NULL;
12140266059SGregory Neil Shapiro 	     evp = &ev->ev_link)
12240266059SGregory Neil Shapiro 	{
12340266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
12440266059SGregory Neil Shapiro 		if (timercmp(&(ev->ev_time), &nowi, >=))
1255b0945b5SGregory Neil Shapiro #else
12640266059SGregory Neil Shapiro 		if (ev->ev_time >= nowi)
1275b0945b5SGregory Neil Shapiro #endif
12840266059SGregory Neil Shapiro 			break;
12940266059SGregory Neil Shapiro 	}
13040266059SGregory Neil Shapiro 
13140266059SGregory Neil Shapiro 	ENTER_CRITICAL();
13240266059SGregory Neil Shapiro 	if (SmFreeEventList == NULL)
13340266059SGregory Neil Shapiro 	{
13440266059SGregory Neil Shapiro 		/*
13540266059SGregory Neil Shapiro 		**  This shouldn't happen.  If called from sm_seteventm(),
13640266059SGregory Neil Shapiro 		**  we have just malloced a SmFreeEventList entry.  If
13740266059SGregory Neil Shapiro 		**  called from a signal handler, it should have been
13840266059SGregory Neil Shapiro 		**  from an existing event which sm_tick() just added to
13940266059SGregory Neil Shapiro 		**  SmFreeEventList.
14040266059SGregory Neil Shapiro 		*/
14140266059SGregory Neil Shapiro 
14240266059SGregory Neil Shapiro 		LEAVE_CRITICAL();
143a7ec597cSGregory Neil Shapiro 		if (wasblocked == 0)
144a7ec597cSGregory Neil Shapiro 			(void) sm_releasesignal(SIGALRM);
14540266059SGregory Neil Shapiro 		return NULL;
14640266059SGregory Neil Shapiro 	}
14740266059SGregory Neil Shapiro 	else
14840266059SGregory Neil Shapiro 	{
14940266059SGregory Neil Shapiro 		ev = SmFreeEventList;
15040266059SGregory Neil Shapiro 		SmFreeEventList = ev->ev_link;
15140266059SGregory Neil Shapiro 	}
15240266059SGregory Neil Shapiro 	LEAVE_CRITICAL();
15340266059SGregory Neil Shapiro 
15440266059SGregory Neil Shapiro 	/* insert new event */
15540266059SGregory Neil Shapiro 	ev->ev_time = nowi;
15640266059SGregory Neil Shapiro 	ev->ev_func = func;
15740266059SGregory Neil Shapiro 	ev->ev_arg = arg;
15840266059SGregory Neil Shapiro 	ev->ev_pid = getpid();
15940266059SGregory Neil Shapiro 	ENTER_CRITICAL();
16040266059SGregory Neil Shapiro 	ev->ev_link = *evp;
16140266059SGregory Neil Shapiro 	*evp = ev;
16240266059SGregory Neil Shapiro 	LEAVE_CRITICAL();
16340266059SGregory Neil Shapiro 
16440266059SGregory Neil Shapiro 	(void) sm_signal(SIGALRM, sm_tick);
16540266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
16640266059SGregory Neil Shapiro 	timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
16740266059SGregory Neil Shapiro 	itime.it_interval.tv_sec = 0;
16840266059SGregory Neil Shapiro 	itime.it_interval.tv_usec = 0;
169605302a5SGregory Neil Shapiro 	if (itime.it_value.tv_sec < 0)
170605302a5SGregory Neil Shapiro 		itime.it_value.tv_sec = 0;
17140266059SGregory Neil Shapiro 	if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
17240266059SGregory Neil Shapiro 		itime.it_value.tv_usec = 1000;
17340266059SGregory Neil Shapiro 	(void) setitimer(ITIMER_REAL, &itime, NULL);
17440266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
17540266059SGregory Neil Shapiro 	intvl = SmEventQueue->ev_time - now;
1765ef517c0SGregory Neil Shapiro 	(void) alarm((unsigned) (intvl < 1 ? 1 : intvl));
17740266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
17840266059SGregory Neil Shapiro 	if (wasblocked == 0)
17940266059SGregory Neil Shapiro 		(void) sm_releasesignal(SIGALRM);
18040266059SGregory Neil Shapiro 	return ev;
18140266059SGregory Neil Shapiro }
18240266059SGregory Neil Shapiro /*
18340266059SGregory Neil Shapiro **  SM_CLREVENT -- remove an event from the event queue.
18440266059SGregory Neil Shapiro **
18540266059SGregory Neil Shapiro **	Parameters:
18640266059SGregory Neil Shapiro **		ev -- pointer to event to remove.
18740266059SGregory Neil Shapiro **
18840266059SGregory Neil Shapiro **	Returns:
18940266059SGregory Neil Shapiro **		none.
19040266059SGregory Neil Shapiro **
19140266059SGregory Neil Shapiro **	Side Effects:
19240266059SGregory Neil Shapiro **		arranges for event ev to not happen.
19340266059SGregory Neil Shapiro */
19440266059SGregory Neil Shapiro 
19540266059SGregory Neil Shapiro void
sm_clrevent(ev)19640266059SGregory Neil Shapiro sm_clrevent(ev)
19740266059SGregory Neil Shapiro 	register SM_EVENT *ev;
19840266059SGregory Neil Shapiro {
19940266059SGregory Neil Shapiro 	register SM_EVENT **evp;
20040266059SGregory Neil Shapiro 	int wasblocked;
20140266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
20240266059SGregory Neil Shapiro 	struct itimerval clr;
2035b0945b5SGregory Neil Shapiro #endif
20440266059SGregory Neil Shapiro 
20540266059SGregory Neil Shapiro 	if (ev == NULL)
20640266059SGregory Neil Shapiro 		return;
20740266059SGregory Neil Shapiro 
20840266059SGregory Neil Shapiro 	/* find the parent event */
20940266059SGregory Neil Shapiro 	wasblocked = sm_blocksignal(SIGALRM);
21040266059SGregory Neil Shapiro 	for (evp = (SM_EVENT **) (&SmEventQueue);
21140266059SGregory Neil Shapiro 	     *evp != NULL;
21240266059SGregory Neil Shapiro 	     evp = &(*evp)->ev_link)
21340266059SGregory Neil Shapiro 	{
21440266059SGregory Neil Shapiro 		if (*evp == ev)
21540266059SGregory Neil Shapiro 			break;
21640266059SGregory Neil Shapiro 	}
21740266059SGregory Neil Shapiro 
21840266059SGregory Neil Shapiro 	/* now remove it */
21940266059SGregory Neil Shapiro 	if (*evp != NULL)
22040266059SGregory Neil Shapiro 	{
22140266059SGregory Neil Shapiro 		ENTER_CRITICAL();
22240266059SGregory Neil Shapiro 		*evp = ev->ev_link;
22340266059SGregory Neil Shapiro 		ev->ev_link = SmFreeEventList;
22440266059SGregory Neil Shapiro 		SmFreeEventList = ev;
22540266059SGregory Neil Shapiro 		LEAVE_CRITICAL();
22640266059SGregory Neil Shapiro 	}
22740266059SGregory Neil Shapiro 
22840266059SGregory Neil Shapiro 	/* restore clocks and pick up anything spare */
22940266059SGregory Neil Shapiro 	if (wasblocked == 0)
23040266059SGregory Neil Shapiro 		(void) sm_releasesignal(SIGALRM);
23140266059SGregory Neil Shapiro 	if (SmEventQueue != NULL)
23240266059SGregory Neil Shapiro 		(void) kill(getpid(), SIGALRM);
23340266059SGregory Neil Shapiro 	else
23440266059SGregory Neil Shapiro 	{
23540266059SGregory Neil Shapiro 		/* nothing left in event queue, no need for an alarm */
23640266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
23740266059SGregory Neil Shapiro 		clr.it_interval.tv_sec = 0;
23840266059SGregory Neil Shapiro 		clr.it_interval.tv_usec = 0;
23940266059SGregory Neil Shapiro 		clr.it_value.tv_sec = 0;
24040266059SGregory Neil Shapiro 		clr.it_value.tv_usec = 0;
24140266059SGregory Neil Shapiro 		(void) setitimer(ITIMER_REAL, &clr, NULL);
24240266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
24340266059SGregory Neil Shapiro 		(void) alarm(0);
24440266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
24540266059SGregory Neil Shapiro 	}
24640266059SGregory Neil Shapiro }
24740266059SGregory Neil Shapiro /*
24840266059SGregory Neil Shapiro **  SM_CLEAR_EVENTS -- remove all events from the event queue.
24940266059SGregory Neil Shapiro **
25040266059SGregory Neil Shapiro **	Parameters:
25140266059SGregory Neil Shapiro **		none.
25240266059SGregory Neil Shapiro **
25340266059SGregory Neil Shapiro **	Returns:
25440266059SGregory Neil Shapiro **		none.
25540266059SGregory Neil Shapiro */
25640266059SGregory Neil Shapiro 
25740266059SGregory Neil Shapiro void
sm_clear_events()25840266059SGregory Neil Shapiro sm_clear_events()
25940266059SGregory Neil Shapiro {
26040266059SGregory Neil Shapiro 	register SM_EVENT *ev;
26140266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
26240266059SGregory Neil Shapiro 	struct itimerval clr;
2635b0945b5SGregory Neil Shapiro #endif
26440266059SGregory Neil Shapiro 	int wasblocked;
26540266059SGregory Neil Shapiro 
26640266059SGregory Neil Shapiro 	/* nothing will be left in event queue, no need for an alarm */
26740266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
26840266059SGregory Neil Shapiro 	clr.it_interval.tv_sec = 0;
26940266059SGregory Neil Shapiro 	clr.it_interval.tv_usec = 0;
27040266059SGregory Neil Shapiro 	clr.it_value.tv_sec = 0;
27140266059SGregory Neil Shapiro 	clr.it_value.tv_usec = 0;
27240266059SGregory Neil Shapiro 	(void) setitimer(ITIMER_REAL, &clr, NULL);
27340266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
27440266059SGregory Neil Shapiro 	(void) alarm(0);
27540266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
276739ac4d4SGregory Neil Shapiro 
277739ac4d4SGregory Neil Shapiro 	if (SmEventQueue == NULL)
278739ac4d4SGregory Neil Shapiro 		return;
279739ac4d4SGregory Neil Shapiro 
28040266059SGregory Neil Shapiro 	wasblocked = sm_blocksignal(SIGALRM);
28140266059SGregory Neil Shapiro 
28240266059SGregory Neil Shapiro 	/* find the end of the EventQueue */
28340266059SGregory Neil Shapiro 	for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
28440266059SGregory Neil Shapiro 		continue;
28540266059SGregory Neil Shapiro 
28640266059SGregory Neil Shapiro 	ENTER_CRITICAL();
28740266059SGregory Neil Shapiro 	ev->ev_link = SmFreeEventList;
28840266059SGregory Neil Shapiro 	SmFreeEventList = SmEventQueue;
28940266059SGregory Neil Shapiro 	SmEventQueue = NULL;
29040266059SGregory Neil Shapiro 	LEAVE_CRITICAL();
29140266059SGregory Neil Shapiro 
29240266059SGregory Neil Shapiro 	/* restore clocks and pick up anything spare */
29340266059SGregory Neil Shapiro 	if (wasblocked == 0)
29440266059SGregory Neil Shapiro 		(void) sm_releasesignal(SIGALRM);
29540266059SGregory Neil Shapiro }
29640266059SGregory Neil Shapiro /*
29740266059SGregory Neil Shapiro **  SM_TICK -- take a clock tick
29840266059SGregory Neil Shapiro **
29940266059SGregory Neil Shapiro **	Called by the alarm clock.  This routine runs events as needed.
30040266059SGregory Neil Shapiro **	Always called as a signal handler, so we assume that SIGALRM
30140266059SGregory Neil Shapiro **	has been blocked.
30240266059SGregory Neil Shapiro **
30340266059SGregory Neil Shapiro **	Parameters:
30440266059SGregory Neil Shapiro **		One that is ignored; for compatibility with signal handlers.
30540266059SGregory Neil Shapiro **
30640266059SGregory Neil Shapiro **	Returns:
30740266059SGregory Neil Shapiro **		none.
30840266059SGregory Neil Shapiro **
30940266059SGregory Neil Shapiro **	Side Effects:
31040266059SGregory Neil Shapiro **		calls the next function in EventQueue.
31140266059SGregory Neil Shapiro **
31240266059SGregory Neil Shapiro **	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
31340266059SGregory Neil Shapiro **		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
31440266059SGregory Neil Shapiro **		DOING.
31540266059SGregory Neil Shapiro */
31640266059SGregory Neil Shapiro 
31740266059SGregory Neil Shapiro /* ARGSUSED */
31840266059SGregory Neil Shapiro SIGFUNC_DECL
sm_tick(sig)31940266059SGregory Neil Shapiro sm_tick(sig)
32040266059SGregory Neil Shapiro 	int sig;
32140266059SGregory Neil Shapiro {
32240266059SGregory Neil Shapiro 	register SM_EVENT *ev;
32340266059SGregory Neil Shapiro 	pid_t mypid;
32440266059SGregory Neil Shapiro 	int save_errno = errno;
32540266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
32640266059SGregory Neil Shapiro 	struct itimerval clr;
32740266059SGregory Neil Shapiro 	struct timeval now;
3285b0945b5SGregory Neil Shapiro #else
32940266059SGregory Neil Shapiro 	register time_t now;
33040266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
33140266059SGregory Neil Shapiro 
33240266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
33340266059SGregory Neil Shapiro 	clr.it_interval.tv_sec = 0;
33440266059SGregory Neil Shapiro 	clr.it_interval.tv_usec = 0;
33540266059SGregory Neil Shapiro 	clr.it_value.tv_sec = 0;
33640266059SGregory Neil Shapiro 	clr.it_value.tv_usec = 0;
33740266059SGregory Neil Shapiro 	(void) setitimer(ITIMER_REAL, &clr, NULL);
33840266059SGregory Neil Shapiro 	gettimeofday(&now, NULL);
33940266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
34040266059SGregory Neil Shapiro 	(void) alarm(0);
34140266059SGregory Neil Shapiro 	now = time(NULL);
34240266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
34340266059SGregory Neil Shapiro 
34440266059SGregory Neil Shapiro 	FIX_SYSV_SIGNAL(sig, sm_tick);
34540266059SGregory Neil Shapiro 	errno = save_errno;
34640266059SGregory Neil Shapiro 	CHECK_CRITICAL(sig);
34740266059SGregory Neil Shapiro 
34840266059SGregory Neil Shapiro 	mypid = getpid();
34940266059SGregory Neil Shapiro 	while (PendingSignal != 0)
35040266059SGregory Neil Shapiro 	{
35140266059SGregory Neil Shapiro 		int sigbit = 0;
35240266059SGregory Neil Shapiro 		int sig = 0;
35340266059SGregory Neil Shapiro 
35440266059SGregory Neil Shapiro 		if (bitset(PEND_SIGHUP, PendingSignal))
35540266059SGregory Neil Shapiro 		{
35640266059SGregory Neil Shapiro 			sigbit = PEND_SIGHUP;
35740266059SGregory Neil Shapiro 			sig = SIGHUP;
35840266059SGregory Neil Shapiro 		}
35940266059SGregory Neil Shapiro 		else if (bitset(PEND_SIGINT, PendingSignal))
36040266059SGregory Neil Shapiro 		{
36140266059SGregory Neil Shapiro 			sigbit = PEND_SIGINT;
36240266059SGregory Neil Shapiro 			sig = SIGINT;
36340266059SGregory Neil Shapiro 		}
36440266059SGregory Neil Shapiro 		else if (bitset(PEND_SIGTERM, PendingSignal))
36540266059SGregory Neil Shapiro 		{
36640266059SGregory Neil Shapiro 			sigbit = PEND_SIGTERM;
36740266059SGregory Neil Shapiro 			sig = SIGTERM;
36840266059SGregory Neil Shapiro 		}
36940266059SGregory Neil Shapiro 		else if (bitset(PEND_SIGUSR1, PendingSignal))
37040266059SGregory Neil Shapiro 		{
37140266059SGregory Neil Shapiro 			sigbit = PEND_SIGUSR1;
37240266059SGregory Neil Shapiro 			sig = SIGUSR1;
37340266059SGregory Neil Shapiro 		}
37440266059SGregory Neil Shapiro 		else
37540266059SGregory Neil Shapiro 		{
37640266059SGregory Neil Shapiro 			/* If we get here, we are in trouble */
37740266059SGregory Neil Shapiro 			abort();
37840266059SGregory Neil Shapiro 		}
37940266059SGregory Neil Shapiro 		PendingSignal &= ~sigbit;
38040266059SGregory Neil Shapiro 		kill(mypid, sig);
38140266059SGregory Neil Shapiro 	}
38240266059SGregory Neil Shapiro 
38340266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
38440266059SGregory Neil Shapiro 	gettimeofday(&now, NULL);
3855b0945b5SGregory Neil Shapiro #else
38640266059SGregory Neil Shapiro 	now = time(NULL);
3875b0945b5SGregory Neil Shapiro #endif
38840266059SGregory Neil Shapiro 	while ((ev = SmEventQueue) != NULL &&
38940266059SGregory Neil Shapiro 	       (ev->ev_pid != mypid ||
39040266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
39140266059SGregory Neil Shapiro 		timercmp(&ev->ev_time, &now, <=)
3925b0945b5SGregory Neil Shapiro #else
39340266059SGregory Neil Shapiro 		ev->ev_time <= now
3945b0945b5SGregory Neil Shapiro #endif
39540266059SGregory Neil Shapiro 		))
39640266059SGregory Neil Shapiro 	{
397b6bacd31SGregory Neil Shapiro 		void (*f)__P((int));
39840266059SGregory Neil Shapiro 		int arg;
39940266059SGregory Neil Shapiro 		pid_t pid;
40040266059SGregory Neil Shapiro 
40140266059SGregory Neil Shapiro 		/* process the event on the top of the queue */
40240266059SGregory Neil Shapiro 		ev = SmEventQueue;
40340266059SGregory Neil Shapiro 		SmEventQueue = SmEventQueue->ev_link;
40440266059SGregory Neil Shapiro 
40540266059SGregory Neil Shapiro 		/* we must be careful in here because ev_func may not return */
40640266059SGregory Neil Shapiro 		f = ev->ev_func;
40740266059SGregory Neil Shapiro 		arg = ev->ev_arg;
40840266059SGregory Neil Shapiro 		pid = ev->ev_pid;
40940266059SGregory Neil Shapiro 		ENTER_CRITICAL();
41040266059SGregory Neil Shapiro 		ev->ev_link = SmFreeEventList;
41140266059SGregory Neil Shapiro 		SmFreeEventList = ev;
41240266059SGregory Neil Shapiro 		LEAVE_CRITICAL();
41340266059SGregory Neil Shapiro 		if (pid != getpid())
41440266059SGregory Neil Shapiro 			continue;
41540266059SGregory Neil Shapiro 		if (SmEventQueue != NULL)
41640266059SGregory Neil Shapiro 		{
41740266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
41840266059SGregory Neil Shapiro 			if (timercmp(&SmEventQueue->ev_time, &now, >))
41940266059SGregory Neil Shapiro 			{
42040266059SGregory Neil Shapiro 				timersub(&SmEventQueue->ev_time, &now,
42140266059SGregory Neil Shapiro 					 &clr.it_value);
42240266059SGregory Neil Shapiro 				clr.it_interval.tv_sec = 0;
42340266059SGregory Neil Shapiro 				clr.it_interval.tv_usec = 0;
424605302a5SGregory Neil Shapiro 				if (clr.it_value.tv_sec < 0)
425605302a5SGregory Neil Shapiro 					clr.it_value.tv_sec = 0;
426605302a5SGregory Neil Shapiro 				if (clr.it_value.tv_sec == 0 &&
427605302a5SGregory Neil Shapiro 				    clr.it_value.tv_usec == 0)
428605302a5SGregory Neil Shapiro 					clr.it_value.tv_usec = 1000;
42940266059SGregory Neil Shapiro 				(void) setitimer(ITIMER_REAL, &clr, NULL);
43040266059SGregory Neil Shapiro 			}
43140266059SGregory Neil Shapiro 			else
43240266059SGregory Neil Shapiro 			{
43340266059SGregory Neil Shapiro 				clr.it_interval.tv_sec = 0;
43440266059SGregory Neil Shapiro 				clr.it_interval.tv_usec = 0;
43540266059SGregory Neil Shapiro 				clr.it_value.tv_sec = 3;
43640266059SGregory Neil Shapiro 				clr.it_value.tv_usec = 0;
43740266059SGregory Neil Shapiro 				(void) setitimer(ITIMER_REAL, &clr, NULL);
43840266059SGregory Neil Shapiro 			}
43940266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
44040266059SGregory Neil Shapiro 			if (SmEventQueue->ev_time > now)
44140266059SGregory Neil Shapiro 				(void) alarm((unsigned) (SmEventQueue->ev_time
44240266059SGregory Neil Shapiro 							 - now));
44340266059SGregory Neil Shapiro 			else
44440266059SGregory Neil Shapiro 				(void) alarm(3);
44540266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
44640266059SGregory Neil Shapiro 		}
44740266059SGregory Neil Shapiro 
44840266059SGregory Neil Shapiro 		/* call ev_func */
44940266059SGregory Neil Shapiro 		errno = save_errno;
45040266059SGregory Neil Shapiro 		(*f)(arg);
45140266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
45240266059SGregory Neil Shapiro 		clr.it_interval.tv_sec = 0;
45340266059SGregory Neil Shapiro 		clr.it_interval.tv_usec = 0;
45440266059SGregory Neil Shapiro 		clr.it_value.tv_sec = 0;
45540266059SGregory Neil Shapiro 		clr.it_value.tv_usec = 0;
45640266059SGregory Neil Shapiro 		(void) setitimer(ITIMER_REAL, &clr, NULL);
45740266059SGregory Neil Shapiro 		gettimeofday(&now, NULL);
45840266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
45940266059SGregory Neil Shapiro 		(void) alarm(0);
46040266059SGregory Neil Shapiro 		now = time(NULL);
46140266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
46240266059SGregory Neil Shapiro 	}
46340266059SGregory Neil Shapiro 	if (SmEventQueue != NULL)
46440266059SGregory Neil Shapiro 	{
46540266059SGregory Neil Shapiro #if SM_CONF_SETITIMER
46640266059SGregory Neil Shapiro 		timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
46740266059SGregory Neil Shapiro 		clr.it_interval.tv_sec = 0;
46840266059SGregory Neil Shapiro 		clr.it_interval.tv_usec = 0;
469605302a5SGregory Neil Shapiro 		if (clr.it_value.tv_sec < 0)
470605302a5SGregory Neil Shapiro 			clr.it_value.tv_sec = 0;
471605302a5SGregory Neil Shapiro 		if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
472605302a5SGregory Neil Shapiro 			clr.it_value.tv_usec = 1000;
47340266059SGregory Neil Shapiro 		(void) setitimer(ITIMER_REAL, &clr, NULL);
47440266059SGregory Neil Shapiro #else /* SM_CONF_SETITIMER */
47540266059SGregory Neil Shapiro 		(void) alarm((unsigned) (SmEventQueue->ev_time - now));
47640266059SGregory Neil Shapiro #endif /* SM_CONF_SETITIMER */
47740266059SGregory Neil Shapiro 	}
47840266059SGregory Neil Shapiro 	errno = save_errno;
47940266059SGregory Neil Shapiro 	return SIGFUNC_RETURN;
48040266059SGregory Neil Shapiro }
48140266059SGregory Neil Shapiro /*
48240266059SGregory Neil Shapiro **  SLEEP -- a version of sleep that works with this stuff
48340266059SGregory Neil Shapiro **
48440266059SGregory Neil Shapiro **	Because Unix sleep uses the alarm facility, I must reimplement
48540266059SGregory Neil Shapiro **	it here.
48640266059SGregory Neil Shapiro **
48740266059SGregory Neil Shapiro **	Parameters:
48840266059SGregory Neil Shapiro **		intvl -- time to sleep.
48940266059SGregory Neil Shapiro **
49040266059SGregory Neil Shapiro **	Returns:
49140266059SGregory Neil Shapiro **		zero.
49240266059SGregory Neil Shapiro **
49340266059SGregory Neil Shapiro **	Side Effects:
49440266059SGregory Neil Shapiro **		waits for intvl time.  However, other events can
49540266059SGregory Neil Shapiro **		be run during that interval.
49640266059SGregory Neil Shapiro */
49740266059SGregory Neil Shapiro 
49840266059SGregory Neil Shapiro 
499a7ec597cSGregory Neil Shapiro #if !HAVE_NANOSLEEP
500b6bacd31SGregory Neil Shapiro static void	sm_endsleep __P((int));
50140266059SGregory Neil Shapiro static bool	volatile SmSleepDone;
5025b0945b5SGregory Neil Shapiro #endif
50340266059SGregory Neil Shapiro 
50440266059SGregory Neil Shapiro #ifndef SLEEP_T
50540266059SGregory Neil Shapiro # define SLEEP_T	unsigned int
5065b0945b5SGregory Neil Shapiro #endif
50740266059SGregory Neil Shapiro 
50840266059SGregory Neil Shapiro SLEEP_T
sleep(intvl)50940266059SGregory Neil Shapiro sleep(intvl)
51040266059SGregory Neil Shapiro 	unsigned int intvl;
51140266059SGregory Neil Shapiro {
512a7ec597cSGregory Neil Shapiro #if HAVE_NANOSLEEP
513a7ec597cSGregory Neil Shapiro 	struct timespec rqtp;
51440266059SGregory Neil Shapiro 
51540266059SGregory Neil Shapiro 	if (intvl == 0)
51640266059SGregory Neil Shapiro 		return (SLEEP_T) 0;
517a7ec597cSGregory Neil Shapiro 	rqtp.tv_sec = intvl;
518a7ec597cSGregory Neil Shapiro 	rqtp.tv_nsec = 0;
519a7ec597cSGregory Neil Shapiro 	nanosleep(&rqtp, NULL);
520a7ec597cSGregory Neil Shapiro 	return (SLEEP_T) 0;
521a7ec597cSGregory Neil Shapiro #else /* HAVE_NANOSLEEP */
522a7ec597cSGregory Neil Shapiro 	int was_held;
523a7ec597cSGregory Neil Shapiro 	SM_EVENT *ev;
524a7ec597cSGregory Neil Shapiro # if _FFR_SLEEP_USE_SELECT > 0
525a7ec597cSGregory Neil Shapiro 	int r;
526e92d3f3fSGregory Neil Shapiro #  if _FFR_SLEEP_USE_SELECT > 0
527e92d3f3fSGregory Neil Shapiro 	struct timeval sm_io_to;
5285b0945b5SGregory Neil Shapiro #  endif
529a7ec597cSGregory Neil Shapiro # endif /* _FFR_SLEEP_USE_SELECT > 0 */
530a7ec597cSGregory Neil Shapiro # if SM_CONF_SETITIMER
531a7ec597cSGregory Neil Shapiro 	struct timeval now, begin, diff;
532a7ec597cSGregory Neil Shapiro #  if _FFR_SLEEP_USE_SELECT > 0
533e92d3f3fSGregory Neil Shapiro 	struct timeval slpv;
5345b0945b5SGregory Neil Shapiro #  endif
535a7ec597cSGregory Neil Shapiro # else /*  SM_CONF_SETITIMER */
536a7ec597cSGregory Neil Shapiro 	time_t begin, now;
537a7ec597cSGregory Neil Shapiro # endif /*  SM_CONF_SETITIMER */
538a7ec597cSGregory Neil Shapiro 
539a7ec597cSGregory Neil Shapiro 	if (intvl == 0)
540a7ec597cSGregory Neil Shapiro 		return (SLEEP_T) 0;
541a7ec597cSGregory Neil Shapiro # if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
542a7ec597cSGregory Neil Shapiro 	if (intvl > _FFR_MAX_SLEEP_TIME)
543a7ec597cSGregory Neil Shapiro 	{
544a7ec597cSGregory Neil Shapiro 		syslog(LOG_ERR, "sleep: interval=%u exceeds max value %d",
545a7ec597cSGregory Neil Shapiro 			intvl, _FFR_MAX_SLEEP_TIME);
546a7ec597cSGregory Neil Shapiro #  if 0
547a7ec597cSGregory Neil Shapiro 		SM_ASSERT(intvl < (unsigned int) INT_MAX);
5485b0945b5SGregory Neil Shapiro #  endif
549a7ec597cSGregory Neil Shapiro 		intvl = _FFR_MAX_SLEEP_TIME;
550a7ec597cSGregory Neil Shapiro 	}
551a7ec597cSGregory Neil Shapiro # endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
55240266059SGregory Neil Shapiro 	SmSleepDone = false;
553a7ec597cSGregory Neil Shapiro 
554a7ec597cSGregory Neil Shapiro # if SM_CONF_SETITIMER
555a7ec597cSGregory Neil Shapiro #  if _FFR_SLEEP_USE_SELECT > 0
556a7ec597cSGregory Neil Shapiro 	slpv.tv_sec = intvl;
557a7ec597cSGregory Neil Shapiro 	slpv.tv_usec = 0;
5585b0945b5SGregory Neil Shapiro #  endif
559a7ec597cSGregory Neil Shapiro 	(void) gettimeofday(&now, NULL);
560a7ec597cSGregory Neil Shapiro 	begin = now;
561a7ec597cSGregory Neil Shapiro # else /*  SM_CONF_SETITIMER */
562a7ec597cSGregory Neil Shapiro 	now = begin = time(NULL);
563a7ec597cSGregory Neil Shapiro # endif /*  SM_CONF_SETITIMER */
564a7ec597cSGregory Neil Shapiro 
565a7ec597cSGregory Neil Shapiro 	ev = sm_setevent((time_t) intvl, sm_endsleep, 0);
566a7ec597cSGregory Neil Shapiro 	if (ev == NULL)
567a7ec597cSGregory Neil Shapiro 	{
568a7ec597cSGregory Neil Shapiro 		/* COMPLAIN */
569a7ec597cSGregory Neil Shapiro # if 0
570a7ec597cSGregory Neil Shapiro 		syslog(LOG_ERR, "sleep: sm_setevent(%u) failed", intvl);
5715b0945b5SGregory Neil Shapiro # endif
572a7ec597cSGregory Neil Shapiro 		SmSleepDone = true;
573a7ec597cSGregory Neil Shapiro 	}
57440266059SGregory Neil Shapiro 	was_held = sm_releasesignal(SIGALRM);
575a7ec597cSGregory Neil Shapiro 
57640266059SGregory Neil Shapiro 	while (!SmSleepDone)
577a7ec597cSGregory Neil Shapiro 	{
578a7ec597cSGregory Neil Shapiro # if SM_CONF_SETITIMER
579a7ec597cSGregory Neil Shapiro 		(void) gettimeofday(&now, NULL);
580a7ec597cSGregory Neil Shapiro 		timersub(&now, &begin, &diff);
581a7ec597cSGregory Neil Shapiro 		if (diff.tv_sec < 0 ||
582a7ec597cSGregory Neil Shapiro 		    (diff.tv_sec == 0 && diff.tv_usec == 0))
583a7ec597cSGregory Neil Shapiro 			break;
584a7ec597cSGregory Neil Shapiro #  if _FFR_SLEEP_USE_SELECT > 0
585a7ec597cSGregory Neil Shapiro 		timersub(&slpv, &diff, &sm_io_to);
5865b0945b5SGregory Neil Shapiro #  endif
587a7ec597cSGregory Neil Shapiro # else /* SM_CONF_SETITIMER */
588a7ec597cSGregory Neil Shapiro 		now = time(NULL);
589a7ec597cSGregory Neil Shapiro 
590a7ec597cSGregory Neil Shapiro 		/*
591a7ec597cSGregory Neil Shapiro 		**  Check whether time expired before signal is released.
592a7ec597cSGregory Neil Shapiro 		**  Due to the granularity of time() add 1 to be on the
593a7ec597cSGregory Neil Shapiro 		**  safe side.
594a7ec597cSGregory Neil Shapiro 		*/
595a7ec597cSGregory Neil Shapiro 
596a7ec597cSGregory Neil Shapiro 		if (!(begin + (time_t) intvl + 1 > now))
597a7ec597cSGregory Neil Shapiro 			break;
598a7ec597cSGregory Neil Shapiro #  if _FFR_SLEEP_USE_SELECT > 0
599a7ec597cSGregory Neil Shapiro 		sm_io_to.tv_sec = intvl - (now - begin);
600a7ec597cSGregory Neil Shapiro 		if (sm_io_to.tv_sec <= 0)
601a7ec597cSGregory Neil Shapiro 			sm_io_to.tv_sec = 1;
602e92d3f3fSGregory Neil Shapiro 		sm_io_to.tv_usec = 0;
603a7ec597cSGregory Neil Shapiro #  endif /* _FFR_SLEEP_USE_SELECT > 0 */
604a7ec597cSGregory Neil Shapiro # endif /* SM_CONF_SETITIMER */
605a7ec597cSGregory Neil Shapiro # if _FFR_SLEEP_USE_SELECT > 0
606a7ec597cSGregory Neil Shapiro 		if (intvl <= _FFR_SLEEP_USE_SELECT)
607a7ec597cSGregory Neil Shapiro 		{
608a7ec597cSGregory Neil Shapiro 			r = select(0, NULL, NULL, NULL, &sm_io_to);
609a7ec597cSGregory Neil Shapiro 			if (r == 0)
610a7ec597cSGregory Neil Shapiro 				break;
611a7ec597cSGregory Neil Shapiro 		}
612a7ec597cSGregory Neil Shapiro 		else
613a7ec597cSGregory Neil Shapiro # endif /* _FFR_SLEEP_USE_SELECT > 0 */
614*2fb4f839SGregory Neil Shapiro 		/* "else" in #if code above */
61540266059SGregory Neil Shapiro 		(void) pause();
616a7ec597cSGregory Neil Shapiro 	}
617a7ec597cSGregory Neil Shapiro 
618a7ec597cSGregory Neil Shapiro 	/* if out of the loop without the event being triggered remove it */
619a7ec597cSGregory Neil Shapiro 	if (!SmSleepDone)
620a7ec597cSGregory Neil Shapiro 		sm_clrevent(ev);
62140266059SGregory Neil Shapiro 	if (was_held > 0)
62240266059SGregory Neil Shapiro 		(void) sm_blocksignal(SIGALRM);
62340266059SGregory Neil Shapiro 	return (SLEEP_T) 0;
624a7ec597cSGregory Neil Shapiro #endif /* HAVE_NANOSLEEP */
62540266059SGregory Neil Shapiro }
62640266059SGregory Neil Shapiro 
627a7ec597cSGregory Neil Shapiro #if !HAVE_NANOSLEEP
62840266059SGregory Neil Shapiro static void
sm_endsleep(ignore)629b6bacd31SGregory Neil Shapiro sm_endsleep(ignore)
630b6bacd31SGregory Neil Shapiro 	int ignore;
63140266059SGregory Neil Shapiro {
63240266059SGregory Neil Shapiro 	/*
63340266059SGregory Neil Shapiro 	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
63440266059SGregory Neil Shapiro 	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
63540266059SGregory Neil Shapiro 	**	DOING.
63640266059SGregory Neil Shapiro 	*/
63740266059SGregory Neil Shapiro 
63840266059SGregory Neil Shapiro 	SmSleepDone = true;
63940266059SGregory Neil Shapiro }
640a7ec597cSGregory Neil Shapiro #endif /* !HAVE_NANOSLEEP */
64140266059SGregory Neil Shapiro 
642