1 # include "sendmail.h" 2 # include <signal.h> 3 4 SCCSID(@(#)clock.c 4.2 03/11/84); 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 133 (void) signal(SIGALRM, SIG_IGN); 134 (void) alarm(0); 135 now = curtime(); 136 137 # ifdef DEBUG 138 if (tTd(5, 4)) 139 printf("tick: now=%ld\n", now); 140 # endif DEBUG 141 142 while ((ev = EventQueue) != NULL && 143 (ev->ev_time <= now || ev->ev_pid != getpid())) 144 { 145 int (*f)(); 146 int arg; 147 int pid; 148 149 /* process the event on the top of the queue */ 150 ev = EventQueue; 151 EventQueue = EventQueue->ev_link; 152 # ifdef DEBUG 153 if (tTd(5, 6)) 154 printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, 155 ev->ev_func, ev->ev_arg, ev->ev_pid); 156 # endif DEBUG 157 158 /* we must be careful in here because ev_func may not return */ 159 (void) signal(SIGALRM, tick); 160 f = ev->ev_func; 161 arg = ev->ev_arg; 162 pid = ev->ev_pid; 163 free((char *) ev); 164 if (pid != getpid()) 165 continue; 166 if (EventQueue != NULL) 167 { 168 if (EventQueue->ev_time > now) 169 (void) alarm((unsigned) (EventQueue->ev_time - now)); 170 else 171 (void) alarm(3); 172 } 173 (*f)(arg); 174 (void) alarm(0); 175 now = curtime(); 176 } 177 (void) signal(SIGALRM, tick); 178 if (EventQueue != NULL) 179 (void) alarm((unsigned) (EventQueue->ev_time - now)); 180 } 181 /* 182 ** SLEEP -- a version of sleep that works with this stuff 183 ** 184 ** Because sleep uses the alarm facility, I must reimplement 185 ** it here. 186 ** 187 ** Parameters: 188 ** intvl -- time to sleep. 189 ** 190 ** Returns: 191 ** none. 192 ** 193 ** Side Effects: 194 ** waits for intvl time. However, other events can 195 ** be run during that interval. 196 */ 197 198 static bool SleepDone; 199 200 sleep(intvl) 201 int intvl; 202 { 203 extern endsleep(); 204 205 if (intvl == 0) 206 return; 207 SleepDone = FALSE; 208 (void) setevent((time_t) intvl, endsleep, 0); 209 while (!SleepDone) 210 pause(); 211 } 212 213 static 214 endsleep() 215 { 216 SleepDone = TRUE; 217 } 218