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