122696Sdist /* 234920Sbostic * Copyright (c) 1983 Eric P. Allman 362522Sbostic * Copyright (c) 1988, 1993 462522Sbostic * The Regents of the University of California. All rights reserved. 533728Sbostic * 642824Sbostic * %sccs.include.redist.c% 733728Sbostic */ 822696Sdist 922696Sdist #ifndef lint 10*65615Seric static char sccsid[] = "@(#)clock.c 8.8 (Berkeley) 01/12/94"; 1133728Sbostic #endif /* not lint */ 1222696Sdist 137358Seric # include "sendmail.h" 147358Seric 1560601Seric # ifndef sigmask 1660601Seric # define sigmask(s) (1 << ((s) - 1)) 1760601Seric # endif 1860601Seric 197358Seric /* 207684Seric ** SETEVENT -- set an event to happen at a specific time. 217684Seric ** 229373Seric ** Events are stored in a sorted list for fast processing. 239373Seric ** An event only applies to the process that set it. 249373Seric ** 257684Seric ** Parameters: 267684Seric ** intvl -- intvl until next event occurs. 277684Seric ** func -- function to call on event. 287684Seric ** arg -- argument to func on event. 297684Seric ** 307684Seric ** Returns: 317684Seric ** none. 327684Seric ** 337684Seric ** Side Effects: 347684Seric ** none. 357684Seric */ 367684Seric 37*65615Seric static void tick __P((int)); 3846928Sbostic 397684Seric EVENT * 407684Seric setevent(intvl, func, arg) 417684Seric time_t intvl; 427684Seric int (*func)(); 437684Seric int arg; 447684Seric { 457684Seric register EVENT **evp; 467684Seric register EVENT *ev; 477684Seric auto time_t now; 487684Seric 497757Seric if (intvl <= 0) 507757Seric { 5158151Seric syserr("554 setevent: intvl=%ld\n", intvl); 529346Seric return (NULL); 537757Seric } 547757Seric 5564674Seric (void) setsignal(SIGALRM, SIG_IGN); 567684Seric (void) time(&now); 577684Seric 587684Seric /* search event queue for correct position */ 597684Seric for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) 607684Seric { 617684Seric if (ev->ev_time >= now + intvl) 627684Seric break; 637684Seric } 647684Seric 657684Seric /* insert new event */ 667684Seric ev = (EVENT *) xalloc(sizeof *ev); 677684Seric ev->ev_time = now + intvl; 687684Seric ev->ev_func = func; 697684Seric ev->ev_arg = arg; 707931Seric ev->ev_pid = getpid(); 717684Seric ev->ev_link = *evp; 727684Seric *evp = ev; 737684Seric 748063Seric if (tTd(5, 5)) 757684Seric printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", 767684Seric intvl, now + intvl, func, arg, ev); 777684Seric 78*65615Seric tick(0); 797684Seric return (ev); 807684Seric } 817684Seric /* 827684Seric ** CLREVENT -- remove an event from the event queue. 837684Seric ** 847684Seric ** Parameters: 857684Seric ** ev -- pointer to event to remove. 867684Seric ** 877684Seric ** Returns: 887684Seric ** none. 897684Seric ** 907684Seric ** Side Effects: 917684Seric ** arranges for event ev to not happen. 927684Seric */ 937684Seric 947684Seric clrevent(ev) 957684Seric register EVENT *ev; 967684Seric { 977684Seric register EVENT **evp; 987684Seric 998063Seric if (tTd(5, 5)) 1007684Seric printf("clrevent: ev=%x\n", ev); 1017757Seric if (ev == NULL) 1027757Seric return; 1037684Seric 1047684Seric /* find the parent event */ 10564035Seric (void) setsignal(SIGALRM, SIG_IGN); 1067684Seric for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 1077684Seric { 1087684Seric if (*evp == ev) 1097684Seric break; 1107684Seric } 1117684Seric 1127684Seric /* now remove it */ 1137939Seric if (*evp != NULL) 1147939Seric { 1157939Seric *evp = ev->ev_link; 1169346Seric free((char *) ev); 1177939Seric } 1187862Seric 1197862Seric /* restore clocks and pick up anything spare */ 120*65615Seric tick(0); 1217684Seric } 1227684Seric /* 1237358Seric ** TICK -- take a clock tick 1247358Seric ** 1257684Seric ** Called by the alarm clock. This routine runs events as needed. 1267358Seric ** 1277358Seric ** Parameters: 128*65615Seric ** One that is ignored; for compatibility with signal handlers. 1297358Seric ** 1307358Seric ** Returns: 1317684Seric ** none. 1327358Seric ** 1337358Seric ** Side Effects: 1347684Seric ** calls the next function in EventQueue. 1357358Seric */ 1367358Seric 13746979Sbostic static void 138*65615Seric tick(arg) 139*65615Seric int arg; 1407358Seric { 1417889Seric register time_t now; 1427684Seric register EVENT *ev; 14324955Seric int mypid = getpid(); 14464738Seric int olderrno = errno; 14563787Seric #ifdef SIG_UNBLOCK 14663787Seric sigset_t ss; 14763787Seric #endif 1487684Seric 14964035Seric (void) setsignal(SIGALRM, SIG_IGN); 1509373Seric (void) alarm(0); 1517889Seric now = curtime(); 1527684Seric 1538063Seric if (tTd(5, 4)) 1547684Seric printf("tick: now=%ld\n", now); 1557684Seric 1568128Seric while ((ev = EventQueue) != NULL && 15724955Seric (ev->ev_time <= now || ev->ev_pid != mypid)) 1587684Seric { 15916141Seric int (*f)(); 16016141Seric int arg; 16116141Seric int pid; 1627862Seric 1637684Seric /* process the event on the top of the queue */ 1647684Seric ev = EventQueue; 1657684Seric EventQueue = EventQueue->ev_link; 1668063Seric if (tTd(5, 6)) 1677931Seric printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 1687931Seric ev->ev_func, ev->ev_arg, ev->ev_pid); 1697862Seric 1707862Seric /* we must be careful in here because ev_func may not return */ 17164674Seric f = ev->ev_func; 17264674Seric arg = ev->ev_arg; 17364674Seric pid = ev->ev_pid; 17464674Seric free((char *) ev); 17564674Seric if (pid != getpid()) 17664674Seric continue; 17764674Seric if (EventQueue != NULL) 17864674Seric { 17964674Seric if (EventQueue->ev_time > now) 18064674Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 18164674Seric else 18264674Seric (void) alarm(3); 18364674Seric } 18464674Seric 18564674Seric /* restore signals so that we can take ticks while in ev_func */ 18664035Seric (void) setsignal(SIGALRM, tick); 18763787Seric #ifdef SIG_UNBLOCK 18863787Seric /* unblock SIGALRM signal */ 18963787Seric sigemptyset(&ss); 19063787Seric sigaddset(&ss, SIGALRM); 19163787Seric sigprocmask(SIG_UNBLOCK, &ss, NULL); 19263787Seric #else 19320844Seric #ifdef SIGVTALRM 19420844Seric /* reset 4.2bsd signal mask to allow future alarms */ 19520844Seric (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 19656795Seric #endif /* SIGVTALRM */ 19763787Seric #endif /* SIG_UNBLOCK */ 19820844Seric 19964674Seric /* call ev_func */ 20064738Seric errno = olderrno; 20116141Seric (*f)(arg); 2027862Seric (void) alarm(0); 2037889Seric now = curtime(); 2047684Seric } 20564035Seric (void) setsignal(SIGALRM, tick); 2067889Seric if (EventQueue != NULL) 20712635Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 20864738Seric errno = olderrno; 2097358Seric } 2107690Seric /* 2117690Seric ** SLEEP -- a version of sleep that works with this stuff 2127690Seric ** 2137690Seric ** Because sleep uses the alarm facility, I must reimplement 2147690Seric ** it here. 2157690Seric ** 2167690Seric ** Parameters: 2177690Seric ** intvl -- time to sleep. 2187690Seric ** 2197690Seric ** Returns: 2207690Seric ** none. 2217690Seric ** 2227690Seric ** Side Effects: 2237690Seric ** waits for intvl time. However, other events can 2247690Seric ** be run during that interval. 2257690Seric */ 2267690Seric 2277690Seric static bool SleepDone; 22863937Seric static int endsleep(); 2297690Seric 23063968Seric #ifndef SLEEP_T 23163968Seric # define SLEEP_T unsigned int 23263968Seric #endif 23363968Seric 23463968Seric SLEEP_T 2357690Seric sleep(intvl) 23625615Seric unsigned int intvl; 2377690Seric { 2387757Seric if (intvl == 0) 2397757Seric return; 2407690Seric SleepDone = FALSE; 24112635Seric (void) setevent((time_t) intvl, endsleep, 0); 2427690Seric while (!SleepDone) 2437690Seric pause(); 2447690Seric } 2457690Seric 2467690Seric static 2477690Seric endsleep() 2487690Seric { 2497690Seric SleepDone = TRUE; 2507690Seric } 251