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