1 # include "sendmail.h"
2 
3 SCCSID(@(#)clock.c	3.9		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 # ifdef DEBUG
58 	if (tTd(5, 2))
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, 2))
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, 1))
134 		printf("tick: now=%ld\n", now);
135 # endif DEBUG
136 
137 	while (EventQueue != NULL && EventQueue->ev_time <= now)
138 	{
139 		int (*f)(), a;
140 		int pid;
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, 3))
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 		pid = ev->ev_pid;
155 		free(ev);
156 		if (pid != getpid())
157 			continue;
158 		if (EventQueue != NULL)
159 		{
160 			if (EventQueue->ev_time > now)
161 				(void) alarm(EventQueue->ev_time - now);
162 			else
163 				(void) alarm(3);
164 		}
165 		(*f)(a);
166 		(void) alarm(0);
167 		now = curtime();
168 	}
169 	if (EventQueue != NULL)
170 		(void) alarm(EventQueue->ev_time - now);
171 }
172 /*
173 **  SLEEP -- a version of sleep that works with this stuff
174 **
175 **	Because sleep uses the alarm facility, I must reimplement
176 **	it here.
177 **
178 **	Parameters:
179 **		intvl -- time to sleep.
180 **
181 **	Returns:
182 **		none.
183 **
184 **	Side Effects:
185 **		waits for intvl time.  However, other events can
186 **		be run during that interval.
187 */
188 
189 static bool	SleepDone;
190 
191 sleep(intvl)
192 	int intvl;
193 {
194 	extern endsleep();
195 
196 	if (intvl == 0)
197 		return;
198 	SleepDone = FALSE;
199 	setevent(intvl, endsleep, 0);
200 	while (!SleepDone)
201 		pause();
202 }
203 
204 static
205 endsleep()
206 {
207 	SleepDone = TRUE;
208 }
209