Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Copyright (c) 1983 Eric P. Allman | |
6f14531a RG |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
15637ed4 RG |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #ifndef lint | |
d747e748 | 36 | static char sccsid[] = "@(#)clock.c 8.7 (Berkeley) 10/21/93"; |
15637ed4 RG |
37 | #endif /* not lint */ |
38 | ||
39 | # include "sendmail.h" | |
15637ed4 | 40 | |
6f14531a RG |
41 | # ifndef sigmask |
42 | # define sigmask(s) (1 << ((s) - 1)) | |
43 | # endif | |
44 | ||
15637ed4 RG |
45 | /* |
46 | ** SETEVENT -- set an event to happen at a specific time. | |
47 | ** | |
48 | ** Events are stored in a sorted list for fast processing. | |
49 | ** An event only applies to the process that set it. | |
50 | ** | |
51 | ** Parameters: | |
52 | ** intvl -- intvl until next event occurs. | |
53 | ** func -- function to call on event. | |
54 | ** arg -- argument to func on event. | |
55 | ** | |
56 | ** Returns: | |
57 | ** none. | |
58 | ** | |
59 | ** Side Effects: | |
60 | ** none. | |
61 | */ | |
62 | ||
63 | static void tick(); | |
64 | ||
65 | EVENT * | |
66 | setevent(intvl, func, arg) | |
67 | time_t intvl; | |
68 | int (*func)(); | |
69 | int arg; | |
70 | { | |
71 | register EVENT **evp; | |
72 | register EVENT *ev; | |
73 | auto time_t now; | |
74 | ||
75 | if (intvl <= 0) | |
76 | { | |
6f14531a | 77 | syserr("554 setevent: intvl=%ld\n", intvl); |
15637ed4 RG |
78 | return (NULL); |
79 | } | |
80 | ||
d747e748 | 81 | (void) setsignal(SIGALRM, SIG_IGN); |
15637ed4 RG |
82 | (void) time(&now); |
83 | ||
84 | /* search event queue for correct position */ | |
85 | for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link) | |
86 | { | |
87 | if (ev->ev_time >= now + intvl) | |
88 | break; | |
89 | } | |
90 | ||
91 | /* insert new event */ | |
92 | ev = (EVENT *) xalloc(sizeof *ev); | |
93 | ev->ev_time = now + intvl; | |
94 | ev->ev_func = func; | |
95 | ev->ev_arg = arg; | |
96 | ev->ev_pid = getpid(); | |
97 | ev->ev_link = *evp; | |
98 | *evp = ev; | |
99 | ||
100 | if (tTd(5, 5)) | |
101 | printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n", | |
102 | intvl, now + intvl, func, arg, ev); | |
103 | ||
104 | tick(); | |
105 | return (ev); | |
106 | } | |
107 | \f/* | |
108 | ** CLREVENT -- remove an event from the event queue. | |
109 | ** | |
110 | ** Parameters: | |
111 | ** ev -- pointer to event to remove. | |
112 | ** | |
113 | ** Returns: | |
114 | ** none. | |
115 | ** | |
116 | ** Side Effects: | |
117 | ** arranges for event ev to not happen. | |
118 | */ | |
119 | ||
120 | clrevent(ev) | |
121 | register EVENT *ev; | |
122 | { | |
123 | register EVENT **evp; | |
124 | ||
125 | if (tTd(5, 5)) | |
126 | printf("clrevent: ev=%x\n", ev); | |
127 | if (ev == NULL) | |
128 | return; | |
129 | ||
130 | /* find the parent event */ | |
d747e748 | 131 | (void) setsignal(SIGALRM, SIG_IGN); |
15637ed4 RG |
132 | for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link) |
133 | { | |
134 | if (*evp == ev) | |
135 | break; | |
136 | } | |
137 | ||
138 | /* now remove it */ | |
139 | if (*evp != NULL) | |
140 | { | |
141 | *evp = ev->ev_link; | |
142 | free((char *) ev); | |
143 | } | |
144 | ||
145 | /* restore clocks and pick up anything spare */ | |
146 | tick(); | |
147 | } | |
148 | \f/* | |
149 | ** TICK -- take a clock tick | |
150 | ** | |
151 | ** Called by the alarm clock. This routine runs events as needed. | |
152 | ** | |
153 | ** Parameters: | |
154 | ** none. | |
155 | ** | |
156 | ** Returns: | |
157 | ** none. | |
158 | ** | |
159 | ** Side Effects: | |
160 | ** calls the next function in EventQueue. | |
161 | */ | |
162 | ||
163 | static void | |
164 | tick() | |
165 | { | |
166 | register time_t now; | |
167 | register EVENT *ev; | |
168 | int mypid = getpid(); | |
d747e748 | 169 | int olderrno = errno; |
3a363396 NW |
170 | #ifdef SIG_UNBLOCK |
171 | sigset_t ss; | |
172 | #endif | |
15637ed4 | 173 | |
d747e748 | 174 | (void) setsignal(SIGALRM, SIG_IGN); |
15637ed4 RG |
175 | (void) alarm(0); |
176 | now = curtime(); | |
177 | ||
178 | if (tTd(5, 4)) | |
179 | printf("tick: now=%ld\n", now); | |
180 | ||
181 | while ((ev = EventQueue) != NULL && | |
182 | (ev->ev_time <= now || ev->ev_pid != mypid)) | |
183 | { | |
184 | int (*f)(); | |
185 | int arg; | |
186 | int pid; | |
187 | ||
188 | /* process the event on the top of the queue */ | |
189 | ev = EventQueue; | |
190 | EventQueue = EventQueue->ev_link; | |
191 | if (tTd(5, 6)) | |
192 | printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev, | |
193 | ev->ev_func, ev->ev_arg, ev->ev_pid); | |
194 | ||
195 | /* we must be careful in here because ev_func may not return */ | |
15637ed4 RG |
196 | f = ev->ev_func; |
197 | arg = ev->ev_arg; | |
198 | pid = ev->ev_pid; | |
199 | free((char *) ev); | |
200 | if (pid != getpid()) | |
201 | continue; | |
202 | if (EventQueue != NULL) | |
203 | { | |
204 | if (EventQueue->ev_time > now) | |
205 | (void) alarm((unsigned) (EventQueue->ev_time - now)); | |
206 | else | |
207 | (void) alarm(3); | |
208 | } | |
d747e748 JH |
209 | |
210 | /* restore signals so that we can take ticks while in ev_func */ | |
211 | (void) setsignal(SIGALRM, tick); | |
212 | #ifdef SIG_UNBLOCK | |
213 | /* unblock SIGALRM signal */ | |
214 | sigemptyset(&ss); | |
215 | sigaddset(&ss, SIGALRM); | |
216 | sigprocmask(SIG_UNBLOCK, &ss, NULL); | |
217 | #else | |
218 | #ifdef SIGVTALRM | |
219 | /* reset 4.2bsd signal mask to allow future alarms */ | |
220 | (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM)); | |
221 | #endif /* SIGVTALRM */ | |
222 | #endif /* SIG_UNBLOCK */ | |
223 | ||
224 | /* call ev_func */ | |
225 | errno = olderrno; | |
15637ed4 RG |
226 | (*f)(arg); |
227 | (void) alarm(0); | |
228 | now = curtime(); | |
229 | } | |
d747e748 | 230 | (void) setsignal(SIGALRM, tick); |
15637ed4 RG |
231 | if (EventQueue != NULL) |
232 | (void) alarm((unsigned) (EventQueue->ev_time - now)); | |
d747e748 | 233 | errno = olderrno; |
15637ed4 RG |
234 | } |
235 | \f/* | |
236 | ** SLEEP -- a version of sleep that works with this stuff | |
237 | ** | |
238 | ** Because sleep uses the alarm facility, I must reimplement | |
239 | ** it here. | |
240 | ** | |
241 | ** Parameters: | |
242 | ** intvl -- time to sleep. | |
243 | ** | |
244 | ** Returns: | |
245 | ** none. | |
246 | ** | |
247 | ** Side Effects: | |
248 | ** waits for intvl time. However, other events can | |
249 | ** be run during that interval. | |
250 | */ | |
251 | ||
252 | static bool SleepDone; | |
d747e748 | 253 | static int endsleep(); |
15637ed4 | 254 | |
d747e748 JH |
255 | #ifndef SLEEP_T |
256 | # define SLEEP_T unsigned int | |
257 | #endif | |
258 | ||
259 | SLEEP_T | |
15637ed4 RG |
260 | sleep(intvl) |
261 | unsigned int intvl; | |
262 | { | |
15637ed4 RG |
263 | if (intvl == 0) |
264 | return; | |
265 | SleepDone = FALSE; | |
266 | (void) setevent((time_t) intvl, endsleep, 0); | |
267 | while (!SleepDone) | |
268 | pause(); | |
269 | } | |
270 | ||
271 | static | |
272 | endsleep() | |
273 | { | |
274 | SleepDone = TRUE; | |
275 | } |