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