1 # include "sendmail.h"
2 
3 SCCSID(@(#)clock.c	3.7		08/25/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_link = *evp;
54 	*evp = ev;
55 
56 	/* reschedule next clock tick if appropriate */
57 	if (ev == EventQueue)
58 	{
59 		/* we have a new event */
60 		(void) signal(SIGALRM, tick);
61 		(void) alarm(intvl);
62 	}
63 
64 # ifdef DEBUG
65 	if (tTd(5, 2))
66 		printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
67 			intvl, now + intvl, func, arg, ev);
68 # endif DEBUG
69 
70 	return (ev);
71 }
72 /*
73 **  CLREVENT -- remove an event from the event queue.
74 **
75 **	Parameters:
76 **		ev -- pointer to event to remove.
77 **
78 **	Returns:
79 **		none.
80 **
81 **	Side Effects:
82 **		arranges for event ev to not happen.
83 */
84 
85 clrevent(ev)
86 	register EVENT *ev;
87 {
88 	register EVENT **evp;
89 
90 # ifdef DEBUG
91 	if (tTd(5, 2))
92 		printf("clrevent: ev=%x\n", ev);
93 # endif DEBUG
94 	if (ev == NULL)
95 		return;
96 
97 	/* find the parent event */
98 	signal(SIGALRM, SIG_IGN);
99 	for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
100 	{
101 		if (*evp == ev)
102 			break;
103 	}
104 
105 	/* now remove it */
106 	*evp = ev->ev_link;
107 	free(ev);
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 	signal(SIGALRM, tick);
133 	now = curtime();
134 
135 # ifdef DEBUG
136 	if (tTd(5, 1))
137 		printf("tick: now=%ld\n", now);
138 # endif DEBUG
139 
140 	while (EventQueue != NULL && EventQueue->ev_time <= now)
141 	{
142 		int (*f)(), a;
143 
144 		/* process the event on the top of the queue */
145 		ev = EventQueue;
146 		EventQueue = EventQueue->ev_link;
147 # ifdef DEBUG
148 		if (tTd(5, 3))
149 			printf("tick: ev=%x, func=%x, arg=%d\n", ev,
150 				ev->ev_func, ev->ev_arg);
151 # endif DEBUG
152 
153 		/* we must be careful in here because ev_func may not return */
154 		f = ev->ev_func;
155 		a = ev->ev_arg;
156 		free(ev);
157 		if (EventQueue != NULL)
158 		{
159 			if (EventQueue->ev_time > now)
160 				(void) alarm(EventQueue->ev_time - now);
161 			else
162 				(void) alarm(3);
163 		}
164 		(*f)(a);
165 		(void) alarm(0);
166 		now = curtime();
167 	}
168 	if (EventQueue != NULL)
169 		(void) alarm(EventQueue->ev_time - now);
170 }
171 /*
172 **  SLEEP -- a version of sleep that works with this stuff
173 **
174 **	Because sleep uses the alarm facility, I must reimplement
175 **	it here.
176 **
177 **	Parameters:
178 **		intvl -- time to sleep.
179 **
180 **	Returns:
181 **		none.
182 **
183 **	Side Effects:
184 **		waits for intvl time.  However, other events can
185 **		be run during that interval.
186 */
187 
188 static bool	SleepDone;
189 
190 sleep(intvl)
191 	int intvl;
192 {
193 	extern endsleep();
194 
195 	if (intvl == 0)
196 		return;
197 	SleepDone = FALSE;
198 	setevent(intvl, endsleep, 0);
199 	while (!SleepDone)
200 		pause();
201 }
202 
203 static
204 endsleep()
205 {
206 	SleepDone = TRUE;
207 }
208