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