1 # include "sendmail.h"
2 
3 SCCSID(@(#)clock.c	3.8		08/27/82);
4 
5 /*
6 **  SETEVENT -- set an event to happen at a specific time.
7 **
8 **	Parameters:
9 **		intvl -- intvl until next event occurs.
10 **		func -- function to call on event.
11 **		arg -- argument to func on event.
12 **
13 **	Returns:
14 **		none.
15 **
16 **	Side Effects:
17 **		none.
18 */
19 
20 EVENT *
21 setevent(intvl, func, arg)
22 	time_t intvl;
23 	int (*func)();
24 	int arg;
25 {
26 	register EVENT **evp;
27 	register EVENT *ev;
28 	auto time_t now;
29 	extern tick();
30 
31 # ifdef DEBUG
32 	if (intvl <= 0)
33 	{
34 		syserr("setevent: intvl=%ld\n", intvl);
35 		return;
36 	}
37 # endif DEBUG
38 
39 	(void) time(&now);
40 
41 	/* search event queue for correct position */
42 	for (evp = &EventQueue; (ev = *evp) != NULL; evp = &ev->ev_link)
43 	{
44 		if (ev->ev_time >= now + intvl)
45 			break;
46 	}
47 
48 	/* insert new event */
49 	ev = (EVENT *) xalloc(sizeof *ev);
50 	ev->ev_time = now + intvl;
51 	ev->ev_func = func;
52 	ev->ev_arg = arg;
53 	ev->ev_pid = getpid();
54 	ev->ev_link = *evp;
55 	*evp = ev;
56 
57 	/* reschedule next clock tick if appropriate */
58 	if (ev == EventQueue)
59 	{
60 		/* we have a new event */
61 		(void) signal(SIGALRM, tick);
62 		(void) alarm(intvl);
63 	}
64 
65 # ifdef DEBUG
66 	if (tTd(5, 2))
67 		printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
68 			intvl, now + intvl, func, arg, ev);
69 # endif DEBUG
70 
71 	return (ev);
72 }
73 /*
74 **  CLREVENT -- remove an event from the event queue.
75 **
76 **	Parameters:
77 **		ev -- pointer to event to remove.
78 **
79 **	Returns:
80 **		none.
81 **
82 **	Side Effects:
83 **		arranges for event ev to not happen.
84 */
85 
86 clrevent(ev)
87 	register EVENT *ev;
88 {
89 	register EVENT **evp;
90 
91 # ifdef DEBUG
92 	if (tTd(5, 2))
93 		printf("clrevent: ev=%x\n", ev);
94 # endif DEBUG
95 	if (ev == NULL)
96 		return;
97 
98 	/* find the parent event */
99 	signal(SIGALRM, SIG_IGN);
100 	for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
101 	{
102 		if (*evp == ev)
103 			break;
104 	}
105 
106 	/* now remove it */
107 	*evp = ev->ev_link;
108 	free(ev);
109 
110 	/* restore clocks and pick up anything spare */
111 	tick();
112 }
113 /*
114 **  TICK -- take a clock tick
115 **
116 **	Called by the alarm clock.  This routine runs events as needed.
117 **
118 **	Parameters:
119 **		none.
120 **
121 **	Returns:
122 **		none.
123 **
124 **	Side Effects:
125 **		calls the next function in EventQueue.
126 */
127 
128 tick()
129 {
130 	register time_t now;
131 	register EVENT *ev;
132 
133 	signal(SIGALRM, tick);
134 	now = curtime();
135 
136 # ifdef DEBUG
137 	if (tTd(5, 1))
138 		printf("tick: now=%ld\n", now);
139 # endif DEBUG
140 
141 	while (EventQueue != NULL && EventQueue->ev_time <= now)
142 	{
143 		int (*f)(), a;
144 		int pid;
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, 3))
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 		f = ev->ev_func;
157 		a = ev->ev_arg;
158 		pid = ev->ev_pid;
159 		free(ev);
160 		if (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 	if (EventQueue != NULL)
174 		(void) alarm(EventQueue->ev_time - now);
175 }
176 /*
177 **  SLEEP -- a version of sleep that works with this stuff
178 **
179 **	Because sleep uses the alarm facility, I must reimplement
180 **	it here.
181 **
182 **	Parameters:
183 **		intvl -- time to sleep.
184 **
185 **	Returns:
186 **		none.
187 **
188 **	Side Effects:
189 **		waits for intvl time.  However, other events can
190 **		be run during that interval.
191 */
192 
193 static bool	SleepDone;
194 
195 sleep(intvl)
196 	int intvl;
197 {
198 	extern endsleep();
199 
200 	if (intvl == 0)
201 		return;
202 	SleepDone = FALSE;
203 	setevent(intvl, endsleep, 0);
204 	while (!SleepDone)
205 		pause();
206 }
207 
208 static
209 endsleep()
210 {
211 	SleepDone = TRUE;
212 }
213