1 # include "sendmail.h" 2 # include <signal.h> 3 4 SCCSID(@(#)clock.c 4.4 05/15/85); 5 6 /* 7 ** SETEVENT -- set an event to happen at a specific time. 8 ** 9 ** Events are stored in a sorted list for fast processing. 10 ** An event only applies to the process that set it. 11 ** 12 ** Parameters: 13 ** intvl -- intvl until next event occurs. 14 ** func -- function to call on event. 15 ** arg -- argument to func on event. 16 ** 17 ** Returns: 18 ** none. 19 ** 20 ** Side Effects: 21 ** none. 22 */ 23 24 EVENT * 25 setevent(intvl, func, arg) 26 time_t intvl; 27 int (*func)(); 28 int arg; 29 { 30 register EVENT **evp; 31 register EVENT *ev; 32 auto time_t now; 33 extern tick(); 34 35 # ifdef DEBUG 36 if (intvl <= 0) 37 { 38 syserr("setevent: intvl=%ld\n", intvl); 39 return (NULL); 40 } 41 # endif DEBUG 42 43 (void) time(&now); 44 45 /* search event queue for correct position */ 46 for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) 47 { 48 if (ev->ev_time >= now + intvl) 49 break; 50 } 51 52 /* insert new event */ 53 ev = (EVENT *) xalloc(sizeof *ev); 54 ev->ev_time = now + intvl; 55 ev->ev_func = func; 56 ev->ev_arg = arg; 57 ev->ev_pid = getpid(); 58 ev->ev_link = *evp; 59 *evp = ev; 60 61 # ifdef DEBUG 62 if (tTd(5, 5)) 63 printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", 64 intvl, now + intvl, func, arg, ev); 65 # endif DEBUG 66 67 tick(); 68 return (ev); 69 } 70 /* 71 ** CLREVENT -- remove an event from the event queue. 72 ** 73 ** Parameters: 74 ** ev -- pointer to event to remove. 75 ** 76 ** Returns: 77 ** none. 78 ** 79 ** Side Effects: 80 ** arranges for event ev to not happen. 81 */ 82 83 clrevent(ev) 84 register EVENT *ev; 85 { 86 register EVENT **evp; 87 88 # ifdef DEBUG 89 if (tTd(5, 5)) 90 printf("clrevent: ev=%x\n", ev); 91 # endif DEBUG 92 if (ev == NULL) 93 return; 94 95 /* find the parent event */ 96 (void) signal(SIGALRM, SIG_IGN); 97 for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) 98 { 99 if (*evp == ev) 100 break; 101 } 102 103 /* now remove it */ 104 if (*evp != NULL) 105 { 106 *evp = ev->ev_link; 107 free((char *) ev); 108 } 109 110 /* restore clocks and pick up anything spare */ 111 tick(); 112 } 113 /* 114 ** TICK -- take a clock tick 115 ** 116 ** Called by the alarm clock. This routine runs events as needed. 117 ** 118 ** Parameters: 119 ** none. 120 ** 121 ** Returns: 122 ** none. 123 ** 124 ** Side Effects: 125 ** calls the next function in EventQueue. 126 */ 127 128 tick() 129 { 130 register time_t now; 131 register EVENT *ev; 132 int pid = getpid(); 133 134 (void) signal(SIGALRM, SIG_IGN); 135 (void) alarm(0); 136 now = curtime(); 137 138 # ifdef DEBUG 139 if (tTd(5, 4)) 140 printf("tick: now=%ld\n", now); 141 # endif DEBUG 142 143 while ((ev = EventQueue) != NULL && 144 (ev->ev_time <= now || ev->ev_pid != pid)) 145 { 146 int (*f)(); 147 int arg; 148 int pid; 149 150 /* process the event on the top of the queue */ 151 ev = EventQueue; 152 EventQueue = EventQueue->ev_link; 153 # ifdef DEBUG 154 if (tTd(5, 6)) 155 printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 156 ev->ev_func, ev->ev_arg, ev->ev_pid); 157 # endif DEBUG 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 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