1 /* 2 * Copyright (c) 1983, 1995 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.11 (Berkeley) 04/21/95"; 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 __P((int)); 38 39 EVENT * 40 setevent(intvl, func, arg) 41 time_t intvl; 42 void (*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) setsignal(SIGALRM, SIG_IGN); 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(0); 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 void 95 clrevent(ev) 96 register EVENT *ev; 97 { 98 register EVENT **evp; 99 100 if (tTd(5, 5)) 101 printf("clrevent: ev=%x\n", ev); 102 if (ev == NULL) 103 return; 104 105 /* find the parent event */ 106 (void) setsignal(SIGALRM, SIG_IGN); 107 for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 108 { 109 if (*evp == ev) 110 break; 111 } 112 113 /* now remove it */ 114 if (*evp != NULL) 115 { 116 *evp = ev->ev_link; 117 free((char *) ev); 118 } 119 120 /* restore clocks and pick up anything spare */ 121 tick(0); 122 } 123 /* 124 ** TICK -- take a clock tick 125 ** 126 ** Called by the alarm clock. This routine runs events as needed. 127 ** 128 ** Parameters: 129 ** One that is ignored; for compatibility with signal handlers. 130 ** 131 ** Returns: 132 ** none. 133 ** 134 ** Side Effects: 135 ** calls the next function in EventQueue. 136 */ 137 138 static void 139 tick(arg) 140 int arg; 141 { 142 register time_t now; 143 register EVENT *ev; 144 int mypid = getpid(); 145 int olderrno = errno; 146 #ifdef SIG_UNBLOCK 147 sigset_t ss; 148 #endif 149 150 (void) setsignal(SIGALRM, SIG_IGN); 151 (void) alarm(0); 152 now = curtime(); 153 154 if (tTd(5, 4)) 155 printf("tick: now=%ld\n", now); 156 157 while ((ev = EventQueue) != NULL && 158 (ev->ev_time <= now || ev->ev_pid != mypid)) 159 { 160 void (*f)(); 161 int arg; 162 int pid; 163 164 /* process the event on the top of the queue */ 165 ev = EventQueue; 166 EventQueue = EventQueue->ev_link; 167 if (tTd(5, 6)) 168 printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 169 ev->ev_func, ev->ev_arg, ev->ev_pid); 170 171 /* we must be careful in here because ev_func may not return */ 172 f = ev->ev_func; 173 arg = ev->ev_arg; 174 pid = ev->ev_pid; 175 free((char *) ev); 176 if (pid != getpid()) 177 continue; 178 if (EventQueue != NULL) 179 { 180 if (EventQueue->ev_time > now) 181 (void) alarm((unsigned) (EventQueue->ev_time - now)); 182 else 183 (void) alarm(3); 184 } 185 186 /* restore signals so that we can take ticks while in ev_func */ 187 (void) setsignal(SIGALRM, tick); 188 #ifdef SIG_UNBLOCK 189 /* unblock SIGALRM signal */ 190 sigemptyset(&ss); 191 sigaddset(&ss, SIGALRM); 192 sigprocmask(SIG_UNBLOCK, &ss, NULL); 193 #else 194 #if HASSIGSETMASK 195 /* reset 4.2bsd signal mask to allow future alarms */ 196 (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); 197 #endif /* HASSIGSETMASK */ 198 #endif /* SIG_UNBLOCK */ 199 200 /* call ev_func */ 201 errno = olderrno; 202 (*f)(arg); 203 (void) alarm(0); 204 now = curtime(); 205 } 206 (void) setsignal(SIGALRM, tick); 207 if (EventQueue != NULL) 208 (void) alarm((unsigned) (EventQueue->ev_time - now)); 209 errno = olderrno; 210 } 211 /* 212 ** SLEEP -- a version of sleep that works with this stuff 213 ** 214 ** Because sleep uses the alarm facility, I must reimplement 215 ** it here. 216 ** 217 ** Parameters: 218 ** intvl -- time to sleep. 219 ** 220 ** Returns: 221 ** none. 222 ** 223 ** Side Effects: 224 ** waits for intvl time. However, other events can 225 ** be run during that interval. 226 */ 227 228 static bool SleepDone; 229 static void endsleep(); 230 231 #ifndef SLEEP_T 232 # define SLEEP_T unsigned int 233 #endif 234 235 SLEEP_T 236 sleep(intvl) 237 unsigned int intvl; 238 { 239 if (intvl == 0) 240 return; 241 SleepDone = FALSE; 242 (void) setevent((time_t) intvl, endsleep, 0); 243 while (!SleepDone) 244 pause(); 245 } 246 247 static void 248 endsleep() 249 { 250 SleepDone = TRUE; 251 } 252