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*68433Seric static char sccsid[] = "@(#)clock.c 8.10 (Berkeley) 02/23/95"; 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 3765615Seric static void tick __P((int)); 3846928Sbostic 397684Seric EVENT * 407684Seric setevent(intvl, func, arg) 417684Seric time_t intvl; 42*68433Seric void (*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 7865615Seric 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 94*68433Seric void 957684Seric clrevent(ev) 967684Seric register EVENT *ev; 977684Seric { 987684Seric register EVENT **evp; 997684Seric 1008063Seric if (tTd(5, 5)) 1017684Seric printf("clrevent: ev=%x\n", ev); 1027757Seric if (ev == NULL) 1037757Seric return; 1047684Seric 1057684Seric /* find the parent event */ 10664035Seric (void) setsignal(SIGALRM, SIG_IGN); 1077684Seric for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 1087684Seric { 1097684Seric if (*evp == ev) 1107684Seric break; 1117684Seric } 1127684Seric 1137684Seric /* now remove it */ 1147939Seric if (*evp != NULL) 1157939Seric { 1167939Seric *evp = ev->ev_link; 1179346Seric free((char *) ev); 1187939Seric } 1197862Seric 1207862Seric /* restore clocks and pick up anything spare */ 12165615Seric tick(0); 1227684Seric } 1237684Seric /* 1247358Seric ** TICK -- take a clock tick 1257358Seric ** 1267684Seric ** Called by the alarm clock. This routine runs events as needed. 1277358Seric ** 1287358Seric ** Parameters: 12965615Seric ** One that is ignored; for compatibility with signal handlers. 1307358Seric ** 1317358Seric ** Returns: 1327684Seric ** none. 1337358Seric ** 1347358Seric ** Side Effects: 1357684Seric ** calls the next function in EventQueue. 1367358Seric */ 1377358Seric 13846979Sbostic static void 13965615Seric tick(arg) 14065615Seric int arg; 1417358Seric { 1427889Seric register time_t now; 1437684Seric register EVENT *ev; 14424955Seric int mypid = getpid(); 14564738Seric int olderrno = errno; 14663787Seric #ifdef SIG_UNBLOCK 14763787Seric sigset_t ss; 14863787Seric #endif 1497684Seric 15064035Seric (void) setsignal(SIGALRM, SIG_IGN); 1519373Seric (void) alarm(0); 1527889Seric now = curtime(); 1537684Seric 1548063Seric if (tTd(5, 4)) 1557684Seric printf("tick: now=%ld\n", now); 1567684Seric 1578128Seric while ((ev = EventQueue) != NULL && 15824955Seric (ev->ev_time <= now || ev->ev_pid != mypid)) 1597684Seric { 160*68433Seric void (*f)(); 16116141Seric int arg; 16216141Seric int pid; 1637862Seric 1647684Seric /* process the event on the top of the queue */ 1657684Seric ev = EventQueue; 1667684Seric EventQueue = EventQueue->ev_link; 1678063Seric if (tTd(5, 6)) 1687931Seric printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 1697931Seric ev->ev_func, ev->ev_arg, ev->ev_pid); 1707862Seric 1717862Seric /* we must be careful in here because ev_func may not return */ 17264674Seric f = ev->ev_func; 17364674Seric arg = ev->ev_arg; 17464674Seric pid = ev->ev_pid; 17564674Seric free((char *) ev); 17664674Seric if (pid != getpid()) 17764674Seric continue; 17864674Seric if (EventQueue != NULL) 17964674Seric { 18064674Seric if (EventQueue->ev_time > now) 18164674Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 18264674Seric else 18364674Seric (void) alarm(3); 18464674Seric } 18564674Seric 18664674Seric /* restore signals so that we can take ticks while in ev_func */ 18764035Seric (void) setsignal(SIGALRM, tick); 18863787Seric #ifdef SIG_UNBLOCK 18963787Seric /* unblock SIGALRM signal */ 19063787Seric sigemptyset(&ss); 19163787Seric sigaddset(&ss, SIGALRM); 19263787Seric sigprocmask(SIG_UNBLOCK, &ss, NULL); 19363787Seric #else 19468099Seric #if HASSIGSETMASK 19520844Seric /* reset 4.2bsd signal mask to allow future alarms */ 19620844Seric (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 19768099Seric #endif /* HASSIGSETMASK */ 19863787Seric #endif /* SIG_UNBLOCK */ 19920844Seric 20064674Seric /* call ev_func */ 20164738Seric errno = olderrno; 20216141Seric (*f)(arg); 2037862Seric (void) alarm(0); 2047889Seric now = curtime(); 2057684Seric } 20664035Seric (void) setsignal(SIGALRM, tick); 2077889Seric if (EventQueue != NULL) 20812635Seric (void) alarm((unsigned) (EventQueue->ev_time - now)); 20964738Seric errno = olderrno; 2107358Seric } 2117690Seric /* 2127690Seric ** SLEEP -- a version of sleep that works with this stuff 2137690Seric ** 2147690Seric ** Because sleep uses the alarm facility, I must reimplement 2157690Seric ** it here. 2167690Seric ** 2177690Seric ** Parameters: 2187690Seric ** intvl -- time to sleep. 2197690Seric ** 2207690Seric ** Returns: 2217690Seric ** none. 2227690Seric ** 2237690Seric ** Side Effects: 2247690Seric ** waits for intvl time. However, other events can 2257690Seric ** be run during that interval. 2267690Seric */ 2277690Seric 2287690Seric static bool SleepDone; 229*68433Seric static void endsleep(); 2307690Seric 23163968Seric #ifndef SLEEP_T 23263968Seric # define SLEEP_T unsigned int 23363968Seric #endif 23463968Seric 23563968Seric SLEEP_T 2367690Seric sleep(intvl) 23725615Seric unsigned int intvl; 2387690Seric { 2397757Seric if (intvl == 0) 2407757Seric return; 2417690Seric SleepDone = FALSE; 24212635Seric (void) setevent((time_t) intvl, endsleep, 0); 2437690Seric while (!SleepDone) 2447690Seric pause(); 2457690Seric } 2467690Seric 247*68433Seric static void 2487690Seric endsleep() 2497690Seric { 2507690Seric SleepDone = TRUE; 2517690Seric } 252