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