Deleted Added
full compact
clock.c (98121) clock.c (98841)
1/*
2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sm/gen.h>
1/*
2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5 * Copyright (c) 1988, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sm/gen.h>
15SM_RCSID("@(#)$Id: clock.c,v 1.35 2002/03/22 18:34:38 gshapiro Exp $")
15SM_RCSID("@(#)$Id: clock.c,v 1.35.2.1 2002/06/20 05:14:45 gshapiro Exp $")
16#include <unistd.h>
17#include <time.h>
18#include <errno.h>
19#if SM_CONF_SETITIMER
20# include <sys/time.h>
21#endif /* SM_CONF_SETITIMER */
22#include <sm/heap.h>
23#include <sm/debug.h>
24#include <sm/bitops.h>
25#include <sm/clock.h>
26#include "local.h"
27
28#ifndef sigmask
29# define sigmask(s) (1 << ((s) - 1))
30#endif /* ! sigmask */
31
32static void sm_endsleep __P((void));
33
34
35/*
36** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
37**
38** Events are stored in a sorted list for fast processing.
39** An event only applies to the process that set it.
40** Source is #ifdef'd to work with older OS's that don't have setitimer()
41** (that is, don't have a timer granularity less than 1 second).
42**
43** Parameters:
44** intvl -- interval until next event occurs (milliseconds).
45** func -- function to call on event.
46** arg -- argument to func on event.
47**
48** Returns:
49** On success returns the SM_EVENT entry created.
50** On failure returns NULL.
51**
52** Side Effects:
53** none.
54*/
55
56static SM_EVENT *volatile SmEventQueue; /* head of event queue */
57static SM_EVENT *volatile SmFreeEventList; /* list of free events */
58
59SM_EVENT *
60sm_seteventm(intvl, func, arg)
61 int intvl;
62 void (*func)();
63 int arg;
64{
65 ENTER_CRITICAL();
66 if (SmFreeEventList == NULL)
67 {
68 SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
69 SmFreeEventList->ev_link = NULL;
70 }
71 LEAVE_CRITICAL();
72
73 return sm_sigsafe_seteventm(intvl, func, arg);
74}
75
76/*
77** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
78** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
79** DOING.
80*/
81
82SM_EVENT *
83sm_sigsafe_seteventm(intvl, func, arg)
84 int intvl;
85 void (*func)();
86 int arg;
87{
88 register SM_EVENT **evp;
89 register SM_EVENT *ev;
90#if SM_CONF_SETITIMER
91 auto struct timeval now, nowi, ival;
92 auto struct itimerval itime;
93#else /* SM_CONF_SETITIMER */
94 auto time_t now, nowi;
95#endif /* SM_CONF_SETITIMER */
96 int wasblocked;
97
98 /* negative times are not allowed */
99 if (intvl <= 0)
100 return NULL;
101
102 wasblocked = sm_blocksignal(SIGALRM);
103#if SM_CONF_SETITIMER
104 ival.tv_sec = intvl / 1000;
105 ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
106 (void) gettimeofday(&now, NULL);
107 nowi = now;
108 timeradd(&now, &ival, &nowi);
109#else /* SM_CONF_SETITIMER */
110 now = time(NULL);
111 nowi = now + (time_t)(intvl / 1000);
112#endif /* SM_CONF_SETITIMER */
113
114 /* search event queue for correct position */
115 for (evp = (SM_EVENT **) (&SmEventQueue);
116 (ev = *evp) != NULL;
117 evp = &ev->ev_link)
118 {
119#if SM_CONF_SETITIMER
120 if (timercmp(&(ev->ev_time), &nowi, >=))
121#else /* SM_CONF_SETITIMER */
122 if (ev->ev_time >= nowi)
123#endif /* SM_CONF_SETITIMER */
124 break;
125 }
126
127 ENTER_CRITICAL();
128 if (SmFreeEventList == NULL)
129 {
130 /*
131 ** This shouldn't happen. If called from sm_seteventm(),
132 ** we have just malloced a SmFreeEventList entry. If
133 ** called from a signal handler, it should have been
134 ** from an existing event which sm_tick() just added to
135 ** SmFreeEventList.
136 */
137
138 LEAVE_CRITICAL();
139 return NULL;
140 }
141 else
142 {
143 ev = SmFreeEventList;
144 SmFreeEventList = ev->ev_link;
145 }
146 LEAVE_CRITICAL();
147
148 /* insert new event */
149 ev->ev_time = nowi;
150 ev->ev_func = func;
151 ev->ev_arg = arg;
152 ev->ev_pid = getpid();
153 ENTER_CRITICAL();
154 ev->ev_link = *evp;
155 *evp = ev;
156 LEAVE_CRITICAL();
157
158 (void) sm_signal(SIGALRM, sm_tick);
159# if SM_CONF_SETITIMER
160 timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
161 itime.it_interval.tv_sec = 0;
162 itime.it_interval.tv_usec = 0;
163 if (itime.it_value.tv_sec < 0)
164 itime.it_value.tv_sec = 0;
165 if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
166 itime.it_value.tv_usec = 1000;
167 (void) setitimer(ITIMER_REAL, &itime, NULL);
168# else /* SM_CONF_SETITIMER */
169 intvl = SmEventQueue->ev_time - now;
170 (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
171# endif /* SM_CONF_SETITIMER */
172 if (wasblocked == 0)
173 (void) sm_releasesignal(SIGALRM);
174 return ev;
175}
176/*
177** SM_CLREVENT -- remove an event from the event queue.
178**
179** Parameters:
180** ev -- pointer to event to remove.
181**
182** Returns:
183** none.
184**
185** Side Effects:
186** arranges for event ev to not happen.
187*/
188
189void
190sm_clrevent(ev)
191 register SM_EVENT *ev;
192{
193 register SM_EVENT **evp;
194 int wasblocked;
195# if SM_CONF_SETITIMER
196 struct itimerval clr;
197# endif /* SM_CONF_SETITIMER */
198
199 if (ev == NULL)
200 return;
201
202 /* find the parent event */
203 wasblocked = sm_blocksignal(SIGALRM);
204 for (evp = (SM_EVENT **) (&SmEventQueue);
205 *evp != NULL;
206 evp = &(*evp)->ev_link)
207 {
208 if (*evp == ev)
209 break;
210 }
211
212 /* now remove it */
213 if (*evp != NULL)
214 {
215 ENTER_CRITICAL();
216 *evp = ev->ev_link;
217 ev->ev_link = SmFreeEventList;
218 SmFreeEventList = ev;
219 LEAVE_CRITICAL();
220 }
221
222 /* restore clocks and pick up anything spare */
223 if (wasblocked == 0)
224 (void) sm_releasesignal(SIGALRM);
225 if (SmEventQueue != NULL)
226 (void) kill(getpid(), SIGALRM);
227 else
228 {
229 /* nothing left in event queue, no need for an alarm */
230# if SM_CONF_SETITIMER
231 clr.it_interval.tv_sec = 0;
232 clr.it_interval.tv_usec = 0;
233 clr.it_value.tv_sec = 0;
234 clr.it_value.tv_usec = 0;
235 (void) setitimer(ITIMER_REAL, &clr, NULL);
236# else /* SM_CONF_SETITIMER */
237 (void) alarm(0);
238# endif /* SM_CONF_SETITIMER */
239 }
240}
241/*
242** SM_CLEAR_EVENTS -- remove all events from the event queue.
243**
244** Parameters:
245** none.
246**
247** Returns:
248** none.
249*/
250
251void
252sm_clear_events()
253{
254 register SM_EVENT *ev;
255#if SM_CONF_SETITIMER
256 struct itimerval clr;
257#endif /* SM_CONF_SETITIMER */
258 int wasblocked;
259
16#include <unistd.h>
17#include <time.h>
18#include <errno.h>
19#if SM_CONF_SETITIMER
20# include <sys/time.h>
21#endif /* SM_CONF_SETITIMER */
22#include <sm/heap.h>
23#include <sm/debug.h>
24#include <sm/bitops.h>
25#include <sm/clock.h>
26#include "local.h"
27
28#ifndef sigmask
29# define sigmask(s) (1 << ((s) - 1))
30#endif /* ! sigmask */
31
32static void sm_endsleep __P((void));
33
34
35/*
36** SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
37**
38** Events are stored in a sorted list for fast processing.
39** An event only applies to the process that set it.
40** Source is #ifdef'd to work with older OS's that don't have setitimer()
41** (that is, don't have a timer granularity less than 1 second).
42**
43** Parameters:
44** intvl -- interval until next event occurs (milliseconds).
45** func -- function to call on event.
46** arg -- argument to func on event.
47**
48** Returns:
49** On success returns the SM_EVENT entry created.
50** On failure returns NULL.
51**
52** Side Effects:
53** none.
54*/
55
56static SM_EVENT *volatile SmEventQueue; /* head of event queue */
57static SM_EVENT *volatile SmFreeEventList; /* list of free events */
58
59SM_EVENT *
60sm_seteventm(intvl, func, arg)
61 int intvl;
62 void (*func)();
63 int arg;
64{
65 ENTER_CRITICAL();
66 if (SmFreeEventList == NULL)
67 {
68 SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
69 SmFreeEventList->ev_link = NULL;
70 }
71 LEAVE_CRITICAL();
72
73 return sm_sigsafe_seteventm(intvl, func, arg);
74}
75
76/*
77** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
78** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
79** DOING.
80*/
81
82SM_EVENT *
83sm_sigsafe_seteventm(intvl, func, arg)
84 int intvl;
85 void (*func)();
86 int arg;
87{
88 register SM_EVENT **evp;
89 register SM_EVENT *ev;
90#if SM_CONF_SETITIMER
91 auto struct timeval now, nowi, ival;
92 auto struct itimerval itime;
93#else /* SM_CONF_SETITIMER */
94 auto time_t now, nowi;
95#endif /* SM_CONF_SETITIMER */
96 int wasblocked;
97
98 /* negative times are not allowed */
99 if (intvl <= 0)
100 return NULL;
101
102 wasblocked = sm_blocksignal(SIGALRM);
103#if SM_CONF_SETITIMER
104 ival.tv_sec = intvl / 1000;
105 ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
106 (void) gettimeofday(&now, NULL);
107 nowi = now;
108 timeradd(&now, &ival, &nowi);
109#else /* SM_CONF_SETITIMER */
110 now = time(NULL);
111 nowi = now + (time_t)(intvl / 1000);
112#endif /* SM_CONF_SETITIMER */
113
114 /* search event queue for correct position */
115 for (evp = (SM_EVENT **) (&SmEventQueue);
116 (ev = *evp) != NULL;
117 evp = &ev->ev_link)
118 {
119#if SM_CONF_SETITIMER
120 if (timercmp(&(ev->ev_time), &nowi, >=))
121#else /* SM_CONF_SETITIMER */
122 if (ev->ev_time >= nowi)
123#endif /* SM_CONF_SETITIMER */
124 break;
125 }
126
127 ENTER_CRITICAL();
128 if (SmFreeEventList == NULL)
129 {
130 /*
131 ** This shouldn't happen. If called from sm_seteventm(),
132 ** we have just malloced a SmFreeEventList entry. If
133 ** called from a signal handler, it should have been
134 ** from an existing event which sm_tick() just added to
135 ** SmFreeEventList.
136 */
137
138 LEAVE_CRITICAL();
139 return NULL;
140 }
141 else
142 {
143 ev = SmFreeEventList;
144 SmFreeEventList = ev->ev_link;
145 }
146 LEAVE_CRITICAL();
147
148 /* insert new event */
149 ev->ev_time = nowi;
150 ev->ev_func = func;
151 ev->ev_arg = arg;
152 ev->ev_pid = getpid();
153 ENTER_CRITICAL();
154 ev->ev_link = *evp;
155 *evp = ev;
156 LEAVE_CRITICAL();
157
158 (void) sm_signal(SIGALRM, sm_tick);
159# if SM_CONF_SETITIMER
160 timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
161 itime.it_interval.tv_sec = 0;
162 itime.it_interval.tv_usec = 0;
163 if (itime.it_value.tv_sec < 0)
164 itime.it_value.tv_sec = 0;
165 if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
166 itime.it_value.tv_usec = 1000;
167 (void) setitimer(ITIMER_REAL, &itime, NULL);
168# else /* SM_CONF_SETITIMER */
169 intvl = SmEventQueue->ev_time - now;
170 (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
171# endif /* SM_CONF_SETITIMER */
172 if (wasblocked == 0)
173 (void) sm_releasesignal(SIGALRM);
174 return ev;
175}
176/*
177** SM_CLREVENT -- remove an event from the event queue.
178**
179** Parameters:
180** ev -- pointer to event to remove.
181**
182** Returns:
183** none.
184**
185** Side Effects:
186** arranges for event ev to not happen.
187*/
188
189void
190sm_clrevent(ev)
191 register SM_EVENT *ev;
192{
193 register SM_EVENT **evp;
194 int wasblocked;
195# if SM_CONF_SETITIMER
196 struct itimerval clr;
197# endif /* SM_CONF_SETITIMER */
198
199 if (ev == NULL)
200 return;
201
202 /* find the parent event */
203 wasblocked = sm_blocksignal(SIGALRM);
204 for (evp = (SM_EVENT **) (&SmEventQueue);
205 *evp != NULL;
206 evp = &(*evp)->ev_link)
207 {
208 if (*evp == ev)
209 break;
210 }
211
212 /* now remove it */
213 if (*evp != NULL)
214 {
215 ENTER_CRITICAL();
216 *evp = ev->ev_link;
217 ev->ev_link = SmFreeEventList;
218 SmFreeEventList = ev;
219 LEAVE_CRITICAL();
220 }
221
222 /* restore clocks and pick up anything spare */
223 if (wasblocked == 0)
224 (void) sm_releasesignal(SIGALRM);
225 if (SmEventQueue != NULL)
226 (void) kill(getpid(), SIGALRM);
227 else
228 {
229 /* nothing left in event queue, no need for an alarm */
230# if SM_CONF_SETITIMER
231 clr.it_interval.tv_sec = 0;
232 clr.it_interval.tv_usec = 0;
233 clr.it_value.tv_sec = 0;
234 clr.it_value.tv_usec = 0;
235 (void) setitimer(ITIMER_REAL, &clr, NULL);
236# else /* SM_CONF_SETITIMER */
237 (void) alarm(0);
238# endif /* SM_CONF_SETITIMER */
239 }
240}
241/*
242** SM_CLEAR_EVENTS -- remove all events from the event queue.
243**
244** Parameters:
245** none.
246**
247** Returns:
248** none.
249*/
250
251void
252sm_clear_events()
253{
254 register SM_EVENT *ev;
255#if SM_CONF_SETITIMER
256 struct itimerval clr;
257#endif /* SM_CONF_SETITIMER */
258 int wasblocked;
259
260 if (SmEventQueue == NULL)
261 return;
262
263 /* nothing will be left in event queue, no need for an alarm */
264#if SM_CONF_SETITIMER
265 clr.it_interval.tv_sec = 0;
266 clr.it_interval.tv_usec = 0;
267 clr.it_value.tv_sec = 0;
268 clr.it_value.tv_usec = 0;
269 (void) setitimer(ITIMER_REAL, &clr, NULL);
270#else /* SM_CONF_SETITIMER */
271 (void) alarm(0);
272#endif /* SM_CONF_SETITIMER */
260 /* nothing will be left in event queue, no need for an alarm */
261#if SM_CONF_SETITIMER
262 clr.it_interval.tv_sec = 0;
263 clr.it_interval.tv_usec = 0;
264 clr.it_value.tv_sec = 0;
265 clr.it_value.tv_usec = 0;
266 (void) setitimer(ITIMER_REAL, &clr, NULL);
267#else /* SM_CONF_SETITIMER */
268 (void) alarm(0);
269#endif /* SM_CONF_SETITIMER */
270
271 if (SmEventQueue == NULL)
272 return;
273
273 wasblocked = sm_blocksignal(SIGALRM);
274
275 /* find the end of the EventQueue */
276 for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
277 continue;
278
279 ENTER_CRITICAL();
280 ev->ev_link = SmFreeEventList;
281 SmFreeEventList = SmEventQueue;
282 SmEventQueue = NULL;
283 LEAVE_CRITICAL();
284
285 /* restore clocks and pick up anything spare */
286 if (wasblocked == 0)
287 (void) sm_releasesignal(SIGALRM);
288}
289/*
290** SM_TICK -- take a clock tick
291**
292** Called by the alarm clock. This routine runs events as needed.
293** Always called as a signal handler, so we assume that SIGALRM
294** has been blocked.
295**
296** Parameters:
297** One that is ignored; for compatibility with signal handlers.
298**
299** Returns:
300** none.
301**
302** Side Effects:
303** calls the next function in EventQueue.
304**
305** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
306** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
307** DOING.
308*/
309
310/* ARGSUSED */
311SIGFUNC_DECL
312sm_tick(sig)
313 int sig;
314{
315 register SM_EVENT *ev;
316 pid_t mypid;
317 int save_errno = errno;
318#if SM_CONF_SETITIMER
319 struct itimerval clr;
320 struct timeval now;
321#else /* SM_CONF_SETITIMER */
322 register time_t now;
323#endif /* SM_CONF_SETITIMER */
324
325#if SM_CONF_SETITIMER
326 clr.it_interval.tv_sec = 0;
327 clr.it_interval.tv_usec = 0;
328 clr.it_value.tv_sec = 0;
329 clr.it_value.tv_usec = 0;
330 (void) setitimer(ITIMER_REAL, &clr, NULL);
331 gettimeofday(&now, NULL);
332#else /* SM_CONF_SETITIMER */
333 (void) alarm(0);
334 now = time(NULL);
335#endif /* SM_CONF_SETITIMER */
336
337 FIX_SYSV_SIGNAL(sig, sm_tick);
338 errno = save_errno;
339 CHECK_CRITICAL(sig);
340
341 mypid = getpid();
342 while (PendingSignal != 0)
343 {
344 int sigbit = 0;
345 int sig = 0;
346
347 if (bitset(PEND_SIGHUP, PendingSignal))
348 {
349 sigbit = PEND_SIGHUP;
350 sig = SIGHUP;
351 }
352 else if (bitset(PEND_SIGINT, PendingSignal))
353 {
354 sigbit = PEND_SIGINT;
355 sig = SIGINT;
356 }
357 else if (bitset(PEND_SIGTERM, PendingSignal))
358 {
359 sigbit = PEND_SIGTERM;
360 sig = SIGTERM;
361 }
362 else if (bitset(PEND_SIGUSR1, PendingSignal))
363 {
364 sigbit = PEND_SIGUSR1;
365 sig = SIGUSR1;
366 }
367 else
368 {
369 /* If we get here, we are in trouble */
370 abort();
371 }
372 PendingSignal &= ~sigbit;
373 kill(mypid, sig);
374 }
375
376#if SM_CONF_SETITIMER
377 gettimeofday(&now, NULL);
378#else /* SM_CONF_SETITIMER */
379 now = time(NULL);
380#endif /* SM_CONF_SETITIMER */
381 while ((ev = SmEventQueue) != NULL &&
382 (ev->ev_pid != mypid ||
383#if SM_CONF_SETITIMER
384 timercmp(&ev->ev_time, &now, <=)
385#else /* SM_CONF_SETITIMER */
386 ev->ev_time <= now
387#endif /* SM_CONF_SETITIMER */
388 ))
389 {
390 void (*f)();
391 int arg;
392 pid_t pid;
393
394 /* process the event on the top of the queue */
395 ev = SmEventQueue;
396 SmEventQueue = SmEventQueue->ev_link;
397
398 /* we must be careful in here because ev_func may not return */
399 f = ev->ev_func;
400 arg = ev->ev_arg;
401 pid = ev->ev_pid;
402 ENTER_CRITICAL();
403 ev->ev_link = SmFreeEventList;
404 SmFreeEventList = ev;
405 LEAVE_CRITICAL();
406 if (pid != getpid())
407 continue;
408 if (SmEventQueue != NULL)
409 {
410#if SM_CONF_SETITIMER
411 if (timercmp(&SmEventQueue->ev_time, &now, >))
412 {
413 timersub(&SmEventQueue->ev_time, &now,
414 &clr.it_value);
415 clr.it_interval.tv_sec = 0;
416 clr.it_interval.tv_usec = 0;
417 if (clr.it_value.tv_sec < 0)
418 clr.it_value.tv_sec = 0;
419 if (clr.it_value.tv_sec == 0 &&
420 clr.it_value.tv_usec == 0)
421 clr.it_value.tv_usec = 1000;
422 (void) setitimer(ITIMER_REAL, &clr, NULL);
423 }
424 else
425 {
426 clr.it_interval.tv_sec = 0;
427 clr.it_interval.tv_usec = 0;
428 clr.it_value.tv_sec = 3;
429 clr.it_value.tv_usec = 0;
430 (void) setitimer(ITIMER_REAL, &clr, NULL);
431 }
432#else /* SM_CONF_SETITIMER */
433 if (SmEventQueue->ev_time > now)
434 (void) alarm((unsigned) (SmEventQueue->ev_time
435 - now));
436 else
437 (void) alarm(3);
438#endif /* SM_CONF_SETITIMER */
439 }
440
441 /* call ev_func */
442 errno = save_errno;
443 (*f)(arg);
444#if SM_CONF_SETITIMER
445 clr.it_interval.tv_sec = 0;
446 clr.it_interval.tv_usec = 0;
447 clr.it_value.tv_sec = 0;
448 clr.it_value.tv_usec = 0;
449 (void) setitimer(ITIMER_REAL, &clr, NULL);
450 gettimeofday(&now, NULL);
451#else /* SM_CONF_SETITIMER */
452 (void) alarm(0);
453 now = time(NULL);
454#endif /* SM_CONF_SETITIMER */
455 }
456 if (SmEventQueue != NULL)
457 {
458#if SM_CONF_SETITIMER
459 timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
460 clr.it_interval.tv_sec = 0;
461 clr.it_interval.tv_usec = 0;
462 if (clr.it_value.tv_sec < 0)
463 clr.it_value.tv_sec = 0;
464 if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
465 clr.it_value.tv_usec = 1000;
466 (void) setitimer(ITIMER_REAL, &clr, NULL);
467#else /* SM_CONF_SETITIMER */
468 (void) alarm((unsigned) (SmEventQueue->ev_time - now));
469#endif /* SM_CONF_SETITIMER */
470 }
471 errno = save_errno;
472 return SIGFUNC_RETURN;
473}
474/*
475** SLEEP -- a version of sleep that works with this stuff
476**
477** Because Unix sleep uses the alarm facility, I must reimplement
478** it here.
479**
480** Parameters:
481** intvl -- time to sleep.
482**
483** Returns:
484** zero.
485**
486** Side Effects:
487** waits for intvl time. However, other events can
488** be run during that interval.
489*/
490
491
492static bool volatile SmSleepDone;
493
494#ifndef SLEEP_T
495# define SLEEP_T unsigned int
496#endif /* ! SLEEP_T */
497
498SLEEP_T
499sleep(intvl)
500 unsigned int intvl;
501{
502 int was_held;
503
504 if (intvl == 0)
505 return (SLEEP_T) 0;
506 SmSleepDone = false;
507 (void) sm_setevent((time_t) intvl, sm_endsleep, 0);
508 was_held = sm_releasesignal(SIGALRM);
509 while (!SmSleepDone)
510 (void) pause();
511 if (was_held > 0)
512 (void) sm_blocksignal(SIGALRM);
513 return (SLEEP_T) 0;
514}
515
516static void
517sm_endsleep()
518{
519 /*
520 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
521 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
522 ** DOING.
523 */
524
525 SmSleepDone = true;
526}
527
274 wasblocked = sm_blocksignal(SIGALRM);
275
276 /* find the end of the EventQueue */
277 for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
278 continue;
279
280 ENTER_CRITICAL();
281 ev->ev_link = SmFreeEventList;
282 SmFreeEventList = SmEventQueue;
283 SmEventQueue = NULL;
284 LEAVE_CRITICAL();
285
286 /* restore clocks and pick up anything spare */
287 if (wasblocked == 0)
288 (void) sm_releasesignal(SIGALRM);
289}
290/*
291** SM_TICK -- take a clock tick
292**
293** Called by the alarm clock. This routine runs events as needed.
294** Always called as a signal handler, so we assume that SIGALRM
295** has been blocked.
296**
297** Parameters:
298** One that is ignored; for compatibility with signal handlers.
299**
300** Returns:
301** none.
302**
303** Side Effects:
304** calls the next function in EventQueue.
305**
306** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
307** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
308** DOING.
309*/
310
311/* ARGSUSED */
312SIGFUNC_DECL
313sm_tick(sig)
314 int sig;
315{
316 register SM_EVENT *ev;
317 pid_t mypid;
318 int save_errno = errno;
319#if SM_CONF_SETITIMER
320 struct itimerval clr;
321 struct timeval now;
322#else /* SM_CONF_SETITIMER */
323 register time_t now;
324#endif /* SM_CONF_SETITIMER */
325
326#if SM_CONF_SETITIMER
327 clr.it_interval.tv_sec = 0;
328 clr.it_interval.tv_usec = 0;
329 clr.it_value.tv_sec = 0;
330 clr.it_value.tv_usec = 0;
331 (void) setitimer(ITIMER_REAL, &clr, NULL);
332 gettimeofday(&now, NULL);
333#else /* SM_CONF_SETITIMER */
334 (void) alarm(0);
335 now = time(NULL);
336#endif /* SM_CONF_SETITIMER */
337
338 FIX_SYSV_SIGNAL(sig, sm_tick);
339 errno = save_errno;
340 CHECK_CRITICAL(sig);
341
342 mypid = getpid();
343 while (PendingSignal != 0)
344 {
345 int sigbit = 0;
346 int sig = 0;
347
348 if (bitset(PEND_SIGHUP, PendingSignal))
349 {
350 sigbit = PEND_SIGHUP;
351 sig = SIGHUP;
352 }
353 else if (bitset(PEND_SIGINT, PendingSignal))
354 {
355 sigbit = PEND_SIGINT;
356 sig = SIGINT;
357 }
358 else if (bitset(PEND_SIGTERM, PendingSignal))
359 {
360 sigbit = PEND_SIGTERM;
361 sig = SIGTERM;
362 }
363 else if (bitset(PEND_SIGUSR1, PendingSignal))
364 {
365 sigbit = PEND_SIGUSR1;
366 sig = SIGUSR1;
367 }
368 else
369 {
370 /* If we get here, we are in trouble */
371 abort();
372 }
373 PendingSignal &= ~sigbit;
374 kill(mypid, sig);
375 }
376
377#if SM_CONF_SETITIMER
378 gettimeofday(&now, NULL);
379#else /* SM_CONF_SETITIMER */
380 now = time(NULL);
381#endif /* SM_CONF_SETITIMER */
382 while ((ev = SmEventQueue) != NULL &&
383 (ev->ev_pid != mypid ||
384#if SM_CONF_SETITIMER
385 timercmp(&ev->ev_time, &now, <=)
386#else /* SM_CONF_SETITIMER */
387 ev->ev_time <= now
388#endif /* SM_CONF_SETITIMER */
389 ))
390 {
391 void (*f)();
392 int arg;
393 pid_t pid;
394
395 /* process the event on the top of the queue */
396 ev = SmEventQueue;
397 SmEventQueue = SmEventQueue->ev_link;
398
399 /* we must be careful in here because ev_func may not return */
400 f = ev->ev_func;
401 arg = ev->ev_arg;
402 pid = ev->ev_pid;
403 ENTER_CRITICAL();
404 ev->ev_link = SmFreeEventList;
405 SmFreeEventList = ev;
406 LEAVE_CRITICAL();
407 if (pid != getpid())
408 continue;
409 if (SmEventQueue != NULL)
410 {
411#if SM_CONF_SETITIMER
412 if (timercmp(&SmEventQueue->ev_time, &now, >))
413 {
414 timersub(&SmEventQueue->ev_time, &now,
415 &clr.it_value);
416 clr.it_interval.tv_sec = 0;
417 clr.it_interval.tv_usec = 0;
418 if (clr.it_value.tv_sec < 0)
419 clr.it_value.tv_sec = 0;
420 if (clr.it_value.tv_sec == 0 &&
421 clr.it_value.tv_usec == 0)
422 clr.it_value.tv_usec = 1000;
423 (void) setitimer(ITIMER_REAL, &clr, NULL);
424 }
425 else
426 {
427 clr.it_interval.tv_sec = 0;
428 clr.it_interval.tv_usec = 0;
429 clr.it_value.tv_sec = 3;
430 clr.it_value.tv_usec = 0;
431 (void) setitimer(ITIMER_REAL, &clr, NULL);
432 }
433#else /* SM_CONF_SETITIMER */
434 if (SmEventQueue->ev_time > now)
435 (void) alarm((unsigned) (SmEventQueue->ev_time
436 - now));
437 else
438 (void) alarm(3);
439#endif /* SM_CONF_SETITIMER */
440 }
441
442 /* call ev_func */
443 errno = save_errno;
444 (*f)(arg);
445#if SM_CONF_SETITIMER
446 clr.it_interval.tv_sec = 0;
447 clr.it_interval.tv_usec = 0;
448 clr.it_value.tv_sec = 0;
449 clr.it_value.tv_usec = 0;
450 (void) setitimer(ITIMER_REAL, &clr, NULL);
451 gettimeofday(&now, NULL);
452#else /* SM_CONF_SETITIMER */
453 (void) alarm(0);
454 now = time(NULL);
455#endif /* SM_CONF_SETITIMER */
456 }
457 if (SmEventQueue != NULL)
458 {
459#if SM_CONF_SETITIMER
460 timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
461 clr.it_interval.tv_sec = 0;
462 clr.it_interval.tv_usec = 0;
463 if (clr.it_value.tv_sec < 0)
464 clr.it_value.tv_sec = 0;
465 if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
466 clr.it_value.tv_usec = 1000;
467 (void) setitimer(ITIMER_REAL, &clr, NULL);
468#else /* SM_CONF_SETITIMER */
469 (void) alarm((unsigned) (SmEventQueue->ev_time - now));
470#endif /* SM_CONF_SETITIMER */
471 }
472 errno = save_errno;
473 return SIGFUNC_RETURN;
474}
475/*
476** SLEEP -- a version of sleep that works with this stuff
477**
478** Because Unix sleep uses the alarm facility, I must reimplement
479** it here.
480**
481** Parameters:
482** intvl -- time to sleep.
483**
484** Returns:
485** zero.
486**
487** Side Effects:
488** waits for intvl time. However, other events can
489** be run during that interval.
490*/
491
492
493static bool volatile SmSleepDone;
494
495#ifndef SLEEP_T
496# define SLEEP_T unsigned int
497#endif /* ! SLEEP_T */
498
499SLEEP_T
500sleep(intvl)
501 unsigned int intvl;
502{
503 int was_held;
504
505 if (intvl == 0)
506 return (SLEEP_T) 0;
507 SmSleepDone = false;
508 (void) sm_setevent((time_t) intvl, sm_endsleep, 0);
509 was_held = sm_releasesignal(SIGALRM);
510 while (!SmSleepDone)
511 (void) pause();
512 if (was_held > 0)
513 (void) sm_blocksignal(SIGALRM);
514 return (SLEEP_T) 0;
515}
516
517static void
518sm_endsleep()
519{
520 /*
521 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
522 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
523 ** DOING.
524 */
525
526 SmSleepDone = true;
527}
528