xref: /original-bsd/usr.sbin/sendmail/src/clock.c (revision c0e889e7)
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