17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate * the sendmail distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
157c478bd9Sstevel@tonic-gate
167c478bd9Sstevel@tonic-gate #include <sm/gen.h>
17*49218d4fSjbeck SM_RCSID("@(#)$Id: clock.c,v 1.47 2005/06/14 23:07:20 ca Exp $")
187c478bd9Sstevel@tonic-gate #include <unistd.h>
197c478bd9Sstevel@tonic-gate #include <time.h>
207c478bd9Sstevel@tonic-gate #include <errno.h>
217c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
22*49218d4fSjbeck # include <sm/time.h>
237c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
247c478bd9Sstevel@tonic-gate #include <sm/heap.h>
257c478bd9Sstevel@tonic-gate #include <sm/debug.h>
267c478bd9Sstevel@tonic-gate #include <sm/bitops.h>
277c478bd9Sstevel@tonic-gate #include <sm/clock.h>
287c478bd9Sstevel@tonic-gate #include "local.h"
297c478bd9Sstevel@tonic-gate #if _FFR_SLEEP_USE_SELECT > 0
307c478bd9Sstevel@tonic-gate # include <sys/types.h>
317c478bd9Sstevel@tonic-gate #endif /* _FFR_SLEEP_USE_SELECT > 0 */
327c478bd9Sstevel@tonic-gate #if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
337c478bd9Sstevel@tonic-gate # include <syslog.h>
347c478bd9Sstevel@tonic-gate #endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #ifndef sigmask
377c478bd9Sstevel@tonic-gate # define sigmask(s) (1 << ((s) - 1))
387c478bd9Sstevel@tonic-gate #endif /* ! sigmask */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate ** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
437c478bd9Sstevel@tonic-gate **
447c478bd9Sstevel@tonic-gate ** Events are stored in a sorted list for fast processing.
457c478bd9Sstevel@tonic-gate ** An event only applies to the process that set it.
467c478bd9Sstevel@tonic-gate ** Source is #ifdef'd to work with older OS's that don't have setitimer()
477c478bd9Sstevel@tonic-gate ** (that is, don't have a timer granularity less than 1 second).
487c478bd9Sstevel@tonic-gate **
497c478bd9Sstevel@tonic-gate ** Parameters:
507c478bd9Sstevel@tonic-gate ** intvl -- interval until next event occurs (milliseconds).
517c478bd9Sstevel@tonic-gate ** func -- function to call on event.
527c478bd9Sstevel@tonic-gate ** arg -- argument to func on event.
537c478bd9Sstevel@tonic-gate **
547c478bd9Sstevel@tonic-gate ** Returns:
557c478bd9Sstevel@tonic-gate ** On success returns the SM_EVENT entry created.
567c478bd9Sstevel@tonic-gate ** On failure returns NULL.
577c478bd9Sstevel@tonic-gate **
587c478bd9Sstevel@tonic-gate ** Side Effects:
597c478bd9Sstevel@tonic-gate ** none.
607c478bd9Sstevel@tonic-gate */
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate static SM_EVENT *volatile SmEventQueue; /* head of event queue */
637c478bd9Sstevel@tonic-gate static SM_EVENT *volatile SmFreeEventList; /* list of free events */
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate SM_EVENT *
sm_seteventm(intvl,func,arg)667c478bd9Sstevel@tonic-gate sm_seteventm(intvl, func, arg)
677c478bd9Sstevel@tonic-gate int intvl;
687c478bd9Sstevel@tonic-gate void (*func)__P((int));
697c478bd9Sstevel@tonic-gate int arg;
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
727c478bd9Sstevel@tonic-gate if (SmFreeEventList == NULL)
737c478bd9Sstevel@tonic-gate {
747c478bd9Sstevel@tonic-gate SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
757c478bd9Sstevel@tonic-gate SmFreeEventList->ev_link = NULL;
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate return sm_sigsafe_seteventm(intvl, func, arg);
807c478bd9Sstevel@tonic-gate }
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
847c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
857c478bd9Sstevel@tonic-gate ** DOING.
867c478bd9Sstevel@tonic-gate */
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate SM_EVENT *
sm_sigsafe_seteventm(intvl,func,arg)897c478bd9Sstevel@tonic-gate sm_sigsafe_seteventm(intvl, func, arg)
907c478bd9Sstevel@tonic-gate int intvl;
917c478bd9Sstevel@tonic-gate void (*func)__P((int));
927c478bd9Sstevel@tonic-gate int arg;
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate register SM_EVENT **evp;
957c478bd9Sstevel@tonic-gate register SM_EVENT *ev;
967c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
977c478bd9Sstevel@tonic-gate auto struct timeval now, nowi, ival;
987c478bd9Sstevel@tonic-gate auto struct itimerval itime;
997c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
1007c478bd9Sstevel@tonic-gate auto time_t now, nowi;
1017c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
1027c478bd9Sstevel@tonic-gate int wasblocked;
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate /* negative times are not allowed */
1057c478bd9Sstevel@tonic-gate if (intvl <= 0)
1067c478bd9Sstevel@tonic-gate return NULL;
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGALRM);
1097c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
1107c478bd9Sstevel@tonic-gate ival.tv_sec = intvl / 1000;
1117c478bd9Sstevel@tonic-gate ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
1127c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL);
1137c478bd9Sstevel@tonic-gate nowi = now;
1147c478bd9Sstevel@tonic-gate timeradd(&now, &ival, &nowi);
1157c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
1167c478bd9Sstevel@tonic-gate now = time(NULL);
1177c478bd9Sstevel@tonic-gate nowi = now + (time_t)(intvl / 1000);
1187c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate /* search event queue for correct position */
1217c478bd9Sstevel@tonic-gate for (evp = (SM_EVENT **) (&SmEventQueue);
1227c478bd9Sstevel@tonic-gate (ev = *evp) != NULL;
1237c478bd9Sstevel@tonic-gate evp = &ev->ev_link)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
1267c478bd9Sstevel@tonic-gate if (timercmp(&(ev->ev_time), &nowi, >=))
1277c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
1287c478bd9Sstevel@tonic-gate if (ev->ev_time >= nowi)
1297c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
1307c478bd9Sstevel@tonic-gate break;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
1347c478bd9Sstevel@tonic-gate if (SmFreeEventList == NULL)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate ** This shouldn't happen. If called from sm_seteventm(),
1387c478bd9Sstevel@tonic-gate ** we have just malloced a SmFreeEventList entry. If
1397c478bd9Sstevel@tonic-gate ** called from a signal handler, it should have been
1407c478bd9Sstevel@tonic-gate ** from an existing event which sm_tick() just added to
1417c478bd9Sstevel@tonic-gate ** SmFreeEventList.
1427c478bd9Sstevel@tonic-gate */
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
1457c478bd9Sstevel@tonic-gate if (wasblocked == 0)
1467c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM);
1477c478bd9Sstevel@tonic-gate return NULL;
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate else
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate ev = SmFreeEventList;
1527c478bd9Sstevel@tonic-gate SmFreeEventList = ev->ev_link;
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /* insert new event */
1577c478bd9Sstevel@tonic-gate ev->ev_time = nowi;
1587c478bd9Sstevel@tonic-gate ev->ev_func = func;
1597c478bd9Sstevel@tonic-gate ev->ev_arg = arg;
1607c478bd9Sstevel@tonic-gate ev->ev_pid = getpid();
1617c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
1627c478bd9Sstevel@tonic-gate ev->ev_link = *evp;
1637c478bd9Sstevel@tonic-gate *evp = ev;
1647c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate (void) sm_signal(SIGALRM, sm_tick);
1677c478bd9Sstevel@tonic-gate # if SM_CONF_SETITIMER
1687c478bd9Sstevel@tonic-gate timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
1697c478bd9Sstevel@tonic-gate itime.it_interval.tv_sec = 0;
1707c478bd9Sstevel@tonic-gate itime.it_interval.tv_usec = 0;
1717c478bd9Sstevel@tonic-gate if (itime.it_value.tv_sec < 0)
1727c478bd9Sstevel@tonic-gate itime.it_value.tv_sec = 0;
1737c478bd9Sstevel@tonic-gate if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
1747c478bd9Sstevel@tonic-gate itime.it_value.tv_usec = 1000;
1757c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &itime, NULL);
1767c478bd9Sstevel@tonic-gate # else /* SM_CONF_SETITIMER */
1777c478bd9Sstevel@tonic-gate intvl = SmEventQueue->ev_time - now;
1787c478bd9Sstevel@tonic-gate (void) alarm((unsigned) (intvl < 1 ? 1 : intvl));
1797c478bd9Sstevel@tonic-gate # endif /* SM_CONF_SETITIMER */
1807c478bd9Sstevel@tonic-gate if (wasblocked == 0)
1817c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM);
1827c478bd9Sstevel@tonic-gate return ev;
1837c478bd9Sstevel@tonic-gate }
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate ** SM_CLREVENT -- remove an event from the event queue.
1867c478bd9Sstevel@tonic-gate **
1877c478bd9Sstevel@tonic-gate ** Parameters:
1887c478bd9Sstevel@tonic-gate ** ev -- pointer to event to remove.
1897c478bd9Sstevel@tonic-gate **
1907c478bd9Sstevel@tonic-gate ** Returns:
1917c478bd9Sstevel@tonic-gate ** none.
1927c478bd9Sstevel@tonic-gate **
1937c478bd9Sstevel@tonic-gate ** Side Effects:
1947c478bd9Sstevel@tonic-gate ** arranges for event ev to not happen.
1957c478bd9Sstevel@tonic-gate */
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate void
sm_clrevent(ev)1987c478bd9Sstevel@tonic-gate sm_clrevent(ev)
1997c478bd9Sstevel@tonic-gate register SM_EVENT *ev;
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate register SM_EVENT **evp;
2027c478bd9Sstevel@tonic-gate int wasblocked;
2037c478bd9Sstevel@tonic-gate # if SM_CONF_SETITIMER
2047c478bd9Sstevel@tonic-gate struct itimerval clr;
2057c478bd9Sstevel@tonic-gate # endif /* SM_CONF_SETITIMER */
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate if (ev == NULL)
2087c478bd9Sstevel@tonic-gate return;
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate /* find the parent event */
2117c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGALRM);
2127c478bd9Sstevel@tonic-gate for (evp = (SM_EVENT **) (&SmEventQueue);
2137c478bd9Sstevel@tonic-gate *evp != NULL;
2147c478bd9Sstevel@tonic-gate evp = &(*evp)->ev_link)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate if (*evp == ev)
2177c478bd9Sstevel@tonic-gate break;
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate /* now remove it */
2217c478bd9Sstevel@tonic-gate if (*evp != NULL)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
2247c478bd9Sstevel@tonic-gate *evp = ev->ev_link;
2257c478bd9Sstevel@tonic-gate ev->ev_link = SmFreeEventList;
2267c478bd9Sstevel@tonic-gate SmFreeEventList = ev;
2277c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /* restore clocks and pick up anything spare */
2317c478bd9Sstevel@tonic-gate if (wasblocked == 0)
2327c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM);
2337c478bd9Sstevel@tonic-gate if (SmEventQueue != NULL)
2347c478bd9Sstevel@tonic-gate (void) kill(getpid(), SIGALRM);
2357c478bd9Sstevel@tonic-gate else
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate /* nothing left in event queue, no need for an alarm */
2387c478bd9Sstevel@tonic-gate # if SM_CONF_SETITIMER
2397c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
2407c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
2417c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
2427c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 0;
2437c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
2447c478bd9Sstevel@tonic-gate # else /* SM_CONF_SETITIMER */
2457c478bd9Sstevel@tonic-gate (void) alarm(0);
2467c478bd9Sstevel@tonic-gate # endif /* SM_CONF_SETITIMER */
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate /*
2507c478bd9Sstevel@tonic-gate ** SM_CLEAR_EVENTS -- remove all events from the event queue.
2517c478bd9Sstevel@tonic-gate **
2527c478bd9Sstevel@tonic-gate ** Parameters:
2537c478bd9Sstevel@tonic-gate ** none.
2547c478bd9Sstevel@tonic-gate **
2557c478bd9Sstevel@tonic-gate ** Returns:
2567c478bd9Sstevel@tonic-gate ** none.
2577c478bd9Sstevel@tonic-gate */
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate void
sm_clear_events()2607c478bd9Sstevel@tonic-gate sm_clear_events()
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate register SM_EVENT *ev;
2637c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
2647c478bd9Sstevel@tonic-gate struct itimerval clr;
2657c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
2667c478bd9Sstevel@tonic-gate int wasblocked;
2677c478bd9Sstevel@tonic-gate
2687c478bd9Sstevel@tonic-gate /* nothing will be left in event queue, no need for an alarm */
2697c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
2707c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
2717c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
2727c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
2737c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 0;
2747c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
2757c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
2767c478bd9Sstevel@tonic-gate (void) alarm(0);
2777c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate if (SmEventQueue == NULL)
2807c478bd9Sstevel@tonic-gate return;
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate wasblocked = sm_blocksignal(SIGALRM);
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate /* find the end of the EventQueue */
2857c478bd9Sstevel@tonic-gate for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
2867c478bd9Sstevel@tonic-gate continue;
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
2897c478bd9Sstevel@tonic-gate ev->ev_link = SmFreeEventList;
2907c478bd9Sstevel@tonic-gate SmFreeEventList = SmEventQueue;
2917c478bd9Sstevel@tonic-gate SmEventQueue = NULL;
2927c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate /* restore clocks and pick up anything spare */
2957c478bd9Sstevel@tonic-gate if (wasblocked == 0)
2967c478bd9Sstevel@tonic-gate (void) sm_releasesignal(SIGALRM);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate /*
2997c478bd9Sstevel@tonic-gate ** SM_TICK -- take a clock tick
3007c478bd9Sstevel@tonic-gate **
3017c478bd9Sstevel@tonic-gate ** Called by the alarm clock. This routine runs events as needed.
3027c478bd9Sstevel@tonic-gate ** Always called as a signal handler, so we assume that SIGALRM
3037c478bd9Sstevel@tonic-gate ** has been blocked.
3047c478bd9Sstevel@tonic-gate **
3057c478bd9Sstevel@tonic-gate ** Parameters:
3067c478bd9Sstevel@tonic-gate ** One that is ignored; for compatibility with signal handlers.
3077c478bd9Sstevel@tonic-gate **
3087c478bd9Sstevel@tonic-gate ** Returns:
3097c478bd9Sstevel@tonic-gate ** none.
3107c478bd9Sstevel@tonic-gate **
3117c478bd9Sstevel@tonic-gate ** Side Effects:
3127c478bd9Sstevel@tonic-gate ** calls the next function in EventQueue.
3137c478bd9Sstevel@tonic-gate **
3147c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
3157c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
3167c478bd9Sstevel@tonic-gate ** DOING.
3177c478bd9Sstevel@tonic-gate */
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate /* ARGSUSED */
3207c478bd9Sstevel@tonic-gate SIGFUNC_DECL
sm_tick(sig)3217c478bd9Sstevel@tonic-gate sm_tick(sig)
3227c478bd9Sstevel@tonic-gate int sig;
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate register SM_EVENT *ev;
3257c478bd9Sstevel@tonic-gate pid_t mypid;
3267c478bd9Sstevel@tonic-gate int save_errno = errno;
3277c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
3287c478bd9Sstevel@tonic-gate struct itimerval clr;
3297c478bd9Sstevel@tonic-gate struct timeval now;
3307c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
3317c478bd9Sstevel@tonic-gate register time_t now;
3327c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
3357c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
3367c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
3377c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
3387c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 0;
3397c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
3407c478bd9Sstevel@tonic-gate gettimeofday(&now, NULL);
3417c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
3427c478bd9Sstevel@tonic-gate (void) alarm(0);
3437c478bd9Sstevel@tonic-gate now = time(NULL);
3447c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate FIX_SYSV_SIGNAL(sig, sm_tick);
3477c478bd9Sstevel@tonic-gate errno = save_errno;
3487c478bd9Sstevel@tonic-gate CHECK_CRITICAL(sig);
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate mypid = getpid();
3517c478bd9Sstevel@tonic-gate while (PendingSignal != 0)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate int sigbit = 0;
3547c478bd9Sstevel@tonic-gate int sig = 0;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate if (bitset(PEND_SIGHUP, PendingSignal))
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate sigbit = PEND_SIGHUP;
3597c478bd9Sstevel@tonic-gate sig = SIGHUP;
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate else if (bitset(PEND_SIGINT, PendingSignal))
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate sigbit = PEND_SIGINT;
3647c478bd9Sstevel@tonic-gate sig = SIGINT;
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate else if (bitset(PEND_SIGTERM, PendingSignal))
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate sigbit = PEND_SIGTERM;
3697c478bd9Sstevel@tonic-gate sig = SIGTERM;
3707c478bd9Sstevel@tonic-gate }
3717c478bd9Sstevel@tonic-gate else if (bitset(PEND_SIGUSR1, PendingSignal))
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate sigbit = PEND_SIGUSR1;
3747c478bd9Sstevel@tonic-gate sig = SIGUSR1;
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate else
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate /* If we get here, we are in trouble */
3797c478bd9Sstevel@tonic-gate abort();
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate PendingSignal &= ~sigbit;
3827c478bd9Sstevel@tonic-gate kill(mypid, sig);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
3867c478bd9Sstevel@tonic-gate gettimeofday(&now, NULL);
3877c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
3887c478bd9Sstevel@tonic-gate now = time(NULL);
3897c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
3907c478bd9Sstevel@tonic-gate while ((ev = SmEventQueue) != NULL &&
3917c478bd9Sstevel@tonic-gate (ev->ev_pid != mypid ||
3927c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
3937c478bd9Sstevel@tonic-gate timercmp(&ev->ev_time, &now, <=)
3947c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
3957c478bd9Sstevel@tonic-gate ev->ev_time <= now
3967c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
3977c478bd9Sstevel@tonic-gate ))
3987c478bd9Sstevel@tonic-gate {
3997c478bd9Sstevel@tonic-gate void (*f)__P((int));
4007c478bd9Sstevel@tonic-gate int arg;
4017c478bd9Sstevel@tonic-gate pid_t pid;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate /* process the event on the top of the queue */
4047c478bd9Sstevel@tonic-gate ev = SmEventQueue;
4057c478bd9Sstevel@tonic-gate SmEventQueue = SmEventQueue->ev_link;
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /* we must be careful in here because ev_func may not return */
4087c478bd9Sstevel@tonic-gate f = ev->ev_func;
4097c478bd9Sstevel@tonic-gate arg = ev->ev_arg;
4107c478bd9Sstevel@tonic-gate pid = ev->ev_pid;
4117c478bd9Sstevel@tonic-gate ENTER_CRITICAL();
4127c478bd9Sstevel@tonic-gate ev->ev_link = SmFreeEventList;
4137c478bd9Sstevel@tonic-gate SmFreeEventList = ev;
4147c478bd9Sstevel@tonic-gate LEAVE_CRITICAL();
4157c478bd9Sstevel@tonic-gate if (pid != getpid())
4167c478bd9Sstevel@tonic-gate continue;
4177c478bd9Sstevel@tonic-gate if (SmEventQueue != NULL)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
4207c478bd9Sstevel@tonic-gate if (timercmp(&SmEventQueue->ev_time, &now, >))
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate timersub(&SmEventQueue->ev_time, &now,
4237c478bd9Sstevel@tonic-gate &clr.it_value);
4247c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
4257c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
4267c478bd9Sstevel@tonic-gate if (clr.it_value.tv_sec < 0)
4277c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
4287c478bd9Sstevel@tonic-gate if (clr.it_value.tv_sec == 0 &&
4297c478bd9Sstevel@tonic-gate clr.it_value.tv_usec == 0)
4307c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 1000;
4317c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate else
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
4367c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
4377c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 3;
4387c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 0;
4397c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
4427c478bd9Sstevel@tonic-gate if (SmEventQueue->ev_time > now)
4437c478bd9Sstevel@tonic-gate (void) alarm((unsigned) (SmEventQueue->ev_time
4447c478bd9Sstevel@tonic-gate - now));
4457c478bd9Sstevel@tonic-gate else
4467c478bd9Sstevel@tonic-gate (void) alarm(3);
4477c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate /* call ev_func */
4517c478bd9Sstevel@tonic-gate errno = save_errno;
4527c478bd9Sstevel@tonic-gate (*f)(arg);
4537c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
4547c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
4557c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
4567c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
4577c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 0;
4587c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
4597c478bd9Sstevel@tonic-gate gettimeofday(&now, NULL);
4607c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
4617c478bd9Sstevel@tonic-gate (void) alarm(0);
4627c478bd9Sstevel@tonic-gate now = time(NULL);
4637c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate if (SmEventQueue != NULL)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
4687c478bd9Sstevel@tonic-gate timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
4697c478bd9Sstevel@tonic-gate clr.it_interval.tv_sec = 0;
4707c478bd9Sstevel@tonic-gate clr.it_interval.tv_usec = 0;
4717c478bd9Sstevel@tonic-gate if (clr.it_value.tv_sec < 0)
4727c478bd9Sstevel@tonic-gate clr.it_value.tv_sec = 0;
4737c478bd9Sstevel@tonic-gate if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
4747c478bd9Sstevel@tonic-gate clr.it_value.tv_usec = 1000;
4757c478bd9Sstevel@tonic-gate (void) setitimer(ITIMER_REAL, &clr, NULL);
4767c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
4777c478bd9Sstevel@tonic-gate (void) alarm((unsigned) (SmEventQueue->ev_time - now));
4787c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate errno = save_errno;
4817c478bd9Sstevel@tonic-gate return SIGFUNC_RETURN;
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate ** SLEEP -- a version of sleep that works with this stuff
4857c478bd9Sstevel@tonic-gate **
4867c478bd9Sstevel@tonic-gate ** Because Unix sleep uses the alarm facility, I must reimplement
4877c478bd9Sstevel@tonic-gate ** it here.
4887c478bd9Sstevel@tonic-gate **
4897c478bd9Sstevel@tonic-gate ** Parameters:
4907c478bd9Sstevel@tonic-gate ** intvl -- time to sleep.
4917c478bd9Sstevel@tonic-gate **
4927c478bd9Sstevel@tonic-gate ** Returns:
4937c478bd9Sstevel@tonic-gate ** zero.
4947c478bd9Sstevel@tonic-gate **
4957c478bd9Sstevel@tonic-gate ** Side Effects:
4967c478bd9Sstevel@tonic-gate ** waits for intvl time. However, other events can
4977c478bd9Sstevel@tonic-gate ** be run during that interval.
4987c478bd9Sstevel@tonic-gate */
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate # if !HAVE_NANOSLEEP
5027c478bd9Sstevel@tonic-gate static void sm_endsleep __P((int));
5037c478bd9Sstevel@tonic-gate static bool volatile SmSleepDone;
5047c478bd9Sstevel@tonic-gate # endif /* !HAVE_NANOSLEEP */
5057c478bd9Sstevel@tonic-gate
5067c478bd9Sstevel@tonic-gate #ifndef SLEEP_T
5077c478bd9Sstevel@tonic-gate # define SLEEP_T unsigned int
5087c478bd9Sstevel@tonic-gate #endif /* ! SLEEP_T */
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate SLEEP_T
sleep(intvl)5117c478bd9Sstevel@tonic-gate sleep(intvl)
5127c478bd9Sstevel@tonic-gate unsigned int intvl;
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate #if HAVE_NANOSLEEP
5157c478bd9Sstevel@tonic-gate struct timespec rqtp;
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate if (intvl == 0)
5187c478bd9Sstevel@tonic-gate return (SLEEP_T) 0;
5197c478bd9Sstevel@tonic-gate rqtp.tv_sec = intvl;
5207c478bd9Sstevel@tonic-gate rqtp.tv_nsec = 0;
5217c478bd9Sstevel@tonic-gate nanosleep(&rqtp, NULL);
5227c478bd9Sstevel@tonic-gate return (SLEEP_T) 0;
5237c478bd9Sstevel@tonic-gate #else /* HAVE_NANOSLEEP */
5247c478bd9Sstevel@tonic-gate int was_held;
5257c478bd9Sstevel@tonic-gate SM_EVENT *ev;
5267c478bd9Sstevel@tonic-gate #if _FFR_SLEEP_USE_SELECT > 0
5277c478bd9Sstevel@tonic-gate int r;
5287c478bd9Sstevel@tonic-gate # if _FFR_SLEEP_USE_SELECT > 0
5297c478bd9Sstevel@tonic-gate struct timeval sm_io_to;
5307c478bd9Sstevel@tonic-gate # endif /* _FFR_SLEEP_USE_SELECT > 0 */
5317c478bd9Sstevel@tonic-gate #endif /* _FFR_SLEEP_USE_SELECT > 0 */
5327c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
5337c478bd9Sstevel@tonic-gate struct timeval now, begin, diff;
5347c478bd9Sstevel@tonic-gate # if _FFR_SLEEP_USE_SELECT > 0
5357c478bd9Sstevel@tonic-gate struct timeval slpv;
5367c478bd9Sstevel@tonic-gate # endif /* _FFR_SLEEP_USE_SELECT > 0 */
5377c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
5387c478bd9Sstevel@tonic-gate time_t begin, now;
5397c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
5407c478bd9Sstevel@tonic-gate
5417c478bd9Sstevel@tonic-gate if (intvl == 0)
5427c478bd9Sstevel@tonic-gate return (SLEEP_T) 0;
5437c478bd9Sstevel@tonic-gate #if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
5447c478bd9Sstevel@tonic-gate if (intvl > _FFR_MAX_SLEEP_TIME)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "sleep: interval=%u exceeds max value %d",
5477c478bd9Sstevel@tonic-gate intvl, _FFR_MAX_SLEEP_TIME);
5487c478bd9Sstevel@tonic-gate # if 0
5497c478bd9Sstevel@tonic-gate SM_ASSERT(intvl < (unsigned int) INT_MAX);
5507c478bd9Sstevel@tonic-gate # endif /* 0 */
5517c478bd9Sstevel@tonic-gate intvl = _FFR_MAX_SLEEP_TIME;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate #endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
5547c478bd9Sstevel@tonic-gate SmSleepDone = false;
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
5577c478bd9Sstevel@tonic-gate # if _FFR_SLEEP_USE_SELECT > 0
5587c478bd9Sstevel@tonic-gate slpv.tv_sec = intvl;
5597c478bd9Sstevel@tonic-gate slpv.tv_usec = 0;
5607c478bd9Sstevel@tonic-gate # endif /* _FFR_SLEEP_USE_SELECT > 0 */
5617c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL);
5627c478bd9Sstevel@tonic-gate begin = now;
5637c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
5647c478bd9Sstevel@tonic-gate now = begin = time(NULL);
5657c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate ev = sm_setevent((time_t) intvl, sm_endsleep, 0);
5687c478bd9Sstevel@tonic-gate if (ev == NULL)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate /* COMPLAIN */
5717c478bd9Sstevel@tonic-gate #if 0
5727c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "sleep: sm_setevent(%u) failed", intvl);
5737c478bd9Sstevel@tonic-gate #endif /* 0 */
5747c478bd9Sstevel@tonic-gate SmSleepDone = true;
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate was_held = sm_releasesignal(SIGALRM);
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate while (!SmSleepDone)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate #if SM_CONF_SETITIMER
5817c478bd9Sstevel@tonic-gate (void) gettimeofday(&now, NULL);
5827c478bd9Sstevel@tonic-gate timersub(&now, &begin, &diff);
5837c478bd9Sstevel@tonic-gate if (diff.tv_sec < 0 ||
5847c478bd9Sstevel@tonic-gate (diff.tv_sec == 0 && diff.tv_usec == 0))
5857c478bd9Sstevel@tonic-gate break;
5867c478bd9Sstevel@tonic-gate # if _FFR_SLEEP_USE_SELECT > 0
5877c478bd9Sstevel@tonic-gate timersub(&slpv, &diff, &sm_io_to);
5887c478bd9Sstevel@tonic-gate # endif /* _FFR_SLEEP_USE_SELECT > 0 */
5897c478bd9Sstevel@tonic-gate #else /* SM_CONF_SETITIMER */
5907c478bd9Sstevel@tonic-gate now = time(NULL);
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate ** Check whether time expired before signal is released.
5947c478bd9Sstevel@tonic-gate ** Due to the granularity of time() add 1 to be on the
5957c478bd9Sstevel@tonic-gate ** safe side.
5967c478bd9Sstevel@tonic-gate */
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate if (!(begin + (time_t) intvl + 1 > now))
5997c478bd9Sstevel@tonic-gate break;
6007c478bd9Sstevel@tonic-gate # if _FFR_SLEEP_USE_SELECT > 0
6017c478bd9Sstevel@tonic-gate sm_io_to.tv_sec = intvl - (now - begin);
6027c478bd9Sstevel@tonic-gate if (sm_io_to.tv_sec <= 0)
6037c478bd9Sstevel@tonic-gate sm_io_to.tv_sec = 1;
6047c478bd9Sstevel@tonic-gate sm_io_to.tv_usec = 0;
6057c478bd9Sstevel@tonic-gate # endif /* _FFR_SLEEP_USE_SELECT > 0 */
6067c478bd9Sstevel@tonic-gate #endif /* SM_CONF_SETITIMER */
6077c478bd9Sstevel@tonic-gate #if _FFR_SLEEP_USE_SELECT > 0
6087c478bd9Sstevel@tonic-gate if (intvl <= _FFR_SLEEP_USE_SELECT)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate r = select(0, NULL, NULL, NULL, &sm_io_to);
6117c478bd9Sstevel@tonic-gate if (r == 0)
6127c478bd9Sstevel@tonic-gate break;
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate else
6157c478bd9Sstevel@tonic-gate #endif /* _FFR_SLEEP_USE_SELECT > 0 */
6167c478bd9Sstevel@tonic-gate (void) pause();
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /* if out of the loop without the event being triggered remove it */
6207c478bd9Sstevel@tonic-gate if (!SmSleepDone)
6217c478bd9Sstevel@tonic-gate sm_clrevent(ev);
6227c478bd9Sstevel@tonic-gate if (was_held > 0)
6237c478bd9Sstevel@tonic-gate (void) sm_blocksignal(SIGALRM);
6247c478bd9Sstevel@tonic-gate return (SLEEP_T) 0;
6257c478bd9Sstevel@tonic-gate #endif /* HAVE_NANOSLEEP */
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate #if !HAVE_NANOSLEEP
6297c478bd9Sstevel@tonic-gate static void
sm_endsleep(ignore)6307c478bd9Sstevel@tonic-gate sm_endsleep(ignore)
6317c478bd9Sstevel@tonic-gate int ignore;
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate /*
6347c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
6357c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
6367c478bd9Sstevel@tonic-gate ** DOING.
6377c478bd9Sstevel@tonic-gate */
6387c478bd9Sstevel@tonic-gate
6397c478bd9Sstevel@tonic-gate SmSleepDone = true;
6407c478bd9Sstevel@tonic-gate }
6417c478bd9Sstevel@tonic-gate #endif /* !HAVE_NANOSLEEP */
6427c478bd9Sstevel@tonic-gate
643