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