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 * 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 * 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 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 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 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 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 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