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