1 # include "sendmail.h"
2 
3 SCCSID(@(#)clock.c	3.11		09/08/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 # ifdef DEBUG
58 	if (tTd(5, 5))
59 		printf("setevent: intvl=%ld, for=%ld, func=%x, arg=%d, ev=%x\n",
60 			intvl, now + intvl, func, arg, ev);
61 # endif DEBUG
62 
63 	tick();
64 	return (ev);
65 }
66 /*
67 **  CLREVENT -- remove an event from the event queue.
68 **
69 **	Parameters:
70 **		ev -- pointer to event to remove.
71 **
72 **	Returns:
73 **		none.
74 **
75 **	Side Effects:
76 **		arranges for event ev to not happen.
77 */
78 
79 clrevent(ev)
80 	register EVENT *ev;
81 {
82 	register EVENT **evp;
83 
84 # ifdef DEBUG
85 	if (tTd(5, 5))
86 		printf("clrevent: ev=%x\n", ev);
87 # endif DEBUG
88 	if (ev == NULL)
89 		return;
90 
91 	/* find the parent event */
92 	signal(SIGALRM, SIG_IGN);
93 	for (evp = &EventQueue; *evp != NULL; evp = &(*evp)->ev_link)
94 	{
95 		if (*evp == ev)
96 			break;
97 	}
98 
99 	/* now remove it */
100 	if (*evp != NULL)
101 	{
102 		*evp = ev->ev_link;
103 		free(ev);
104 	}
105 
106 	/* restore clocks and pick up anything spare */
107 	tick();
108 }
109 /*
110 **  TICK -- take a clock tick
111 **
112 **	Called by the alarm clock.  This routine runs events as needed.
113 **
114 **	Parameters:
115 **		none.
116 **
117 **	Returns:
118 **		none.
119 **
120 **	Side Effects:
121 **		calls the next function in EventQueue.
122 */
123 
124 tick()
125 {
126 	register time_t now;
127 	register EVENT *ev;
128 
129 	signal(SIGALRM, tick);
130 	now = curtime();
131 
132 # ifdef DEBUG
133 	if (tTd(5, 4))
134 		printf("tick: now=%ld\n", now);
135 # endif DEBUG
136 
137 	while ((ev = EventQueue) != NULL &&
138 	       (ev->ev_time <= now || ev->ev_pid != getpid()))
139 	{
140 		int (*f)(), a;
141 
142 		/* process the event on the top of the queue */
143 		ev = EventQueue;
144 		EventQueue = EventQueue->ev_link;
145 # ifdef DEBUG
146 		if (tTd(5, 6))
147 			printf("tick: ev=%x, func=%x, arg=%d, pid=%d\n", ev,
148 				ev->ev_func, ev->ev_arg, ev->ev_pid);
149 # endif DEBUG
150 
151 		/* we must be careful in here because ev_func may not return */
152 		f = ev->ev_func;
153 		a = ev->ev_arg;
154 		free(ev);
155 		if (ev->ev_pid != getpid())
156 			continue;
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