1 /*
2 * Copyright (c) 1983, 1995 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 #ifndef lint
10 static char sccsid[] = "@(#)clock.c 8.12 (Berkeley) 05/23/95";
11 #endif /* not lint */
12
13 # include "sendmail.h"
14
15 # ifndef sigmask
16 # define sigmask(s) (1 << ((s) - 1))
17 # endif
18
19 /*
20 ** SETEVENT -- set an event to happen at a specific time.
21 **
22 ** Events are stored in a sorted list for fast processing.
23 ** An event only applies to the process that set it.
24 **
25 ** Parameters:
26 ** intvl -- intvl until next event occurs.
27 ** func -- function to call on event.
28 ** arg -- argument to func on event.
29 **
30 ** Returns:
31 ** none.
32 **
33 ** Side Effects:
34 ** none.
35 */
36
37 static void tick __P((int));
38
39 EVENT *
setevent(intvl,func,arg)40 setevent(intvl, func, arg)
41 time_t intvl;
42 void (*func)();
43 int arg;
44 {
45 register EVENT **evp;
46 register EVENT *ev;
47 auto time_t now;
48
49 if (intvl <= 0)
50 {
51 syserr("554 setevent: intvl=%ld\n", intvl);
52 return (NULL);
53 }
54
55 (void) setsignal(SIGALRM, SIG_IGN);
56 (void) time(&now);
57
58 /* search event queue for correct position */
59 for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
60 {
61 if (ev->ev_time >= now + intvl)
62 break;
63 }
64
65 /* insert new event */
66 ev = (EVENT *) xalloc(sizeof *ev);
67 ev->ev_time = now + intvl;
68 ev->ev_func = func;
69 ev->ev_arg = arg;
70 ev->ev_pid = getpid();
71 ev->ev_link = *evp;
72 *evp = ev;
73
74 if (tTd(5, 5))
75 printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
76 intvl, now + intvl, func, arg, ev);
77
78 tick(0);
79 return (ev);
80 }
81 /*
82 ** CLREVENT -- remove an event from the event queue.
83 **
84 ** Parameters:
85 ** ev -- pointer to event to remove.
86 **
87 ** Returns:
88 ** none.
89 **
90 ** Side Effects:
91 ** arranges for event ev to not happen.
92 */
93
94 void
clrevent(ev)95 clrevent(ev)
96 register EVENT *ev;
97 {
98 register EVENT **evp;
99
100 if (tTd(5, 5))
101 printf("clrevent: ev=%x\n", ev);
102 if (ev == NULL)
103 return;
104
105 /* find the parent event */
106 (void) setsignal(SIGALRM, SIG_IGN);
107 for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
108 {
109 if (*evp == ev)
110 break;
111 }
112
113 /* now remove it */
114 if (*evp != NULL)
115 {
116 *evp = ev->ev_link;
117 free((char *) ev);
118 }
119
120 /* restore clocks and pick up anything spare */
121 tick(0);
122 }
123 /*
124 ** TICK -- take a clock tick
125 **
126 ** Called by the alarm clock. This routine runs events as needed.
127 **
128 ** Parameters:
129 ** One that is ignored; for compatibility with signal handlers.
130 **
131 ** Returns:
132 ** none.
133 **
134 ** Side Effects:
135 ** calls the next function in EventQueue.
136 */
137
138 static void
tick(arg)139 tick(arg)
140 int arg;
141 {
142 register time_t now;
143 register EVENT *ev;
144 int mypid = getpid();
145 int olderrno = errno;
146 #ifdef SIG_UNBLOCK
147 sigset_t ss;
148 #endif
149
150 (void) setsignal(SIGALRM, SIG_IGN);
151 (void) alarm(0);
152 now = curtime();
153
154 if (tTd(5, 4))
155 printf("tick: now=%ld\n", now);
156
157 while ((ev = EventQueue) != NULL &&
158 (ev->ev_time <= now || ev->ev_pid != mypid))
159 {
160 void (*f)();
161 int arg;
162 int pid;
163
164 /* process the event on the top of the queue */
165 ev = EventQueue;
166 EventQueue = EventQueue->ev_link;
167 if (tTd(5, 6))
168 printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev,
169 ev->ev_func, ev->ev_arg, ev->ev_pid);
170
171 /* we must be careful in here because ev_func may not return */
172 f = ev->ev_func;
173 arg = ev->ev_arg;
174 pid = ev->ev_pid;
175 free((char *) ev);
176 if (pid != getpid())
177 continue;
178 if (EventQueue != NULL)
179 {
180 if (EventQueue->ev_time > now)
181 (void) alarm((unsigned) (EventQueue->ev_time - now));
182 else
183 (void) alarm(3);
184 }
185
186 /* restore signals so that we can take ticks while in ev_func */
187 (void) setsignal(SIGALRM, tick);
188 #ifdef SIG_UNBLOCK
189 /* unblock SIGALRM signal */
190 sigemptyset(&ss);
191 sigaddset(&ss, SIGALRM);
192 sigprocmask(SIG_UNBLOCK, &ss, NULL);
193 #else
194 #if HASSIGSETMASK
195 /* reset 4.2bsd signal mask to allow future alarms */
196 (void) sigsetmask(sigblock(0) & ~sigmask(SIGALRM));
197 #endif /* HASSIGSETMASK */
198 #endif /* SIG_UNBLOCK */
199
200 /* call ev_func */
201 errno = olderrno;
202 (*f)(arg);
203 (void) alarm(0);
204 now = curtime();
205 }
206 (void) setsignal(SIGALRM, tick);
207 if (EventQueue != NULL)
208 (void) alarm((unsigned) (EventQueue->ev_time - now));
209 errno = olderrno;
210 }
211 /*
212 ** SLEEP -- a version of sleep that works with this stuff
213 **
214 ** Because sleep uses the alarm facility, I must reimplement
215 ** it here.
216 **
217 ** Parameters:
218 ** intvl -- time to sleep.
219 **
220 ** Returns:
221 ** none.
222 **
223 ** Side Effects:
224 ** waits for intvl time. However, other events can
225 ** be run during that interval.
226 */
227
228 static bool SleepDone;
229 static void endsleep();
230
231 #ifndef SLEEP_T
232 # define SLEEP_T unsigned int
233 #endif
234
235 SLEEP_T
sleep(intvl)236 sleep(intvl)
237 unsigned int intvl;
238 {
239 if (intvl == 0)
240 return (SLEEP_T) 0;
241 SleepDone = FALSE;
242 (void) setevent((time_t) intvl, endsleep, 0);
243 while (!SleepDone)
244 pause();
245 return (SLEEP_T) 0;
246 }
247
248 static void
endsleep()249 endsleep()
250 {
251 SleepDone = TRUE;
252 }
253