source: trunk/third/sendmail/src/clock.c @ 12554

Revision 12554, 5.2 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12553, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)clock.c     8.35 (Berkeley) 2/2/1999";
15#endif /* not lint */
16
17# include "sendmail.h"
18
19# ifndef sigmask
20#  define sigmask(s)    (1 << ((s) - 1))
21# endif
22
23/*
24**  SETEVENT -- set an event to happen at a specific time.
25**
26**      Events are stored in a sorted list for fast processing.
27**      An event only applies to the process that set it.
28**
29**      Parameters:
30**              intvl -- intvl until next event occurs.
31**              func -- function to call on event.
32**              arg -- argument to func on event.
33**
34**      Returns:
35**              none.
36**
37**      Side Effects:
38**              none.
39*/
40
41EVENT   *FreeEventList;         /* list of free events */
42
43static SIGFUNC_DECL     tick __P((int));
44
45EVENT *
46setevent(intvl, func, arg)
47        time_t intvl;
48        void (*func)();
49        int arg;
50{
51        register EVENT **evp;
52        register EVENT *ev;
53        auto time_t now;
54        int wasblocked;
55
56        if (intvl <= 0)
57        {
58                syserr("554 setevent: intvl=%ld\n", intvl);
59                return (NULL);
60        }
61
62        wasblocked = blocksignal(SIGALRM);
63        now = curtime();
64
65        /* search event queue for correct position */
66        for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
67        {
68                if (ev->ev_time >= now + intvl)
69                        break;
70        }
71
72        /* insert new event */
73        ev = FreeEventList;
74        if (ev == NULL)
75                ev = (EVENT *) xalloc(sizeof *ev);
76        else
77                FreeEventList = ev->ev_link;
78        ev->ev_time = now + intvl;
79        ev->ev_func = func;
80        ev->ev_arg = arg;
81        ev->ev_pid = getpid();
82        ev->ev_link = *evp;
83        *evp = ev;
84
85        if (tTd(5, 5))
86                printf("setevent: intvl=%ld, for=%ld, func=%lx, arg=%d, ev=%lx\n",
87                        (long) intvl, (long)(now + intvl), (u_long) func,
88                        arg, (u_long) ev);
89
90        setsignal(SIGALRM, tick);
91        intvl = EventQueue->ev_time - now;
92        (void) alarm((unsigned) intvl < 1 ? 1 : intvl);
93        if (wasblocked == 0)
94                (void) releasesignal(SIGALRM);
95        return (ev);
96}
97/*
98**  CLREVENT -- remove an event from the event queue.
99**
100**      Parameters:
101**              ev -- pointer to event to remove.
102**
103**      Returns:
104**              none.
105**
106**      Side Effects:
107**              arranges for event ev to not happen.
108*/
109
110void
111clrevent(ev)
112        register EVENT *ev;
113{
114        register EVENT **evp;
115        int wasblocked;
116
117        if (tTd(5, 5))
118                printf("clrevent: ev=%lx\n", (u_long) ev);
119        if (ev == NULL)
120                return;
121
122        /* find the parent event */
123        wasblocked = blocksignal(SIGALRM);
124        for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
125        {
126                if (*evp == ev)
127                        break;
128        }
129
130        /* now remove it */
131        if (*evp != NULL)
132        {
133                *evp = ev->ev_link;
134                ev->ev_link = FreeEventList;
135                FreeEventList = ev;
136        }
137
138        /* restore clocks and pick up anything spare */
139        if (wasblocked == 0)
140                releasesignal(SIGALRM);
141        if (EventQueue != NULL)
142                kill(getpid(), SIGALRM);
143}
144/*
145**  TICK -- take a clock tick
146**
147**      Called by the alarm clock.  This routine runs events as needed.
148**      Always called as a signal handler, so we assume that SIGALRM
149**      has been blocked.
150**
151**      Parameters:
152**              One that is ignored; for compatibility with signal handlers.
153**
154**      Returns:
155**              none.
156**
157**      Side Effects:
158**              calls the next function in EventQueue.
159*/
160
161/* ARGSUSED */
162static SIGFUNC_DECL
163tick(sig)
164        int sig;
165{
166        register time_t now;
167        register EVENT *ev;
168        int mypid = getpid();
169        int olderrno = errno;
170
171        (void) alarm(0);
172        now = curtime();
173
174        if (tTd(5, 4))
175                printf("tick: now=%ld\n", (long) now);
176
177        /* reset signal in case System V semantics */
178        (void) setsignal(SIGALRM, tick);
179        while ((ev = EventQueue) != NULL &&
180               (ev->ev_time <= now || ev->ev_pid != mypid))
181        {
182                void (*f)();
183                int arg;
184                int pid;
185
186                /* process the event on the top of the queue */
187                ev = EventQueue;
188                EventQueue = EventQueue->ev_link;
189                if (tTd(5, 6))
190                        printf("tick: ev=%lx, func=%lx, arg=%d, pid=%d\n",
191                                (u_long) ev, (u_long) ev->ev_func,
192                                ev->ev_arg, ev->ev_pid);
193
194                /* we must be careful in here because ev_func may not return */
195                f = ev->ev_func;
196                arg = ev->ev_arg;
197                pid = ev->ev_pid;
198                ev->ev_link = FreeEventList;
199                FreeEventList = 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                }
209
210                /* call ev_func */
211                errno = olderrno;
212                (*f)(arg);
213                (void) alarm(0);
214                now = curtime();
215        }
216        if (EventQueue != NULL)
217                (void) alarm((unsigned) (EventQueue->ev_time - now));
218        errno = olderrno;
219        return SIGFUNC_RETURN;
220}
221/*
222**  SLEEP -- a version of sleep that works with this stuff
223**
224**      Because sleep uses the alarm facility, I must reimplement
225**      it here.
226**
227**      Parameters:
228**              intvl -- time to sleep.
229**
230**      Returns:
231**              none.
232**
233**      Side Effects:
234**              waits for intvl time.  However, other events can
235**              be run during that interval.
236*/
237
238static bool     SleepDone;
239static void     endsleep __P((void));
240
241#ifndef SLEEP_T
242# define SLEEP_T        unsigned int
243#endif
244
245SLEEP_T
246sleep(intvl)
247        unsigned int intvl;
248{
249        int was_held;
250
251        if (intvl == 0)
252                return (SLEEP_T) 0;
253        SleepDone = FALSE;
254        (void) setevent((time_t) intvl, endsleep, 0);
255        was_held = releasesignal(SIGALRM);
256        while (!SleepDone)
257                pause();
258        if (was_held > 0)
259                blocksignal(SIGALRM);
260        return (SLEEP_T) 0;
261}
262
263static void
264endsleep()
265{
266        SleepDone = TRUE;
267}
Note: See TracBrowser for help on using the repository browser.