190792Sgshapiro/*
2261194Sgshapiro * Copyright (c) 1998-2004 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *	All rights reserved.
490792Sgshapiro * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
590792Sgshapiro * Copyright (c) 1988, 1993
690792Sgshapiro *	The Regents of the University of California.  All rights reserved.
790792Sgshapiro *
890792Sgshapiro * By using this file, you agree to the terms and conditions set
990792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1090792Sgshapiro * the sendmail distribution.
1190792Sgshapiro *
1290792Sgshapiro */
1390792Sgshapiro
1490792Sgshapiro#include <sm/gen.h>
15266527SgshapiroSM_RCSID("@(#)$Id: clock.c,v 1.48 2013-11-22 20:51:42 ca Exp $")
1690792Sgshapiro#include <unistd.h>
1790792Sgshapiro#include <time.h>
1890792Sgshapiro#include <errno.h>
1990792Sgshapiro#if SM_CONF_SETITIMER
20157001Sgshapiro# include <sm/time.h>
21363466Sgshapiro#endif
2290792Sgshapiro#include <sm/heap.h>
2390792Sgshapiro#include <sm/debug.h>
2490792Sgshapiro#include <sm/bitops.h>
2590792Sgshapiro#include <sm/clock.h>
2690792Sgshapiro#include "local.h"
27120256Sgshapiro#if _FFR_SLEEP_USE_SELECT > 0
28120256Sgshapiro# include <sys/types.h>
29363466Sgshapiro#endif
30120256Sgshapiro#if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
31120256Sgshapiro# include <syslog.h>
32363466Sgshapiro#endif
3390792Sgshapiro
3490792Sgshapiro#ifndef sigmask
3590792Sgshapiro# define sigmask(s)	(1 << ((s) - 1))
36363466Sgshapiro#endif
3790792Sgshapiro
3890792Sgshapiro
3990792Sgshapiro/*
4090792Sgshapiro**  SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
4190792Sgshapiro**
4290792Sgshapiro**	Events are stored in a sorted list for fast processing.
4390792Sgshapiro**	An event only applies to the process that set it.
4490792Sgshapiro**	Source is #ifdef'd to work with older OS's that don't have setitimer()
4590792Sgshapiro**	(that is, don't have a timer granularity less than 1 second).
4690792Sgshapiro**
4790792Sgshapiro**	Parameters:
4890792Sgshapiro**		intvl -- interval until next event occurs (milliseconds).
4990792Sgshapiro**		func -- function to call on event.
5090792Sgshapiro**		arg -- argument to func on event.
5190792Sgshapiro**
5290792Sgshapiro**	Returns:
5390792Sgshapiro**		On success returns the SM_EVENT entry created.
5490792Sgshapiro**		On failure returns NULL.
5590792Sgshapiro**
5690792Sgshapiro**	Side Effects:
5790792Sgshapiro**		none.
5890792Sgshapiro*/
5990792Sgshapiro
6090792Sgshapirostatic SM_EVENT	*volatile SmEventQueue;		/* head of event queue */
6190792Sgshapirostatic SM_EVENT	*volatile SmFreeEventList;	/* list of free events */
6290792Sgshapiro
6390792SgshapiroSM_EVENT *
6490792Sgshapirosm_seteventm(intvl, func, arg)
6590792Sgshapiro	int intvl;
66141858Sgshapiro	void (*func)__P((int));
6790792Sgshapiro	int arg;
6890792Sgshapiro{
6990792Sgshapiro	ENTER_CRITICAL();
7090792Sgshapiro	if (SmFreeEventList == NULL)
7190792Sgshapiro	{
7290792Sgshapiro		SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
7390792Sgshapiro		SmFreeEventList->ev_link = NULL;
7490792Sgshapiro	}
7590792Sgshapiro	LEAVE_CRITICAL();
7690792Sgshapiro
7790792Sgshapiro	return sm_sigsafe_seteventm(intvl, func, arg);
7890792Sgshapiro}
7990792Sgshapiro
8090792Sgshapiro/*
8190792Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
8290792Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
8390792Sgshapiro**		DOING.
8490792Sgshapiro*/
8590792Sgshapiro
8690792SgshapiroSM_EVENT *
8790792Sgshapirosm_sigsafe_seteventm(intvl, func, arg)
8890792Sgshapiro	int intvl;
89141858Sgshapiro	void (*func)__P((int));
9090792Sgshapiro	int arg;
9190792Sgshapiro{
9290792Sgshapiro	register SM_EVENT **evp;
9390792Sgshapiro	register SM_EVENT *ev;
9490792Sgshapiro#if SM_CONF_SETITIMER
9590792Sgshapiro	auto struct timeval now, nowi, ival;
9690792Sgshapiro	auto struct itimerval itime;
97363466Sgshapiro#else
9890792Sgshapiro	auto time_t now, nowi;
99363466Sgshapiro#endif
10090792Sgshapiro	int wasblocked;
10190792Sgshapiro
10290792Sgshapiro	/* negative times are not allowed */
10390792Sgshapiro	if (intvl <= 0)
10490792Sgshapiro		return NULL;
10590792Sgshapiro
10690792Sgshapiro	wasblocked = sm_blocksignal(SIGALRM);
10790792Sgshapiro#if SM_CONF_SETITIMER
10890792Sgshapiro	ival.tv_sec = intvl / 1000;
10990792Sgshapiro	ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
11090792Sgshapiro	(void) gettimeofday(&now, NULL);
11190792Sgshapiro	nowi = now;
11290792Sgshapiro	timeradd(&now, &ival, &nowi);
11390792Sgshapiro#else /*  SM_CONF_SETITIMER */
11490792Sgshapiro	now = time(NULL);
11590792Sgshapiro	nowi = now + (time_t)(intvl / 1000);
11690792Sgshapiro#endif /*  SM_CONF_SETITIMER */
11790792Sgshapiro
11890792Sgshapiro	/* search event queue for correct position */
11990792Sgshapiro	for (evp = (SM_EVENT **) (&SmEventQueue);
12090792Sgshapiro	     (ev = *evp) != NULL;
12190792Sgshapiro	     evp = &ev->ev_link)
12290792Sgshapiro	{
12390792Sgshapiro#if SM_CONF_SETITIMER
12490792Sgshapiro		if (timercmp(&(ev->ev_time), &nowi, >=))
125363466Sgshapiro#else
12690792Sgshapiro		if (ev->ev_time >= nowi)
127363466Sgshapiro#endif
12890792Sgshapiro			break;
12990792Sgshapiro	}
13090792Sgshapiro
13190792Sgshapiro	ENTER_CRITICAL();
13290792Sgshapiro	if (SmFreeEventList == NULL)
13390792Sgshapiro	{
13490792Sgshapiro		/*
13590792Sgshapiro		**  This shouldn't happen.  If called from sm_seteventm(),
13690792Sgshapiro		**  we have just malloced a SmFreeEventList entry.  If
13790792Sgshapiro		**  called from a signal handler, it should have been
13890792Sgshapiro		**  from an existing event which sm_tick() just added to
13990792Sgshapiro		**  SmFreeEventList.
14090792Sgshapiro		*/
14190792Sgshapiro
14290792Sgshapiro		LEAVE_CRITICAL();
143120256Sgshapiro		if (wasblocked == 0)
144120256Sgshapiro			(void) sm_releasesignal(SIGALRM);
14590792Sgshapiro		return NULL;
14690792Sgshapiro	}
14790792Sgshapiro	else
14890792Sgshapiro	{
14990792Sgshapiro		ev = SmFreeEventList;
15090792Sgshapiro		SmFreeEventList = ev->ev_link;
15190792Sgshapiro	}
15290792Sgshapiro	LEAVE_CRITICAL();
15390792Sgshapiro
15490792Sgshapiro	/* insert new event */
15590792Sgshapiro	ev->ev_time = nowi;
15690792Sgshapiro	ev->ev_func = func;
15790792Sgshapiro	ev->ev_arg = arg;
15890792Sgshapiro	ev->ev_pid = getpid();
15990792Sgshapiro	ENTER_CRITICAL();
16090792Sgshapiro	ev->ev_link = *evp;
16190792Sgshapiro	*evp = ev;
16290792Sgshapiro	LEAVE_CRITICAL();
16390792Sgshapiro
16490792Sgshapiro	(void) sm_signal(SIGALRM, sm_tick);
16590792Sgshapiro# if SM_CONF_SETITIMER
16690792Sgshapiro	timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
16790792Sgshapiro	itime.it_interval.tv_sec = 0;
16890792Sgshapiro	itime.it_interval.tv_usec = 0;
16994334Sgshapiro	if (itime.it_value.tv_sec < 0)
17094334Sgshapiro		itime.it_value.tv_sec = 0;
17190792Sgshapiro	if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
17290792Sgshapiro		itime.it_value.tv_usec = 1000;
17390792Sgshapiro	(void) setitimer(ITIMER_REAL, &itime, NULL);
17490792Sgshapiro# else /* SM_CONF_SETITIMER */
17590792Sgshapiro	intvl = SmEventQueue->ev_time - now;
176112810Sgshapiro	(void) alarm((unsigned) (intvl < 1 ? 1 : intvl));
17790792Sgshapiro# endif /* SM_CONF_SETITIMER */
17890792Sgshapiro	if (wasblocked == 0)
17990792Sgshapiro		(void) sm_releasesignal(SIGALRM);
18090792Sgshapiro	return ev;
18190792Sgshapiro}
18290792Sgshapiro/*
18390792Sgshapiro**  SM_CLREVENT -- remove an event from the event queue.
18490792Sgshapiro**
18590792Sgshapiro**	Parameters:
18690792Sgshapiro**		ev -- pointer to event to remove.
18790792Sgshapiro**
18890792Sgshapiro**	Returns:
18990792Sgshapiro**		none.
19090792Sgshapiro**
19190792Sgshapiro**	Side Effects:
19290792Sgshapiro**		arranges for event ev to not happen.
19390792Sgshapiro*/
19490792Sgshapiro
19590792Sgshapirovoid
19690792Sgshapirosm_clrevent(ev)
19790792Sgshapiro	register SM_EVENT *ev;
19890792Sgshapiro{
19990792Sgshapiro	register SM_EVENT **evp;
20090792Sgshapiro	int wasblocked;
20190792Sgshapiro# if SM_CONF_SETITIMER
20290792Sgshapiro	struct itimerval clr;
203363466Sgshapiro# endif
20490792Sgshapiro
20590792Sgshapiro	if (ev == NULL)
20690792Sgshapiro		return;
20790792Sgshapiro
20890792Sgshapiro	/* find the parent event */
20990792Sgshapiro	wasblocked = sm_blocksignal(SIGALRM);
21090792Sgshapiro	for (evp = (SM_EVENT **) (&SmEventQueue);
21190792Sgshapiro	     *evp != NULL;
21290792Sgshapiro	     evp = &(*evp)->ev_link)
21390792Sgshapiro	{
21490792Sgshapiro		if (*evp == ev)
21590792Sgshapiro			break;
21690792Sgshapiro	}
21790792Sgshapiro
21890792Sgshapiro	/* now remove it */
21990792Sgshapiro	if (*evp != NULL)
22090792Sgshapiro	{
22190792Sgshapiro		ENTER_CRITICAL();
22290792Sgshapiro		*evp = ev->ev_link;
22390792Sgshapiro		ev->ev_link = SmFreeEventList;
22490792Sgshapiro		SmFreeEventList = ev;
22590792Sgshapiro		LEAVE_CRITICAL();
22690792Sgshapiro	}
22790792Sgshapiro
22890792Sgshapiro	/* restore clocks and pick up anything spare */
22990792Sgshapiro	if (wasblocked == 0)
23090792Sgshapiro		(void) sm_releasesignal(SIGALRM);
23190792Sgshapiro	if (SmEventQueue != NULL)
23290792Sgshapiro		(void) kill(getpid(), SIGALRM);
23390792Sgshapiro	else
23490792Sgshapiro	{
23590792Sgshapiro		/* nothing left in event queue, no need for an alarm */
23690792Sgshapiro# if SM_CONF_SETITIMER
23790792Sgshapiro		clr.it_interval.tv_sec = 0;
23890792Sgshapiro		clr.it_interval.tv_usec = 0;
23990792Sgshapiro		clr.it_value.tv_sec = 0;
24090792Sgshapiro		clr.it_value.tv_usec = 0;
24190792Sgshapiro		(void) setitimer(ITIMER_REAL, &clr, NULL);
24290792Sgshapiro# else /* SM_CONF_SETITIMER */
24390792Sgshapiro		(void) alarm(0);
24490792Sgshapiro# endif /* SM_CONF_SETITIMER */
24590792Sgshapiro	}
24690792Sgshapiro}
24790792Sgshapiro/*
24890792Sgshapiro**  SM_CLEAR_EVENTS -- remove all events from the event queue.
24990792Sgshapiro**
25090792Sgshapiro**	Parameters:
25190792Sgshapiro**		none.
25290792Sgshapiro**
25390792Sgshapiro**	Returns:
25490792Sgshapiro**		none.
25590792Sgshapiro*/
25690792Sgshapiro
25790792Sgshapirovoid
25890792Sgshapirosm_clear_events()
25990792Sgshapiro{
26090792Sgshapiro	register SM_EVENT *ev;
26190792Sgshapiro#if SM_CONF_SETITIMER
26290792Sgshapiro	struct itimerval clr;
263363466Sgshapiro#endif
26490792Sgshapiro	int wasblocked;
26590792Sgshapiro
26690792Sgshapiro	/* nothing will be left in event queue, no need for an alarm */
26790792Sgshapiro#if SM_CONF_SETITIMER
26890792Sgshapiro	clr.it_interval.tv_sec = 0;
26990792Sgshapiro	clr.it_interval.tv_usec = 0;
27090792Sgshapiro	clr.it_value.tv_sec = 0;
27190792Sgshapiro	clr.it_value.tv_usec = 0;
27290792Sgshapiro	(void) setitimer(ITIMER_REAL, &clr, NULL);
27390792Sgshapiro#else /* SM_CONF_SETITIMER */
27490792Sgshapiro	(void) alarm(0);
27590792Sgshapiro#endif /* SM_CONF_SETITIMER */
27698841Sgshapiro
27798841Sgshapiro	if (SmEventQueue == NULL)
27898841Sgshapiro		return;
27998841Sgshapiro
28090792Sgshapiro	wasblocked = sm_blocksignal(SIGALRM);
28190792Sgshapiro
28290792Sgshapiro	/* find the end of the EventQueue */
28390792Sgshapiro	for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
28490792Sgshapiro		continue;
28590792Sgshapiro
28690792Sgshapiro	ENTER_CRITICAL();
28790792Sgshapiro	ev->ev_link = SmFreeEventList;
28890792Sgshapiro	SmFreeEventList = SmEventQueue;
28990792Sgshapiro	SmEventQueue = NULL;
29090792Sgshapiro	LEAVE_CRITICAL();
29190792Sgshapiro
29290792Sgshapiro	/* restore clocks and pick up anything spare */
29390792Sgshapiro	if (wasblocked == 0)
29490792Sgshapiro		(void) sm_releasesignal(SIGALRM);
29590792Sgshapiro}
29690792Sgshapiro/*
29790792Sgshapiro**  SM_TICK -- take a clock tick
29890792Sgshapiro**
29990792Sgshapiro**	Called by the alarm clock.  This routine runs events as needed.
30090792Sgshapiro**	Always called as a signal handler, so we assume that SIGALRM
30190792Sgshapiro**	has been blocked.
30290792Sgshapiro**
30390792Sgshapiro**	Parameters:
30490792Sgshapiro**		One that is ignored; for compatibility with signal handlers.
30590792Sgshapiro**
30690792Sgshapiro**	Returns:
30790792Sgshapiro**		none.
30890792Sgshapiro**
30990792Sgshapiro**	Side Effects:
31090792Sgshapiro**		calls the next function in EventQueue.
31190792Sgshapiro**
31290792Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
31390792Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
31490792Sgshapiro**		DOING.
31590792Sgshapiro*/
31690792Sgshapiro
31790792Sgshapiro/* ARGSUSED */
31890792SgshapiroSIGFUNC_DECL
31990792Sgshapirosm_tick(sig)
32090792Sgshapiro	int sig;
32190792Sgshapiro{
32290792Sgshapiro	register SM_EVENT *ev;
32390792Sgshapiro	pid_t mypid;
32490792Sgshapiro	int save_errno = errno;
32590792Sgshapiro#if SM_CONF_SETITIMER
32690792Sgshapiro	struct itimerval clr;
32790792Sgshapiro	struct timeval now;
328363466Sgshapiro#else
32990792Sgshapiro	register time_t now;
33090792Sgshapiro#endif /* SM_CONF_SETITIMER */
33190792Sgshapiro
33290792Sgshapiro#if SM_CONF_SETITIMER
33390792Sgshapiro	clr.it_interval.tv_sec = 0;
33490792Sgshapiro	clr.it_interval.tv_usec = 0;
33590792Sgshapiro	clr.it_value.tv_sec = 0;
33690792Sgshapiro	clr.it_value.tv_usec = 0;
33790792Sgshapiro	(void) setitimer(ITIMER_REAL, &clr, NULL);
33890792Sgshapiro	gettimeofday(&now, NULL);
33990792Sgshapiro#else /* SM_CONF_SETITIMER */
34090792Sgshapiro	(void) alarm(0);
34190792Sgshapiro	now = time(NULL);
34290792Sgshapiro#endif /* SM_CONF_SETITIMER */
34390792Sgshapiro
34490792Sgshapiro	FIX_SYSV_SIGNAL(sig, sm_tick);
34590792Sgshapiro	errno = save_errno;
34690792Sgshapiro	CHECK_CRITICAL(sig);
34790792Sgshapiro
34890792Sgshapiro	mypid = getpid();
34990792Sgshapiro	while (PendingSignal != 0)
35090792Sgshapiro	{
35190792Sgshapiro		int sigbit = 0;
35290792Sgshapiro		int sig = 0;
35390792Sgshapiro
35490792Sgshapiro		if (bitset(PEND_SIGHUP, PendingSignal))
35590792Sgshapiro		{
35690792Sgshapiro			sigbit = PEND_SIGHUP;
35790792Sgshapiro			sig = SIGHUP;
35890792Sgshapiro		}
35990792Sgshapiro		else if (bitset(PEND_SIGINT, PendingSignal))
36090792Sgshapiro		{
36190792Sgshapiro			sigbit = PEND_SIGINT;
36290792Sgshapiro			sig = SIGINT;
36390792Sgshapiro		}
36490792Sgshapiro		else if (bitset(PEND_SIGTERM, PendingSignal))
36590792Sgshapiro		{
36690792Sgshapiro			sigbit = PEND_SIGTERM;
36790792Sgshapiro			sig = SIGTERM;
36890792Sgshapiro		}
36990792Sgshapiro		else if (bitset(PEND_SIGUSR1, PendingSignal))
37090792Sgshapiro		{
37190792Sgshapiro			sigbit = PEND_SIGUSR1;
37290792Sgshapiro			sig = SIGUSR1;
37390792Sgshapiro		}
37490792Sgshapiro		else
37590792Sgshapiro		{
37690792Sgshapiro			/* If we get here, we are in trouble */
37790792Sgshapiro			abort();
37890792Sgshapiro		}
37990792Sgshapiro		PendingSignal &= ~sigbit;
38090792Sgshapiro		kill(mypid, sig);
38190792Sgshapiro	}
38290792Sgshapiro
38390792Sgshapiro#if SM_CONF_SETITIMER
38490792Sgshapiro	gettimeofday(&now, NULL);
385363466Sgshapiro#else
38690792Sgshapiro	now = time(NULL);
387363466Sgshapiro#endif
38890792Sgshapiro	while ((ev = SmEventQueue) != NULL &&
38990792Sgshapiro	       (ev->ev_pid != mypid ||
39090792Sgshapiro#if SM_CONF_SETITIMER
39190792Sgshapiro		timercmp(&ev->ev_time, &now, <=)
392363466Sgshapiro#else
39390792Sgshapiro		ev->ev_time <= now
394363466Sgshapiro#endif
39590792Sgshapiro		))
39690792Sgshapiro	{
397141858Sgshapiro		void (*f)__P((int));
39890792Sgshapiro		int arg;
39990792Sgshapiro		pid_t pid;
40090792Sgshapiro
40190792Sgshapiro		/* process the event on the top of the queue */
40290792Sgshapiro		ev = SmEventQueue;
40390792Sgshapiro		SmEventQueue = SmEventQueue->ev_link;
40490792Sgshapiro
40590792Sgshapiro		/* we must be careful in here because ev_func may not return */
40690792Sgshapiro		f = ev->ev_func;
40790792Sgshapiro		arg = ev->ev_arg;
40890792Sgshapiro		pid = ev->ev_pid;
40990792Sgshapiro		ENTER_CRITICAL();
41090792Sgshapiro		ev->ev_link = SmFreeEventList;
41190792Sgshapiro		SmFreeEventList = ev;
41290792Sgshapiro		LEAVE_CRITICAL();
41390792Sgshapiro		if (pid != getpid())
41490792Sgshapiro			continue;
41590792Sgshapiro		if (SmEventQueue != NULL)
41690792Sgshapiro		{
41790792Sgshapiro#if SM_CONF_SETITIMER
41890792Sgshapiro			if (timercmp(&SmEventQueue->ev_time, &now, >))
41990792Sgshapiro			{
42090792Sgshapiro				timersub(&SmEventQueue->ev_time, &now,
42190792Sgshapiro					 &clr.it_value);
42290792Sgshapiro				clr.it_interval.tv_sec = 0;
42390792Sgshapiro				clr.it_interval.tv_usec = 0;
42494334Sgshapiro				if (clr.it_value.tv_sec < 0)
42594334Sgshapiro					clr.it_value.tv_sec = 0;
42694334Sgshapiro				if (clr.it_value.tv_sec == 0 &&
42794334Sgshapiro				    clr.it_value.tv_usec == 0)
42894334Sgshapiro					clr.it_value.tv_usec = 1000;
42990792Sgshapiro				(void) setitimer(ITIMER_REAL, &clr, NULL);
43090792Sgshapiro			}
43190792Sgshapiro			else
43290792Sgshapiro			{
43390792Sgshapiro				clr.it_interval.tv_sec = 0;
43490792Sgshapiro				clr.it_interval.tv_usec = 0;
43590792Sgshapiro				clr.it_value.tv_sec = 3;
43690792Sgshapiro				clr.it_value.tv_usec = 0;
43790792Sgshapiro				(void) setitimer(ITIMER_REAL, &clr, NULL);
43890792Sgshapiro			}
43990792Sgshapiro#else /* SM_CONF_SETITIMER */
44090792Sgshapiro			if (SmEventQueue->ev_time > now)
44190792Sgshapiro				(void) alarm((unsigned) (SmEventQueue->ev_time
44290792Sgshapiro							 - now));
44390792Sgshapiro			else
44490792Sgshapiro				(void) alarm(3);
44590792Sgshapiro#endif /* SM_CONF_SETITIMER */
44690792Sgshapiro		}
44790792Sgshapiro
44890792Sgshapiro		/* call ev_func */
44990792Sgshapiro		errno = save_errno;
45090792Sgshapiro		(*f)(arg);
45190792Sgshapiro#if SM_CONF_SETITIMER
45290792Sgshapiro		clr.it_interval.tv_sec = 0;
45390792Sgshapiro		clr.it_interval.tv_usec = 0;
45490792Sgshapiro		clr.it_value.tv_sec = 0;
45590792Sgshapiro		clr.it_value.tv_usec = 0;
45690792Sgshapiro		(void) setitimer(ITIMER_REAL, &clr, NULL);
45790792Sgshapiro		gettimeofday(&now, NULL);
45890792Sgshapiro#else /* SM_CONF_SETITIMER */
45990792Sgshapiro		(void) alarm(0);
46090792Sgshapiro		now = time(NULL);
46190792Sgshapiro#endif /* SM_CONF_SETITIMER */
46290792Sgshapiro	}
46390792Sgshapiro	if (SmEventQueue != NULL)
46490792Sgshapiro	{
46590792Sgshapiro#if SM_CONF_SETITIMER
46690792Sgshapiro		timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
46790792Sgshapiro		clr.it_interval.tv_sec = 0;
46890792Sgshapiro		clr.it_interval.tv_usec = 0;
46994334Sgshapiro		if (clr.it_value.tv_sec < 0)
47094334Sgshapiro			clr.it_value.tv_sec = 0;
47194334Sgshapiro		if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
47294334Sgshapiro			clr.it_value.tv_usec = 1000;
47390792Sgshapiro		(void) setitimer(ITIMER_REAL, &clr, NULL);
47490792Sgshapiro#else /* SM_CONF_SETITIMER */
47590792Sgshapiro		(void) alarm((unsigned) (SmEventQueue->ev_time - now));
47690792Sgshapiro#endif /* SM_CONF_SETITIMER */
47790792Sgshapiro	}
47890792Sgshapiro	errno = save_errno;
47990792Sgshapiro	return SIGFUNC_RETURN;
48090792Sgshapiro}
48190792Sgshapiro/*
48290792Sgshapiro**  SLEEP -- a version of sleep that works with this stuff
48390792Sgshapiro**
48490792Sgshapiro**	Because Unix sleep uses the alarm facility, I must reimplement
48590792Sgshapiro**	it here.
48690792Sgshapiro**
48790792Sgshapiro**	Parameters:
48890792Sgshapiro**		intvl -- time to sleep.
48990792Sgshapiro**
49090792Sgshapiro**	Returns:
49190792Sgshapiro**		zero.
49290792Sgshapiro**
49390792Sgshapiro**	Side Effects:
49490792Sgshapiro**		waits for intvl time.  However, other events can
49590792Sgshapiro**		be run during that interval.
49690792Sgshapiro*/
49790792Sgshapiro
49890792Sgshapiro
499120256Sgshapiro# if !HAVE_NANOSLEEP
500141858Sgshapirostatic void	sm_endsleep __P((int));
50190792Sgshapirostatic bool	volatile SmSleepDone;
502363466Sgshapiro# endif
50390792Sgshapiro
50490792Sgshapiro#ifndef SLEEP_T
50590792Sgshapiro# define SLEEP_T	unsigned int
506363466Sgshapiro#endif
50790792Sgshapiro
50890792SgshapiroSLEEP_T
50990792Sgshapirosleep(intvl)
51090792Sgshapiro	unsigned int intvl;
51190792Sgshapiro{
512120256Sgshapiro#if HAVE_NANOSLEEP
513120256Sgshapiro	struct timespec rqtp;
514120256Sgshapiro
515120256Sgshapiro	if (intvl == 0)
516120256Sgshapiro		return (SLEEP_T) 0;
517120256Sgshapiro	rqtp.tv_sec = intvl;
518120256Sgshapiro	rqtp.tv_nsec = 0;
519120256Sgshapiro	nanosleep(&rqtp, NULL);
520120256Sgshapiro	return (SLEEP_T) 0;
521120256Sgshapiro#else /* HAVE_NANOSLEEP */
52290792Sgshapiro	int was_held;
523120256Sgshapiro	SM_EVENT *ev;
524120256Sgshapiro#if _FFR_SLEEP_USE_SELECT > 0
525120256Sgshapiro	int r;
526132943Sgshapiro# if _FFR_SLEEP_USE_SELECT > 0
527132943Sgshapiro	struct timeval sm_io_to;
528363466Sgshapiro# endif
529120256Sgshapiro#endif /* _FFR_SLEEP_USE_SELECT > 0 */
530120256Sgshapiro#if SM_CONF_SETITIMER
531120256Sgshapiro	struct timeval now, begin, diff;
532120256Sgshapiro# if _FFR_SLEEP_USE_SELECT > 0
533132943Sgshapiro	struct timeval slpv;
534363466Sgshapiro# endif
535120256Sgshapiro#else /*  SM_CONF_SETITIMER */
536120256Sgshapiro	time_t begin, now;
537120256Sgshapiro#endif /*  SM_CONF_SETITIMER */
53890792Sgshapiro
53990792Sgshapiro	if (intvl == 0)
54090792Sgshapiro		return (SLEEP_T) 0;
541120256Sgshapiro#if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
542120256Sgshapiro	if (intvl > _FFR_MAX_SLEEP_TIME)
543120256Sgshapiro	{
544120256Sgshapiro		syslog(LOG_ERR, "sleep: interval=%u exceeds max value %d",
545120256Sgshapiro			intvl, _FFR_MAX_SLEEP_TIME);
546120256Sgshapiro# if 0
547120256Sgshapiro		SM_ASSERT(intvl < (unsigned int) INT_MAX);
548363466Sgshapiro# endif
549120256Sgshapiro		intvl = _FFR_MAX_SLEEP_TIME;
550120256Sgshapiro	}
551120256Sgshapiro#endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
55290792Sgshapiro	SmSleepDone = false;
553120256Sgshapiro
554120256Sgshapiro#if SM_CONF_SETITIMER
555120256Sgshapiro# if _FFR_SLEEP_USE_SELECT > 0
556120256Sgshapiro	slpv.tv_sec = intvl;
557120256Sgshapiro	slpv.tv_usec = 0;
558363466Sgshapiro# endif
559120256Sgshapiro	(void) gettimeofday(&now, NULL);
560120256Sgshapiro	begin = now;
561120256Sgshapiro#else /*  SM_CONF_SETITIMER */
562120256Sgshapiro	now = begin = time(NULL);
563120256Sgshapiro#endif /*  SM_CONF_SETITIMER */
564120256Sgshapiro
565120256Sgshapiro	ev = sm_setevent((time_t) intvl, sm_endsleep, 0);
566120256Sgshapiro	if (ev == NULL)
567120256Sgshapiro	{
568120256Sgshapiro		/* COMPLAIN */
569120256Sgshapiro#if 0
570120256Sgshapiro		syslog(LOG_ERR, "sleep: sm_setevent(%u) failed", intvl);
571363466Sgshapiro#endif
572120256Sgshapiro		SmSleepDone = true;
573120256Sgshapiro	}
57490792Sgshapiro	was_held = sm_releasesignal(SIGALRM);
575120256Sgshapiro
57690792Sgshapiro	while (!SmSleepDone)
577120256Sgshapiro	{
578120256Sgshapiro#if SM_CONF_SETITIMER
579120256Sgshapiro		(void) gettimeofday(&now, NULL);
580120256Sgshapiro		timersub(&now, &begin, &diff);
581120256Sgshapiro		if (diff.tv_sec < 0 ||
582120256Sgshapiro		    (diff.tv_sec == 0 && diff.tv_usec == 0))
583120256Sgshapiro			break;
584120256Sgshapiro# if _FFR_SLEEP_USE_SELECT > 0
585120256Sgshapiro		timersub(&slpv, &diff, &sm_io_to);
586363466Sgshapiro# endif
587120256Sgshapiro#else /* SM_CONF_SETITIMER */
588120256Sgshapiro		now = time(NULL);
589120256Sgshapiro
590120256Sgshapiro		/*
591120256Sgshapiro		**  Check whether time expired before signal is released.
592120256Sgshapiro		**  Due to the granularity of time() add 1 to be on the
593120256Sgshapiro		**  safe side.
594120256Sgshapiro		*/
595120256Sgshapiro
596120256Sgshapiro		if (!(begin + (time_t) intvl + 1 > now))
597120256Sgshapiro			break;
598120256Sgshapiro# if _FFR_SLEEP_USE_SELECT > 0
599120256Sgshapiro		sm_io_to.tv_sec = intvl - (now - begin);
600120256Sgshapiro		if (sm_io_to.tv_sec <= 0)
601120256Sgshapiro			sm_io_to.tv_sec = 1;
602132943Sgshapiro		sm_io_to.tv_usec = 0;
603120256Sgshapiro# endif /* _FFR_SLEEP_USE_SELECT > 0 */
604120256Sgshapiro#endif /* SM_CONF_SETITIMER */
605120256Sgshapiro#if _FFR_SLEEP_USE_SELECT > 0
606120256Sgshapiro		if (intvl <= _FFR_SLEEP_USE_SELECT)
607120256Sgshapiro		{
608120256Sgshapiro			r = select(0, NULL, NULL, NULL, &sm_io_to);
609120256Sgshapiro			if (r == 0)
610120256Sgshapiro				break;
611120256Sgshapiro		}
612120256Sgshapiro		else
613120256Sgshapiro#endif /* _FFR_SLEEP_USE_SELECT > 0 */
61490792Sgshapiro		(void) pause();
615120256Sgshapiro	}
616120256Sgshapiro
617120256Sgshapiro	/* if out of the loop without the event being triggered remove it */
618120256Sgshapiro	if (!SmSleepDone)
619120256Sgshapiro		sm_clrevent(ev);
62090792Sgshapiro	if (was_held > 0)
62190792Sgshapiro		(void) sm_blocksignal(SIGALRM);
62290792Sgshapiro	return (SLEEP_T) 0;
623120256Sgshapiro#endif /* HAVE_NANOSLEEP */
62490792Sgshapiro}
62590792Sgshapiro
626120256Sgshapiro#if !HAVE_NANOSLEEP
62790792Sgshapirostatic void
628141858Sgshapirosm_endsleep(ignore)
629141858Sgshapiro	int ignore;
63090792Sgshapiro{
63190792Sgshapiro	/*
63290792Sgshapiro	**  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
63390792Sgshapiro	**	ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
63490792Sgshapiro	**	DOING.
63590792Sgshapiro	*/
63690792Sgshapiro
63790792Sgshapiro	SmSleepDone = true;
63890792Sgshapiro}
639120256Sgshapiro#endif /* !HAVE_NANOSLEEP */
64090792Sgshapiro
641