1 # include "sendmail.h" 2 # include <signal.h> 3 4 SCCSID(@(#)clock.c 4.3 12/05/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 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 f = ev->ev_func; 162 arg = ev->ev_arg; 163 pid = ev->ev_pid; 164 free((char *) ev); 165 if (pid != getpid()) 166 continue; 167 if (EventQueue != NULL) 168 { 169 if (EventQueue->ev_time > now) 170 (void) alarm((unsigned) (EventQueue->ev_time - now)); 171 else 172 (void) alarm(3); 173 } 174 (*f)(arg); 175 (void) alarm(0); 176 now = curtime(); 177 } 178 (void) signal(SIGALRM, tick); 179 if (EventQueue != NULL) 180 (void) alarm((unsigned) (EventQueue->ev_time - now)); 181 } 182 /* 183 ** SLEEP -- a version of sleep that works with this stuff 184 ** 185 ** Because sleep uses the alarm facility, I must reimplement 186 ** it here. 187 ** 188 ** Parameters: 189 ** intvl -- time to sleep. 190 ** 191 ** Returns: 192 ** none. 193 ** 194 ** Side Effects: 195 ** waits for intvl time. However, other events can 196 ** be run during that interval. 197 */ 198 199 static bool SleepDone; 200 201 sleep(intvl) 202 int intvl; 203 { 204 extern endsleep(); 205 206 if (intvl == 0) 207 return; 208 SleepDone = FALSE; 209 (void) setevent((time_t) intvl, endsleep, 0); 210 while (!SleepDone) 211 pause(); 212 } 213 214 static 215 endsleep() 216 { 217 SleepDone = TRUE; 218 } 219