1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)clock.c 8.3 (Berkeley) 07/19/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <signal.h> 15 16 # ifndef sigmask 17 # define sigmask(s) (1 << ((s) - 1)) 18 # endif 19 20 /* 21 ** SETEVENT -- set an event to happen at a specific time. 22 ** 23 ** Events are stored in a sorted list for fast processing. 24 ** An event only applies to the process that set it. 25 ** 26 ** Parameters: 27 ** intvl -- intvl until next event occurs. 28 ** func -- function to call on event. 29 ** arg -- argument to func on event. 30 ** 31 ** Returns: 32 ** none. 33 ** 34 ** Side Effects: 35 ** none. 36 */ 37 38 static void tick(); 39 40 EVENT * 41 setevent(intvl, func, arg) 42 time_t intvl; 43 int (*func)(); 44 int arg; 45 { 46 register EVENT **evp; 47 register EVENT *ev; 48 auto time_t now; 49 50 if (intvl <= 0) 51 { 52 syserr("554 setevent: intvl=%ld\n", intvl); 53 return (NULL); 54 } 55 56 (void) time(&now); 57 58 /* search event queue for correct position */ 59 for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) 60 { 61 if (ev->ev_time >= now + intvl) 62 break; 63 } 64 65 /* insert new event */ 66 ev = (EVENT *) xalloc(sizeof *ev); 67 ev->ev_time = now + intvl; 68 ev->ev_func = func; 69 ev->ev_arg = arg; 70 ev->ev_pid = getpid(); 71 ev->ev_link = *evp; 72 *evp = ev; 73 74 if (tTd(5, 5)) 75 printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", 76 intvl, now + intvl, func, arg, ev); 77 78 tick(); 79 return (ev); 80 } 81 /* 82 ** CLREVENT -- remove an event from the event queue. 83 ** 84 ** Parameters: 85 ** ev -- pointer to event to remove. 86 ** 87 ** Returns: 88 ** none. 89 ** 90 ** Side Effects: 91 ** arranges for event ev to not happen. 92 */ 93 94 clrevent(ev) 95 register EVENT *ev; 96 { 97 register EVENT **evp; 98 99 if (tTd(5, 5)) 100 printf("clrevent: ev=%x\n", ev); 101 if (ev == NULL) 102 return; 103 104 /* find the parent event */ 105 (void) signal(SIGALRM, SIG_IGN); 106 for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 107 { 108 if (*evp == ev) 109 break; 110 } 111 112 /* now remove it */ 113 if (*evp != NULL) 114 { 115 *evp = ev->ev_link; 116 free((char *) ev); 117 } 118 119 /* restore clocks and pick up anything spare */ 120 tick(); 121 } 122 /* 123 ** TICK -- take a clock tick 124 ** 125 ** Called by the alarm clock. This routine runs events as needed. 126 ** 127 ** Parameters: 128 ** none. 129 ** 130 ** Returns: 131 ** none. 132 ** 133 ** Side Effects: 134 ** calls the next function in EventQueue. 135 */ 136 137 static void 138 tick() 139 { 140 register time_t now; 141 register EVENT *ev; 142 int mypid = getpid(); 143 #ifdef SIG_UNBLOCK 144 sigset_t ss; 145 #endif 146 147 (void) signal(SIGALRM, SIG_IGN); 148 (void) alarm(0); 149 now = curtime(); 150 151 if (tTd(5, 4)) 152 printf("tick: now=%ld\n", now); 153 154 while ((ev = EventQueue) != NULL && 155 (ev->ev_time <= now || ev->ev_pid != mypid)) 156 { 157 int (*f)(); 158 int arg; 159 int pid; 160 161 /* process the event on the top of the queue */ 162 ev = EventQueue; 163 EventQueue = EventQueue->ev_link; 164 if (tTd(5, 6)) 165 printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 166 ev->ev_func, ev->ev_arg, ev->ev_pid); 167 168 /* we must be careful in here because ev_func may not return */ 169 (void) signal(SIGALRM, tick); 170 #ifdef SIG_UNBLOCK 171 /* unblock SIGALRM signal */ 172 sigemptyset(&ss); 173 sigaddset(&ss, SIGALRM); 174 sigprocmask(SIG_UNBLOCK, &ss, NULL); 175 #else 176 #ifdef SIGVTALRM 177 /* reset 4.2bsd signal mask to allow future alarms */ 178 (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 179 #endif /* SIGVTALRM */ 180 #endif /* SIG_UNBLOCK */ 181 182 f = ev->ev_func; 183 arg = ev->ev_arg; 184 pid = ev->ev_pid; 185 free((char *) ev); 186 if (pid != getpid()) 187 continue; 188 if (EventQueue != NULL) 189 { 190 if (EventQueue->ev_time > now) 191 (void) alarm((unsigned) (EventQueue->ev_time - now)); 192 else 193 (void) alarm(3); 194 } 195 (*f)(arg); 196 (void) alarm(0); 197 now = curtime(); 198 } 199 (void) signal(SIGALRM, tick); 200 if (EventQueue != NULL) 201 (void) alarm((unsigned) (EventQueue->ev_time - now)); 202 } 203 /* 204 ** SLEEP -- a version of sleep that works with this stuff 205 ** 206 ** Because sleep uses the alarm facility, I must reimplement 207 ** it here. 208 ** 209 ** Parameters: 210 ** intvl -- time to sleep. 211 ** 212 ** Returns: 213 ** none. 214 ** 215 ** Side Effects: 216 ** waits for intvl time. However, other events can 217 ** be run during that interval. 218 */ 219 220 static bool SleepDone; 221 static int endsleep(); 222 223 unsigned int 224 sleep(intvl) 225 unsigned int intvl; 226 { 227 if (intvl == 0) 228 return; 229 SleepDone = FALSE; 230 (void) setevent((time_t) intvl, endsleep, 0); 231 while (!SleepDone) 232 pause(); 233 } 234 235 static 236 endsleep() 237 { 238 SleepDone = TRUE; 239 } 240