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