xref: /netbsd/lib/libc/isc/ev_timers.c (revision 0f246c0a)
1*0f246c0aSchristos /*	$NetBSD: ev_timers.c,v 1.11 2012/03/21 00:34:54 christos Exp $	*/
2330989eeSchristos 
3330989eeSchristos /*
4330989eeSchristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5330989eeSchristos  * Copyright (c) 1995-1999 by Internet Software Consortium
6330989eeSchristos  *
7330989eeSchristos  * Permission to use, copy, modify, and distribute this software for any
8330989eeSchristos  * purpose with or without fee is hereby granted, provided that the above
9330989eeSchristos  * copyright notice and this permission notice appear in all copies.
10330989eeSchristos  *
11330989eeSchristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12330989eeSchristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13330989eeSchristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14330989eeSchristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15330989eeSchristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16330989eeSchristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17330989eeSchristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18330989eeSchristos  */
19330989eeSchristos 
20330989eeSchristos /* ev_timers.c - implement timers for the eventlib
21330989eeSchristos  * vix 09sep95 [initial]
22330989eeSchristos  */
23330989eeSchristos 
2449a363f1Schristos #include <sys/cdefs.h>
2549a363f1Schristos #if !defined(LINT) && !defined(CODECENTER) && !defined(lint)
2649a363f1Schristos #ifdef notdef
273873655bSchristos static const char rcsid[] = "Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp";
2849a363f1Schristos #else
29*0f246c0aSchristos __RCSID("$NetBSD: ev_timers.c,v 1.11 2012/03/21 00:34:54 christos Exp $");
3049a363f1Schristos #endif
31330989eeSchristos #endif
32330989eeSchristos 
33330989eeSchristos /* Import. */
34330989eeSchristos 
35330989eeSchristos #include "port_before.h"
36330989eeSchristos #include "fd_setsize.h"
37330989eeSchristos 
38330989eeSchristos #include <errno.h>
39330989eeSchristos 
40330989eeSchristos #include <isc/assertions.h>
41330989eeSchristos #include <isc/eventlib.h>
42330989eeSchristos #include "eventlib_p.h"
43330989eeSchristos 
44330989eeSchristos #include "port_after.h"
45330989eeSchristos 
46330989eeSchristos /* Constants. */
47330989eeSchristos 
48330989eeSchristos #define	MILLION 1000000
49330989eeSchristos #define BILLION 1000000000
50330989eeSchristos 
51330989eeSchristos /* Forward. */
52330989eeSchristos 
5349a363f1Schristos #ifndef _LIBC
54330989eeSchristos static int due_sooner(void *, void *);
55330989eeSchristos static void set_index(void *, int);
56330989eeSchristos static void free_timer(void *, void *);
57330989eeSchristos static void print_timer(void *, void *);
58330989eeSchristos static void idle_timeout(evContext, void *, struct timespec, struct timespec);
59330989eeSchristos 
60330989eeSchristos /* Private type. */
61330989eeSchristos 
62330989eeSchristos typedef struct {
63330989eeSchristos 	evTimerFunc	func;
64330989eeSchristos 	void *		uap;
65330989eeSchristos 	struct timespec	lastTouched;
66330989eeSchristos 	struct timespec	max_idle;
67330989eeSchristos 	evTimer *	timer;
68330989eeSchristos } idle_timer;
6949a363f1Schristos #endif
70330989eeSchristos 
71330989eeSchristos /* Public. */
72330989eeSchristos 
73330989eeSchristos struct timespec
evConsTime(time_t sec,long nsec)74330989eeSchristos evConsTime(time_t sec, long nsec) {
75330989eeSchristos 	struct timespec x;
76330989eeSchristos 
77330989eeSchristos 	x.tv_sec = sec;
78330989eeSchristos 	x.tv_nsec = nsec;
79330989eeSchristos 	return (x);
80330989eeSchristos }
81330989eeSchristos 
82330989eeSchristos struct timespec
evAddTime(struct timespec addend1,struct timespec addend2)83330989eeSchristos evAddTime(struct timespec addend1, struct timespec addend2) {
84330989eeSchristos 	struct timespec x;
85330989eeSchristos 
86330989eeSchristos 	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
87330989eeSchristos 	x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
88330989eeSchristos 	if (x.tv_nsec >= BILLION) {
89330989eeSchristos 		x.tv_sec++;
90330989eeSchristos 		x.tv_nsec -= BILLION;
91330989eeSchristos 	}
92330989eeSchristos 	return (x);
93330989eeSchristos }
94330989eeSchristos 
95330989eeSchristos struct timespec
evSubTime(struct timespec minuend,struct timespec subtrahend)96330989eeSchristos evSubTime(struct timespec minuend, struct timespec subtrahend) {
97330989eeSchristos 	struct timespec x;
98330989eeSchristos 
99330989eeSchristos 	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
100330989eeSchristos 	if (minuend.tv_nsec >= subtrahend.tv_nsec)
101330989eeSchristos 		x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
102330989eeSchristos 	else {
103330989eeSchristos 		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
104330989eeSchristos 		x.tv_sec--;
105330989eeSchristos 	}
106330989eeSchristos 	return (x);
107330989eeSchristos }
108330989eeSchristos 
109330989eeSchristos int
evCmpTime(struct timespec a,struct timespec b)110330989eeSchristos evCmpTime(struct timespec a, struct timespec b) {
111461a86f9Schristos #define SGN(x) ((x) < 0 ? (-1) : (x) > 0 ? (1) : (0));
112461a86f9Schristos 	time_t s = a.tv_sec - b.tv_sec;
113461a86f9Schristos 	long n;
114330989eeSchristos 
115461a86f9Schristos 	if (s != 0)
116461a86f9Schristos 		return SGN(s);
117461a86f9Schristos 
118461a86f9Schristos 	n = a.tv_nsec - b.tv_nsec;
119461a86f9Schristos 	return SGN(n);
120330989eeSchristos }
121330989eeSchristos 
122330989eeSchristos struct timespec
evNowTime(void)12394a48f81Smatt evNowTime(void)
12494a48f81Smatt {
125330989eeSchristos 	struct timeval now;
126330989eeSchristos #ifdef CLOCK_REALTIME
127330989eeSchristos 	struct timespec tsnow;
128330989eeSchristos 	int m = CLOCK_REALTIME;
129330989eeSchristos 
130330989eeSchristos #ifdef CLOCK_MONOTONIC
1316fbd14f0Schristos #ifndef _LIBC
132330989eeSchristos 	if (__evOptMonoTime)
133330989eeSchristos 		m = CLOCK_MONOTONIC;
134330989eeSchristos #endif
1356fbd14f0Schristos #endif
136330989eeSchristos 	if (clock_gettime(m, &tsnow) == 0)
137330989eeSchristos 		return (tsnow);
138330989eeSchristos #endif
139330989eeSchristos 	if (gettimeofday(&now, NULL) < 0)
140*0f246c0aSchristos 		return (evConsTime((time_t)0, 0L));
141330989eeSchristos 	return (evTimeSpec(now));
142330989eeSchristos }
143330989eeSchristos 
144330989eeSchristos struct timespec
evUTCTime(void)14549a363f1Schristos evUTCTime(void) {
146330989eeSchristos 	struct timeval now;
147330989eeSchristos #ifdef CLOCK_REALTIME
148330989eeSchristos 	struct timespec tsnow;
149330989eeSchristos 	if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
150330989eeSchristos 		return (tsnow);
151330989eeSchristos #endif
152330989eeSchristos 	if (gettimeofday(&now, NULL) < 0)
153*0f246c0aSchristos 		return (evConsTime((time_t)0, 0L));
154330989eeSchristos 	return (evTimeSpec(now));
155330989eeSchristos }
156330989eeSchristos 
15749a363f1Schristos #ifndef _LIBC
158330989eeSchristos struct timespec
evLastEventTime(evContext opaqueCtx)159330989eeSchristos evLastEventTime(evContext opaqueCtx) {
160330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
161330989eeSchristos 
162330989eeSchristos 	return (ctx->lastEventTime);
163330989eeSchristos }
16449a363f1Schristos #endif
165330989eeSchristos 
166330989eeSchristos struct timespec
evTimeSpec(struct timeval tv)167330989eeSchristos evTimeSpec(struct timeval tv) {
168330989eeSchristos 	struct timespec ts;
169330989eeSchristos 
170330989eeSchristos 	ts.tv_sec = tv.tv_sec;
171330989eeSchristos 	ts.tv_nsec = tv.tv_usec * 1000;
172330989eeSchristos 	return (ts);
173330989eeSchristos }
174330989eeSchristos 
175330989eeSchristos struct timeval
evTimeVal(struct timespec ts)176330989eeSchristos evTimeVal(struct timespec ts) {
177330989eeSchristos 	struct timeval tv;
178330989eeSchristos 
179330989eeSchristos 	tv.tv_sec = ts.tv_sec;
180e826745eSchristos 	tv.tv_usec = (suseconds_t)(ts.tv_nsec / 1000);
181330989eeSchristos 	return (tv);
182330989eeSchristos }
183330989eeSchristos 
18449a363f1Schristos #ifndef _LIBC
185330989eeSchristos int
evSetTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec due,struct timespec inter,evTimerID * opaqueID)186330989eeSchristos evSetTimer(evContext opaqueCtx,
187330989eeSchristos 	   evTimerFunc func,
188330989eeSchristos 	   void *uap,
189330989eeSchristos 	   struct timespec due,
190330989eeSchristos 	   struct timespec inter,
191330989eeSchristos 	   evTimerID *opaqueID
192330989eeSchristos ) {
193330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
194330989eeSchristos 	evTimer *id;
195330989eeSchristos 
196330989eeSchristos 	evPrintf(ctx, 1,
197330989eeSchristos "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
198330989eeSchristos 		 ctx, func, uap,
199330989eeSchristos 		 (long)due.tv_sec, due.tv_nsec,
200330989eeSchristos 		 (long)inter.tv_sec, inter.tv_nsec);
201330989eeSchristos 
202330989eeSchristos #ifdef __hpux
203330989eeSchristos 	/*
204330989eeSchristos 	 * tv_sec and tv_nsec are unsigned.
205330989eeSchristos 	 */
206330989eeSchristos 	if (due.tv_nsec >= BILLION)
207330989eeSchristos 		EV_ERR(EINVAL);
208330989eeSchristos 
209330989eeSchristos 	if (inter.tv_nsec >= BILLION)
210330989eeSchristos 		EV_ERR(EINVAL);
211330989eeSchristos #else
212330989eeSchristos 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
213330989eeSchristos 		EV_ERR(EINVAL);
214330989eeSchristos 
215330989eeSchristos 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
216330989eeSchristos 		EV_ERR(EINVAL);
217330989eeSchristos #endif
218330989eeSchristos 
219330989eeSchristos 	/* due={0,0} is a magic cookie meaning "now." */
220330989eeSchristos 	if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
221330989eeSchristos 		due = evNowTime();
222330989eeSchristos 
223330989eeSchristos 	/* Allocate and fill. */
224330989eeSchristos 	OKNEW(id);
225330989eeSchristos 	id->func = func;
226330989eeSchristos 	id->uap = uap;
227330989eeSchristos 	id->due = due;
228330989eeSchristos 	id->inter = inter;
229330989eeSchristos 
230330989eeSchristos 	if (heap_insert(ctx->timers, id) < 0)
231330989eeSchristos 		return (-1);
232330989eeSchristos 
233330989eeSchristos 	/* Remember the ID if the caller provided us a place for it. */
234330989eeSchristos 	if (opaqueID)
235330989eeSchristos 		opaqueID->opaque = id;
236330989eeSchristos 
237330989eeSchristos 	if (ctx->debug > 7) {
238330989eeSchristos 		evPrintf(ctx, 7, "timers after evSetTimer:\n");
239330989eeSchristos 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
240330989eeSchristos 	}
241330989eeSchristos 
242330989eeSchristos 	return (0);
243330989eeSchristos }
244330989eeSchristos 
245330989eeSchristos int
evClearTimer(evContext opaqueCtx,evTimerID id)246330989eeSchristos evClearTimer(evContext opaqueCtx, evTimerID id) {
247330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
248330989eeSchristos 	evTimer *del = id.opaque;
249330989eeSchristos 
250330989eeSchristos 	if (ctx->cur != NULL &&
251330989eeSchristos 	    ctx->cur->type == Timer &&
252330989eeSchristos 	    ctx->cur->u.timer.this == del) {
253330989eeSchristos 		evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
254330989eeSchristos 		/*
255330989eeSchristos 		 * Setting the interval to zero ensures that evDrop() will
256330989eeSchristos 		 * clean up the timer.
257330989eeSchristos 		 */
258330989eeSchristos 		del->inter = evConsTime(0, 0);
259330989eeSchristos 		return (0);
260330989eeSchristos 	}
261330989eeSchristos 
262330989eeSchristos 	if (heap_element(ctx->timers, del->index) != del)
263330989eeSchristos 		EV_ERR(ENOENT);
264330989eeSchristos 
265330989eeSchristos 	if (heap_delete(ctx->timers, del->index) < 0)
266330989eeSchristos 		return (-1);
267330989eeSchristos 	FREE(del);
268330989eeSchristos 
269330989eeSchristos 	if (ctx->debug > 7) {
270330989eeSchristos 		evPrintf(ctx, 7, "timers after evClearTimer:\n");
271330989eeSchristos 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
272330989eeSchristos 	}
273330989eeSchristos 
274330989eeSchristos 	return (0);
275330989eeSchristos }
276330989eeSchristos 
277330989eeSchristos int
evConfigTimer(evContext opaqueCtx,evTimerID id,const char * param,int value)278330989eeSchristos evConfigTimer(evContext opaqueCtx,
279330989eeSchristos 	     evTimerID id,
280330989eeSchristos 	     const char *param,
281330989eeSchristos 	     int value
282330989eeSchristos ) {
283330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
284330989eeSchristos 	evTimer *timer = id.opaque;
285330989eeSchristos 	int result=0;
286330989eeSchristos 
287330989eeSchristos 	UNUSED(value);
288330989eeSchristos 
289330989eeSchristos 	if (heap_element(ctx->timers, timer->index) != timer)
290330989eeSchristos 		EV_ERR(ENOENT);
291330989eeSchristos 
292330989eeSchristos 	if (strcmp(param, "rate") == 0)
293330989eeSchristos 		timer->mode |= EV_TMR_RATE;
294330989eeSchristos 	else if (strcmp(param, "interval") == 0)
295330989eeSchristos 		timer->mode &= ~EV_TMR_RATE;
296330989eeSchristos 	else
297330989eeSchristos 		EV_ERR(EINVAL);
298330989eeSchristos 
299330989eeSchristos 	return (result);
300330989eeSchristos }
301330989eeSchristos 
302330989eeSchristos int
evResetTimer(evContext opaqueCtx,evTimerID id,evTimerFunc func,void * uap,struct timespec due,struct timespec inter)303330989eeSchristos evResetTimer(evContext opaqueCtx,
304330989eeSchristos 	     evTimerID id,
305330989eeSchristos 	     evTimerFunc func,
306330989eeSchristos 	     void *uap,
307330989eeSchristos 	     struct timespec due,
308330989eeSchristos 	     struct timespec inter
309330989eeSchristos ) {
310330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
311330989eeSchristos 	evTimer *timer = id.opaque;
312330989eeSchristos 	struct timespec old_due;
313330989eeSchristos 	int result=0;
314330989eeSchristos 
315330989eeSchristos 	if (heap_element(ctx->timers, timer->index) != timer)
316330989eeSchristos 		EV_ERR(ENOENT);
317330989eeSchristos 
318330989eeSchristos #ifdef __hpux
319330989eeSchristos 	/*
320330989eeSchristos 	 * tv_sec and tv_nsec are unsigned.
321330989eeSchristos 	 */
322330989eeSchristos 	if (due.tv_nsec >= BILLION)
323330989eeSchristos 		EV_ERR(EINVAL);
324330989eeSchristos 
325330989eeSchristos 	if (inter.tv_nsec >= BILLION)
326330989eeSchristos 		EV_ERR(EINVAL);
327330989eeSchristos #else
328330989eeSchristos 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
329330989eeSchristos 		EV_ERR(EINVAL);
330330989eeSchristos 
331330989eeSchristos 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
332330989eeSchristos 		EV_ERR(EINVAL);
333330989eeSchristos #endif
334330989eeSchristos 
335330989eeSchristos 	old_due = timer->due;
336330989eeSchristos 
337330989eeSchristos 	timer->func = func;
338330989eeSchristos 	timer->uap = uap;
339330989eeSchristos 	timer->due = due;
340330989eeSchristos 	timer->inter = inter;
341330989eeSchristos 
342330989eeSchristos 	switch (evCmpTime(due, old_due)) {
343330989eeSchristos 	case -1:
344330989eeSchristos 		result = heap_increased(ctx->timers, timer->index);
345330989eeSchristos 		break;
346330989eeSchristos 	case 0:
347330989eeSchristos 		result = 0;
348330989eeSchristos 		break;
349330989eeSchristos 	case 1:
350330989eeSchristos 		result = heap_decreased(ctx->timers, timer->index);
351330989eeSchristos 		break;
352330989eeSchristos 	}
353330989eeSchristos 
354330989eeSchristos 	if (ctx->debug > 7) {
355330989eeSchristos 		evPrintf(ctx, 7, "timers after evResetTimer:\n");
356330989eeSchristos 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
357330989eeSchristos 	}
358330989eeSchristos 
359330989eeSchristos 	return (result);
360330989eeSchristos }
361330989eeSchristos 
362330989eeSchristos int
evSetIdleTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec max_idle,evTimerID * opaqueID)363330989eeSchristos evSetIdleTimer(evContext opaqueCtx,
364330989eeSchristos 		evTimerFunc func,
365330989eeSchristos 		void *uap,
366330989eeSchristos 		struct timespec max_idle,
367330989eeSchristos 		evTimerID *opaqueID
368330989eeSchristos ) {
369330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
370330989eeSchristos 	idle_timer *tt;
371330989eeSchristos 
372330989eeSchristos 	/* Allocate and fill. */
373330989eeSchristos 	OKNEW(tt);
374330989eeSchristos 	tt->func = func;
375330989eeSchristos 	tt->uap = uap;
376330989eeSchristos 	tt->lastTouched = ctx->lastEventTime;
377330989eeSchristos 	tt->max_idle = max_idle;
378330989eeSchristos 
379330989eeSchristos 	if (evSetTimer(opaqueCtx, idle_timeout, tt,
380330989eeSchristos 		       evAddTime(ctx->lastEventTime, max_idle),
381330989eeSchristos 		       max_idle, opaqueID) < 0) {
382330989eeSchristos 		FREE(tt);
383330989eeSchristos 		return (-1);
384330989eeSchristos 	}
385330989eeSchristos 
386330989eeSchristos 	tt->timer = opaqueID->opaque;
387330989eeSchristos 
388330989eeSchristos 	return (0);
389330989eeSchristos }
390330989eeSchristos 
391330989eeSchristos int
evClearIdleTimer(evContext opaqueCtx,evTimerID id)392330989eeSchristos evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
393330989eeSchristos 	evTimer *del = id.opaque;
394330989eeSchristos 	idle_timer *tt = del->uap;
395330989eeSchristos 
396330989eeSchristos 	FREE(tt);
397330989eeSchristos 	return (evClearTimer(opaqueCtx, id));
398330989eeSchristos }
399330989eeSchristos 
400330989eeSchristos int
evResetIdleTimer(evContext opaqueCtx,evTimerID opaqueID,evTimerFunc func,void * uap,struct timespec max_idle)401330989eeSchristos evResetIdleTimer(evContext opaqueCtx,
402330989eeSchristos 		 evTimerID opaqueID,
403330989eeSchristos 		 evTimerFunc func,
404330989eeSchristos 		 void *uap,
405330989eeSchristos 		 struct timespec max_idle
406330989eeSchristos ) {
407330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
408330989eeSchristos 	evTimer *timer = opaqueID.opaque;
409330989eeSchristos 	idle_timer *tt = timer->uap;
410330989eeSchristos 
411330989eeSchristos 	tt->func = func;
412330989eeSchristos 	tt->uap = uap;
413330989eeSchristos 	tt->lastTouched = ctx->lastEventTime;
414330989eeSchristos 	tt->max_idle = max_idle;
415330989eeSchristos 
416330989eeSchristos 	return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
417330989eeSchristos 			     evAddTime(ctx->lastEventTime, max_idle),
418330989eeSchristos 			     max_idle));
419330989eeSchristos }
420330989eeSchristos 
421330989eeSchristos int
evTouchIdleTimer(evContext opaqueCtx,evTimerID id)422330989eeSchristos evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
423330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
424330989eeSchristos 	evTimer *t = id.opaque;
425330989eeSchristos 	idle_timer *tt = t->uap;
426330989eeSchristos 
427330989eeSchristos 	tt->lastTouched = ctx->lastEventTime;
428330989eeSchristos 
429330989eeSchristos 	return (0);
430330989eeSchristos }
431330989eeSchristos 
432330989eeSchristos /* Public to the rest of eventlib. */
433330989eeSchristos 
434330989eeSchristos heap_context
evCreateTimers(const evContext_p * ctx)435330989eeSchristos evCreateTimers(const evContext_p *ctx) {
436330989eeSchristos 
437330989eeSchristos 	UNUSED(ctx);
438330989eeSchristos 
439330989eeSchristos 	return (heap_new(due_sooner, set_index, 2048));
440330989eeSchristos }
441330989eeSchristos 
442330989eeSchristos void
evDestroyTimers(const evContext_p * ctx)443330989eeSchristos evDestroyTimers(const evContext_p *ctx) {
444330989eeSchristos 	(void) heap_for_each(ctx->timers, free_timer, NULL);
445330989eeSchristos 	(void) heap_free(ctx->timers);
446330989eeSchristos }
447330989eeSchristos 
448330989eeSchristos /* Private. */
449330989eeSchristos 
450330989eeSchristos static int
due_sooner(void * a,void * b)451330989eeSchristos due_sooner(void *a, void *b) {
452330989eeSchristos 	evTimer *a_timer, *b_timer;
453330989eeSchristos 
454330989eeSchristos 	a_timer = a;
455330989eeSchristos 	b_timer = b;
456330989eeSchristos 	return (evCmpTime(a_timer->due, b_timer->due) < 0);
457330989eeSchristos }
458330989eeSchristos 
459330989eeSchristos static void
set_index(void * what,int idx)46049a363f1Schristos set_index(void *what, int idx) {
461330989eeSchristos 	evTimer *timer;
462330989eeSchristos 
463330989eeSchristos 	timer = what;
46449a363f1Schristos 	timer->index = idx;
465330989eeSchristos }
466330989eeSchristos 
467330989eeSchristos static void
free_timer(void * what,void * uap)468330989eeSchristos free_timer(void *what, void *uap) {
469330989eeSchristos 	evTimer *t = what;
470330989eeSchristos 
471330989eeSchristos 	UNUSED(uap);
472330989eeSchristos 
473330989eeSchristos 	FREE(t);
474330989eeSchristos }
475330989eeSchristos 
476330989eeSchristos static void
print_timer(void * what,void * uap)477330989eeSchristos print_timer(void *what, void *uap) {
478330989eeSchristos 	evTimer *cur = what;
479330989eeSchristos 	evContext_p *ctx = uap;
480330989eeSchristos 
481330989eeSchristos 	cur = what;
482330989eeSchristos 	evPrintf(ctx, 7,
483330989eeSchristos 	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
484330989eeSchristos 		 cur->func, cur->uap,
485330989eeSchristos 		 (long)cur->due.tv_sec, cur->due.tv_nsec,
486330989eeSchristos 		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
487330989eeSchristos }
488330989eeSchristos 
489330989eeSchristos static void
idle_timeout(evContext opaqueCtx,void * uap,struct timespec due,struct timespec inter)490330989eeSchristos idle_timeout(evContext opaqueCtx,
491330989eeSchristos 	     void *uap,
492330989eeSchristos 	     struct timespec due,
493330989eeSchristos 	     struct timespec inter
494330989eeSchristos ) {
495330989eeSchristos 	evContext_p *ctx = opaqueCtx.opaque;
496330989eeSchristos 	idle_timer *this = uap;
497330989eeSchristos 	struct timespec idle;
498330989eeSchristos 
499330989eeSchristos 	UNUSED(due);
500330989eeSchristos 	UNUSED(inter);
501330989eeSchristos 
502330989eeSchristos 	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
503330989eeSchristos 	if (evCmpTime(idle, this->max_idle) >= 0) {
504330989eeSchristos 		(this->func)(opaqueCtx, this->uap, this->timer->due,
505330989eeSchristos 			     this->max_idle);
506330989eeSchristos 		/*
507330989eeSchristos 		 * Setting the interval to zero will cause the timer to
508330989eeSchristos 		 * be cleaned up in evDrop().
509330989eeSchristos 		 */
51049a363f1Schristos 		this->timer->inter = evConsTime(0L, 0L);
511330989eeSchristos 		FREE(this);
512330989eeSchristos 	} else {
513330989eeSchristos 		/* evDrop() will reschedule the timer. */
514330989eeSchristos 		this->timer->inter = evSubTime(this->max_idle, idle);
515330989eeSchristos 	}
516330989eeSchristos }
51749a363f1Schristos #endif
518d73eb73dSchristos 
519d73eb73dSchristos /*! \file */
520