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