diff options
Diffstat (limited to 'contrib/sendmail/libsm/clock.c')
-rw-r--r-- | contrib/sendmail/libsm/clock.c | 640 |
1 files changed, 0 insertions, 640 deletions
diff --git a/contrib/sendmail/libsm/clock.c b/contrib/sendmail/libsm/clock.c deleted file mode 100644 index 1bdb4fd..0000000 --- a/contrib/sendmail/libsm/clock.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers. - * All rights reserved. - * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. - * - * By using this file, you agree to the terms and conditions set - * forth in the LICENSE file which can be found at the top level of - * the sendmail distribution. - * - */ - -#include <sm/gen.h> -SM_RCSID("@(#)$Id: clock.c,v 1.47 2005/06/14 23:07:20 ca Exp $") -#include <unistd.h> -#include <time.h> -#include <errno.h> -#if SM_CONF_SETITIMER -# include <sm/time.h> -#endif /* SM_CONF_SETITIMER */ -#include <sm/heap.h> -#include <sm/debug.h> -#include <sm/bitops.h> -#include <sm/clock.h> -#include "local.h" -#if _FFR_SLEEP_USE_SELECT > 0 -# include <sys/types.h> -#endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 -# include <syslog.h> -#endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */ - -#ifndef sigmask -# define sigmask(s) (1 << ((s) - 1)) -#endif /* ! sigmask */ - - -/* -** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds. -** -** Events are stored in a sorted list for fast processing. -** An event only applies to the process that set it. -** Source is #ifdef'd to work with older OS's that don't have setitimer() -** (that is, don't have a timer granularity less than 1 second). -** -** Parameters: -** intvl -- interval until next event occurs (milliseconds). -** func -- function to call on event. -** arg -- argument to func on event. -** -** Returns: -** On success returns the SM_EVENT entry created. -** On failure returns NULL. -** -** Side Effects: -** none. -*/ - -static SM_EVENT *volatile SmEventQueue; /* head of event queue */ -static SM_EVENT *volatile SmFreeEventList; /* list of free events */ - -SM_EVENT * -sm_seteventm(intvl, func, arg) - int intvl; - void (*func)__P((int)); - int arg; -{ - ENTER_CRITICAL(); - if (SmFreeEventList == NULL) - { - SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList); - SmFreeEventList->ev_link = NULL; - } - LEAVE_CRITICAL(); - - return sm_sigsafe_seteventm(intvl, func, arg); -} - -/* -** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD -** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE -** DOING. -*/ - -SM_EVENT * -sm_sigsafe_seteventm(intvl, func, arg) - int intvl; - void (*func)__P((int)); - int arg; -{ - register SM_EVENT **evp; - register SM_EVENT *ev; -#if SM_CONF_SETITIMER - auto struct timeval now, nowi, ival; - auto struct itimerval itime; -#else /* SM_CONF_SETITIMER */ - auto time_t now, nowi; -#endif /* SM_CONF_SETITIMER */ - int wasblocked; - - /* negative times are not allowed */ - if (intvl <= 0) - return NULL; - - wasblocked = sm_blocksignal(SIGALRM); -#if SM_CONF_SETITIMER - ival.tv_sec = intvl / 1000; - ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10; - (void) gettimeofday(&now, NULL); - nowi = now; - timeradd(&now, &ival, &nowi); -#else /* SM_CONF_SETITIMER */ - now = time(NULL); - nowi = now + (time_t)(intvl / 1000); -#endif /* SM_CONF_SETITIMER */ - - /* search event queue for correct position */ - for (evp = (SM_EVENT **) (&SmEventQueue); - (ev = *evp) != NULL; - evp = &ev->ev_link) - { -#if SM_CONF_SETITIMER - if (timercmp(&(ev->ev_time), &nowi, >=)) -#else /* SM_CONF_SETITIMER */ - if (ev->ev_time >= nowi) -#endif /* SM_CONF_SETITIMER */ - break; - } - - ENTER_CRITICAL(); - if (SmFreeEventList == NULL) - { - /* - ** This shouldn't happen. If called from sm_seteventm(), - ** we have just malloced a SmFreeEventList entry. If - ** called from a signal handler, it should have been - ** from an existing event which sm_tick() just added to - ** SmFreeEventList. - */ - - LEAVE_CRITICAL(); - if (wasblocked == 0) - (void) sm_releasesignal(SIGALRM); - return NULL; - } - else - { - ev = SmFreeEventList; - SmFreeEventList = ev->ev_link; - } - LEAVE_CRITICAL(); - - /* insert new event */ - ev->ev_time = nowi; - ev->ev_func = func; - ev->ev_arg = arg; - ev->ev_pid = getpid(); - ENTER_CRITICAL(); - ev->ev_link = *evp; - *evp = ev; - LEAVE_CRITICAL(); - - (void) sm_signal(SIGALRM, sm_tick); -# if SM_CONF_SETITIMER - timersub(&SmEventQueue->ev_time, &now, &itime.it_value); - itime.it_interval.tv_sec = 0; - itime.it_interval.tv_usec = 0; - if (itime.it_value.tv_sec < 0) - itime.it_value.tv_sec = 0; - if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0) - itime.it_value.tv_usec = 1000; - (void) setitimer(ITIMER_REAL, &itime, NULL); -# else /* SM_CONF_SETITIMER */ - intvl = SmEventQueue->ev_time - now; - (void) alarm((unsigned) (intvl < 1 ? 1 : intvl)); -# endif /* SM_CONF_SETITIMER */ - if (wasblocked == 0) - (void) sm_releasesignal(SIGALRM); - return ev; -} -/* -** SM_CLREVENT -- remove an event from the event queue. -** -** Parameters: -** ev -- pointer to event to remove. -** -** Returns: -** none. -** -** Side Effects: -** arranges for event ev to not happen. -*/ - -void -sm_clrevent(ev) - register SM_EVENT *ev; -{ - register SM_EVENT **evp; - int wasblocked; -# if SM_CONF_SETITIMER - struct itimerval clr; -# endif /* SM_CONF_SETITIMER */ - - if (ev == NULL) - return; - - /* find the parent event */ - wasblocked = sm_blocksignal(SIGALRM); - for (evp = (SM_EVENT **) (&SmEventQueue); - *evp != NULL; - evp = &(*evp)->ev_link) - { - if (*evp == ev) - break; - } - - /* now remove it */ - if (*evp != NULL) - { - ENTER_CRITICAL(); - *evp = ev->ev_link; - ev->ev_link = SmFreeEventList; - SmFreeEventList = ev; - LEAVE_CRITICAL(); - } - - /* restore clocks and pick up anything spare */ - if (wasblocked == 0) - (void) sm_releasesignal(SIGALRM); - if (SmEventQueue != NULL) - (void) kill(getpid(), SIGALRM); - else - { - /* nothing left in event queue, no need for an alarm */ -# if SM_CONF_SETITIMER - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - clr.it_value.tv_sec = 0; - clr.it_value.tv_usec = 0; - (void) setitimer(ITIMER_REAL, &clr, NULL); -# else /* SM_CONF_SETITIMER */ - (void) alarm(0); -# endif /* SM_CONF_SETITIMER */ - } -} -/* -** SM_CLEAR_EVENTS -- remove all events from the event queue. -** -** Parameters: -** none. -** -** Returns: -** none. -*/ - -void -sm_clear_events() -{ - register SM_EVENT *ev; -#if SM_CONF_SETITIMER - struct itimerval clr; -#endif /* SM_CONF_SETITIMER */ - int wasblocked; - - /* nothing will be left in event queue, no need for an alarm */ -#if SM_CONF_SETITIMER - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - clr.it_value.tv_sec = 0; - clr.it_value.tv_usec = 0; - (void) setitimer(ITIMER_REAL, &clr, NULL); -#else /* SM_CONF_SETITIMER */ - (void) alarm(0); -#endif /* SM_CONF_SETITIMER */ - - if (SmEventQueue == NULL) - return; - - wasblocked = sm_blocksignal(SIGALRM); - - /* find the end of the EventQueue */ - for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link) - continue; - - ENTER_CRITICAL(); - ev->ev_link = SmFreeEventList; - SmFreeEventList = SmEventQueue; - SmEventQueue = NULL; - LEAVE_CRITICAL(); - - /* restore clocks and pick up anything spare */ - if (wasblocked == 0) - (void) sm_releasesignal(SIGALRM); -} -/* -** SM_TICK -- take a clock tick -** -** Called by the alarm clock. This routine runs events as needed. -** Always called as a signal handler, so we assume that SIGALRM -** has been blocked. -** -** Parameters: -** One that is ignored; for compatibility with signal handlers. -** -** Returns: -** none. -** -** Side Effects: -** calls the next function in EventQueue. -** -** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD -** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE -** DOING. -*/ - -/* ARGSUSED */ -SIGFUNC_DECL -sm_tick(sig) - int sig; -{ - register SM_EVENT *ev; - pid_t mypid; - int save_errno = errno; -#if SM_CONF_SETITIMER - struct itimerval clr; - struct timeval now; -#else /* SM_CONF_SETITIMER */ - register time_t now; -#endif /* SM_CONF_SETITIMER */ - -#if SM_CONF_SETITIMER - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - clr.it_value.tv_sec = 0; - clr.it_value.tv_usec = 0; - (void) setitimer(ITIMER_REAL, &clr, NULL); - gettimeofday(&now, NULL); -#else /* SM_CONF_SETITIMER */ - (void) alarm(0); - now = time(NULL); -#endif /* SM_CONF_SETITIMER */ - - FIX_SYSV_SIGNAL(sig, sm_tick); - errno = save_errno; - CHECK_CRITICAL(sig); - - mypid = getpid(); - while (PendingSignal != 0) - { - int sigbit = 0; - int sig = 0; - - if (bitset(PEND_SIGHUP, PendingSignal)) - { - sigbit = PEND_SIGHUP; - sig = SIGHUP; - } - else if (bitset(PEND_SIGINT, PendingSignal)) - { - sigbit = PEND_SIGINT; - sig = SIGINT; - } - else if (bitset(PEND_SIGTERM, PendingSignal)) - { - sigbit = PEND_SIGTERM; - sig = SIGTERM; - } - else if (bitset(PEND_SIGUSR1, PendingSignal)) - { - sigbit = PEND_SIGUSR1; - sig = SIGUSR1; - } - else - { - /* If we get here, we are in trouble */ - abort(); - } - PendingSignal &= ~sigbit; - kill(mypid, sig); - } - -#if SM_CONF_SETITIMER - gettimeofday(&now, NULL); -#else /* SM_CONF_SETITIMER */ - now = time(NULL); -#endif /* SM_CONF_SETITIMER */ - while ((ev = SmEventQueue) != NULL && - (ev->ev_pid != mypid || -#if SM_CONF_SETITIMER - timercmp(&ev->ev_time, &now, <=) -#else /* SM_CONF_SETITIMER */ - ev->ev_time <= now -#endif /* SM_CONF_SETITIMER */ - )) - { - void (*f)__P((int)); - int arg; - pid_t pid; - - /* process the event on the top of the queue */ - ev = SmEventQueue; - SmEventQueue = SmEventQueue->ev_link; - - /* we must be careful in here because ev_func may not return */ - f = ev->ev_func; - arg = ev->ev_arg; - pid = ev->ev_pid; - ENTER_CRITICAL(); - ev->ev_link = SmFreeEventList; - SmFreeEventList = ev; - LEAVE_CRITICAL(); - if (pid != getpid()) - continue; - if (SmEventQueue != NULL) - { -#if SM_CONF_SETITIMER - if (timercmp(&SmEventQueue->ev_time, &now, >)) - { - timersub(&SmEventQueue->ev_time, &now, - &clr.it_value); - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - if (clr.it_value.tv_sec < 0) - clr.it_value.tv_sec = 0; - if (clr.it_value.tv_sec == 0 && - clr.it_value.tv_usec == 0) - clr.it_value.tv_usec = 1000; - (void) setitimer(ITIMER_REAL, &clr, NULL); - } - else - { - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - clr.it_value.tv_sec = 3; - clr.it_value.tv_usec = 0; - (void) setitimer(ITIMER_REAL, &clr, NULL); - } -#else /* SM_CONF_SETITIMER */ - if (SmEventQueue->ev_time > now) - (void) alarm((unsigned) (SmEventQueue->ev_time - - now)); - else - (void) alarm(3); -#endif /* SM_CONF_SETITIMER */ - } - - /* call ev_func */ - errno = save_errno; - (*f)(arg); -#if SM_CONF_SETITIMER - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - clr.it_value.tv_sec = 0; - clr.it_value.tv_usec = 0; - (void) setitimer(ITIMER_REAL, &clr, NULL); - gettimeofday(&now, NULL); -#else /* SM_CONF_SETITIMER */ - (void) alarm(0); - now = time(NULL); -#endif /* SM_CONF_SETITIMER */ - } - if (SmEventQueue != NULL) - { -#if SM_CONF_SETITIMER - timersub(&SmEventQueue->ev_time, &now, &clr.it_value); - clr.it_interval.tv_sec = 0; - clr.it_interval.tv_usec = 0; - if (clr.it_value.tv_sec < 0) - clr.it_value.tv_sec = 0; - if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0) - clr.it_value.tv_usec = 1000; - (void) setitimer(ITIMER_REAL, &clr, NULL); -#else /* SM_CONF_SETITIMER */ - (void) alarm((unsigned) (SmEventQueue->ev_time - now)); -#endif /* SM_CONF_SETITIMER */ - } - errno = save_errno; - return SIGFUNC_RETURN; -} -/* -** SLEEP -- a version of sleep that works with this stuff -** -** Because Unix sleep uses the alarm facility, I must reimplement -** it here. -** -** Parameters: -** intvl -- time to sleep. -** -** Returns: -** zero. -** -** Side Effects: -** waits for intvl time. However, other events can -** be run during that interval. -*/ - - -# if !HAVE_NANOSLEEP -static void sm_endsleep __P((int)); -static bool volatile SmSleepDone; -# endif /* !HAVE_NANOSLEEP */ - -#ifndef SLEEP_T -# define SLEEP_T unsigned int -#endif /* ! SLEEP_T */ - -SLEEP_T -sleep(intvl) - unsigned int intvl; -{ -#if HAVE_NANOSLEEP - struct timespec rqtp; - - if (intvl == 0) - return (SLEEP_T) 0; - rqtp.tv_sec = intvl; - rqtp.tv_nsec = 0; - nanosleep(&rqtp, NULL); - return (SLEEP_T) 0; -#else /* HAVE_NANOSLEEP */ - int was_held; - SM_EVENT *ev; -#if _FFR_SLEEP_USE_SELECT > 0 - int r; -# if _FFR_SLEEP_USE_SELECT > 0 - struct timeval sm_io_to; -# endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#if SM_CONF_SETITIMER - struct timeval now, begin, diff; -# if _FFR_SLEEP_USE_SELECT > 0 - struct timeval slpv; -# endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#else /* SM_CONF_SETITIMER */ - time_t begin, now; -#endif /* SM_CONF_SETITIMER */ - - if (intvl == 0) - return (SLEEP_T) 0; -#if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 - if (intvl > _FFR_MAX_SLEEP_TIME) - { - syslog(LOG_ERR, "sleep: interval=%u exceeds max value %d", - intvl, _FFR_MAX_SLEEP_TIME); -# if 0 - SM_ASSERT(intvl < (unsigned int) INT_MAX); -# endif /* 0 */ - intvl = _FFR_MAX_SLEEP_TIME; - } -#endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */ - SmSleepDone = false; - -#if SM_CONF_SETITIMER -# if _FFR_SLEEP_USE_SELECT > 0 - slpv.tv_sec = intvl; - slpv.tv_usec = 0; -# endif /* _FFR_SLEEP_USE_SELECT > 0 */ - (void) gettimeofday(&now, NULL); - begin = now; -#else /* SM_CONF_SETITIMER */ - now = begin = time(NULL); -#endif /* SM_CONF_SETITIMER */ - - ev = sm_setevent((time_t) intvl, sm_endsleep, 0); - if (ev == NULL) - { - /* COMPLAIN */ -#if 0 - syslog(LOG_ERR, "sleep: sm_setevent(%u) failed", intvl); -#endif /* 0 */ - SmSleepDone = true; - } - was_held = sm_releasesignal(SIGALRM); - - while (!SmSleepDone) - { -#if SM_CONF_SETITIMER - (void) gettimeofday(&now, NULL); - timersub(&now, &begin, &diff); - if (diff.tv_sec < 0 || - (diff.tv_sec == 0 && diff.tv_usec == 0)) - break; -# if _FFR_SLEEP_USE_SELECT > 0 - timersub(&slpv, &diff, &sm_io_to); -# endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#else /* SM_CONF_SETITIMER */ - now = time(NULL); - - /* - ** Check whether time expired before signal is released. - ** Due to the granularity of time() add 1 to be on the - ** safe side. - */ - - if (!(begin + (time_t) intvl + 1 > now)) - break; -# if _FFR_SLEEP_USE_SELECT > 0 - sm_io_to.tv_sec = intvl - (now - begin); - if (sm_io_to.tv_sec <= 0) - sm_io_to.tv_sec = 1; - sm_io_to.tv_usec = 0; -# endif /* _FFR_SLEEP_USE_SELECT > 0 */ -#endif /* SM_CONF_SETITIMER */ -#if _FFR_SLEEP_USE_SELECT > 0 - if (intvl <= _FFR_SLEEP_USE_SELECT) - { - r = select(0, NULL, NULL, NULL, &sm_io_to); - if (r == 0) - break; - } - else -#endif /* _FFR_SLEEP_USE_SELECT > 0 */ - (void) pause(); - } - - /* if out of the loop without the event being triggered remove it */ - if (!SmSleepDone) - sm_clrevent(ev); - if (was_held > 0) - (void) sm_blocksignal(SIGALRM); - return (SLEEP_T) 0; -#endif /* HAVE_NANOSLEEP */ -} - -#if !HAVE_NANOSLEEP -static void -sm_endsleep(ignore) - int ignore; -{ - /* - ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD - ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE - ** DOING. - */ - - SmSleepDone = true; -} -#endif /* !HAVE_NANOSLEEP */ - |