/*
* Copyright (c) 1998-2004 Proofpoint, 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 <unistd.h>
#include <time.h>
#include <errno.h>
#endif /* SM_CONF_SETITIMER */
#include "local.h"
#if _FFR_SLEEP_USE_SELECT > 0
#endif /* _FFR_SLEEP_USE_SELECT > 0 */
# include <syslog.h>
#endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
#ifndef sigmask
#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.
*/
SM_EVENT *
int intvl;
int arg;
{
if (SmFreeEventList == NULL)
{
}
}
/*
** 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 *
int intvl;
int arg;
{
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
int wasblocked;
/* negative times are not allowed */
if (intvl <= 0)
return NULL;
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
/* search event queue for correct position */
{
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
break;
}
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.
*/
if (wasblocked == 0)
(void) sm_releasesignal(SIGALRM);
return NULL;
}
else
{
}
/* insert new event */
# if SM_CONF_SETITIMER
# else /* SM_CONF_SETITIMER */
# 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
{
int wasblocked;
# if SM_CONF_SETITIMER
# endif /* SM_CONF_SETITIMER */
return;
/* find the parent event */
{
break;
}
/* now remove it */
{
}
/* restore clocks and pick up anything spare */
if (wasblocked == 0)
(void) sm_releasesignal(SIGALRM);
if (SmEventQueue != NULL)
else
{
/* nothing left in event queue, no need for an alarm */
# if SM_CONF_SETITIMER
# 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
{
#endif /* SM_CONF_SETITIMER */
int wasblocked;
/* nothing will be left in event queue, no need for an alarm */
#else /* SM_CONF_SETITIMER */
(void) alarm(0);
#endif /* SM_CONF_SETITIMER */
if (SmEventQueue == NULL)
return;
/* find the end of the EventQueue */
continue;
SmEventQueue = NULL;
/* 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 */
int sig;
{
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
#else /* SM_CONF_SETITIMER */
(void) alarm(0);
#endif /* SM_CONF_SETITIMER */
errno = save_errno;
while (PendingSignal != 0)
{
int sigbit = 0;
int sig = 0;
{
}
{
}
{
}
{
}
else
{
/* If we get here, we are in trouble */
abort();
}
PendingSignal &= ~sigbit;
}
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
))
{
void (*f)__P((int));
int arg;
/* process the event on the top of the queue */
ev = SmEventQueue;
/* we must be careful in here because ev_func may not return */
continue;
if (SmEventQueue != NULL)
{
{
}
else
{
}
#else /* SM_CONF_SETITIMER */
- now));
else
(void) alarm(3);
#endif /* SM_CONF_SETITIMER */
}
/* call ev_func */
errno = save_errno;
(*f)(arg);
#else /* SM_CONF_SETITIMER */
(void) alarm(0);
#endif /* SM_CONF_SETITIMER */
}
if (SmEventQueue != NULL)
{
#else /* SM_CONF_SETITIMER */
#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 */
unsigned int intvl;
{
#if HAVE_NANOSLEEP
if (intvl == 0)
return (SLEEP_T) 0;
return (SLEEP_T) 0;
#else /* HAVE_NANOSLEEP */
int was_held;
#if _FFR_SLEEP_USE_SELECT > 0
int r;
# if _FFR_SLEEP_USE_SELECT > 0
# endif /* _FFR_SLEEP_USE_SELECT > 0 */
#endif /* _FFR_SLEEP_USE_SELECT > 0 */
# if _FFR_SLEEP_USE_SELECT > 0
# endif /* _FFR_SLEEP_USE_SELECT > 0 */
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
if (intvl == 0)
return (SLEEP_T) 0;
if (intvl > _FFR_MAX_SLEEP_TIME)
{
# if 0
# endif /* 0 */
}
#endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
SmSleepDone = false;
# if _FFR_SLEEP_USE_SELECT > 0
# endif /* _FFR_SLEEP_USE_SELECT > 0 */
#else /* SM_CONF_SETITIMER */
#endif /* SM_CONF_SETITIMER */
{
/* COMPLAIN */
#if 0
#endif /* 0 */
SmSleepDone = true;
}
while (!SmSleepDone)
{
break;
# if _FFR_SLEEP_USE_SELECT > 0
# endif /* _FFR_SLEEP_USE_SELECT > 0 */
#else /* SM_CONF_SETITIMER */
/*
** Check whether time expired before signal is released.
** Due to the granularity of time() add 1 to be on the
** safe side.
*/
break;
# if _FFR_SLEEP_USE_SELECT > 0
# endif /* _FFR_SLEEP_USE_SELECT > 0 */
#endif /* SM_CONF_SETITIMER */
#if _FFR_SLEEP_USE_SELECT > 0
if (intvl <= _FFR_SLEEP_USE_SELECT)
{
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)
if (was_held > 0)
(void) sm_blocksignal(SIGALRM);
return (SLEEP_T) 0;
#endif /* HAVE_NANOSLEEP */
}
#if !HAVE_NANOSLEEP
static void
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 */