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