1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*
7*0Sstevel@tonic-gate  * Copyright (c) 1995-1999 by Internet Software Consortium
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
10*0Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
11*0Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
12*0Sstevel@tonic-gate  *
13*0Sstevel@tonic-gate  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
14*0Sstevel@tonic-gate  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
15*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
16*0Sstevel@tonic-gate  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
17*0Sstevel@tonic-gate  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18*0Sstevel@tonic-gate  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19*0Sstevel@tonic-gate  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*0Sstevel@tonic-gate  * SOFTWARE.
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate 
23*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate /* ev_timers.c - implement timers for the eventlib
26*0Sstevel@tonic-gate  * vix 09sep95 [initial]
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
30*0Sstevel@tonic-gate static const char rcsid[] = "$Id: ev_timers.c,v 1.33 2002/07/08 05:50:09 marka Exp $";
31*0Sstevel@tonic-gate #endif
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /* Import. */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #include "port_before.h"
36*0Sstevel@tonic-gate #include "fd_setsize.h"
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #include <errno.h>
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #include <isc/assertions.h>
41*0Sstevel@tonic-gate #include <isc/eventlib.h>
42*0Sstevel@tonic-gate #include "eventlib_p.h"
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #include "port_after.h"
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /* Constants. */
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #define	MILLION 1000000
49*0Sstevel@tonic-gate #define BILLION 1000000000
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /* Forward. */
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static int due_sooner(void *, void *);
54*0Sstevel@tonic-gate static void set_index(void *, int);
55*0Sstevel@tonic-gate static void free_timer(void *, void *);
56*0Sstevel@tonic-gate static void print_timer(void *, void *);
57*0Sstevel@tonic-gate static void idle_timeout(evContext, void *, struct timespec, struct timespec);
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /* Private type. */
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate typedef struct {
62*0Sstevel@tonic-gate 	evTimerFunc	func;
63*0Sstevel@tonic-gate 	void *		uap;
64*0Sstevel@tonic-gate 	struct timespec	lastTouched;
65*0Sstevel@tonic-gate 	struct timespec	max_idle;
66*0Sstevel@tonic-gate 	evTimer *	timer;
67*0Sstevel@tonic-gate } idle_timer;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate /* Public. */
70*0Sstevel@tonic-gate 
71*0Sstevel@tonic-gate struct timespec
72*0Sstevel@tonic-gate evConsTime(time_t sec, long nsec) {
73*0Sstevel@tonic-gate 	struct timespec x;
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate 	x.tv_sec = sec;
76*0Sstevel@tonic-gate 	x.tv_nsec = nsec;
77*0Sstevel@tonic-gate 	return (x);
78*0Sstevel@tonic-gate }
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate struct timespec
81*0Sstevel@tonic-gate evAddTime(struct timespec addend1, struct timespec addend2) {
82*0Sstevel@tonic-gate 	struct timespec x;
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
85*0Sstevel@tonic-gate 	x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
86*0Sstevel@tonic-gate 	if (x.tv_nsec >= BILLION) {
87*0Sstevel@tonic-gate 		x.tv_sec++;
88*0Sstevel@tonic-gate 		x.tv_nsec -= BILLION;
89*0Sstevel@tonic-gate 	}
90*0Sstevel@tonic-gate 	return (x);
91*0Sstevel@tonic-gate }
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate struct timespec
94*0Sstevel@tonic-gate evSubTime(struct timespec minuend, struct timespec subtrahend) {
95*0Sstevel@tonic-gate 	struct timespec x;
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate 	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
98*0Sstevel@tonic-gate 	if (minuend.tv_nsec >= subtrahend.tv_nsec)
99*0Sstevel@tonic-gate 		x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
100*0Sstevel@tonic-gate 	else {
101*0Sstevel@tonic-gate 		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
102*0Sstevel@tonic-gate 		x.tv_sec--;
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 	return (x);
105*0Sstevel@tonic-gate }
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate int
108*0Sstevel@tonic-gate evCmpTime(struct timespec a, struct timespec b) {
109*0Sstevel@tonic-gate 	long x = a.tv_sec - b.tv_sec;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if (x == 0L)
112*0Sstevel@tonic-gate 		x = a.tv_nsec - b.tv_nsec;
113*0Sstevel@tonic-gate 	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate struct timespec
117*0Sstevel@tonic-gate evNowTime() {
118*0Sstevel@tonic-gate 	struct timeval now;
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) < 0)
121*0Sstevel@tonic-gate 		return (evConsTime(0, 0));
122*0Sstevel@tonic-gate 	return (evTimeSpec(now));
123*0Sstevel@tonic-gate }
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate struct timespec
126*0Sstevel@tonic-gate evLastEventTime(evContext opaqueCtx) {
127*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 	return (ctx->lastEventTime);
130*0Sstevel@tonic-gate }
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate struct timespec
133*0Sstevel@tonic-gate evTimeSpec(struct timeval tv) {
134*0Sstevel@tonic-gate 	struct timespec ts;
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	ts.tv_sec = tv.tv_sec;
137*0Sstevel@tonic-gate 	ts.tv_nsec = tv.tv_usec * 1000;
138*0Sstevel@tonic-gate 	return (ts);
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate struct timeval
142*0Sstevel@tonic-gate evTimeVal(struct timespec ts) {
143*0Sstevel@tonic-gate 	struct timeval tv;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	tv.tv_sec = ts.tv_sec;
146*0Sstevel@tonic-gate 	tv.tv_usec = ts.tv_nsec / 1000;
147*0Sstevel@tonic-gate 	return (tv);
148*0Sstevel@tonic-gate }
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate int
151*0Sstevel@tonic-gate evSetTimer(evContext opaqueCtx,
152*0Sstevel@tonic-gate 	   evTimerFunc func,
153*0Sstevel@tonic-gate 	   void *uap,
154*0Sstevel@tonic-gate 	   struct timespec due,
155*0Sstevel@tonic-gate 	   struct timespec inter,
156*0Sstevel@tonic-gate 	   evTimerID *opaqueID
157*0Sstevel@tonic-gate ) {
158*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
159*0Sstevel@tonic-gate 	evTimer *id;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	evPrintf(ctx, 1,
162*0Sstevel@tonic-gate "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
163*0Sstevel@tonic-gate 		 ctx, func, uap,
164*0Sstevel@tonic-gate 		 (long)due.tv_sec, due.tv_nsec,
165*0Sstevel@tonic-gate 		 (long)inter.tv_sec, inter.tv_nsec);
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate 	/* due={0,0} is a magic cookie meaning "now." */
168*0Sstevel@tonic-gate 	if (due.tv_sec == 0 && due.tv_nsec == 0L)
169*0Sstevel@tonic-gate 		due = evNowTime();
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	/* Allocate and fill. */
172*0Sstevel@tonic-gate 	OKNEW(id);
173*0Sstevel@tonic-gate 	id->func = func;
174*0Sstevel@tonic-gate 	id->uap = uap;
175*0Sstevel@tonic-gate 	id->due = due;
176*0Sstevel@tonic-gate 	id->inter = inter;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	if (heap_insert(ctx->timers, id) < 0)
179*0Sstevel@tonic-gate 		return (-1);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	/* Remember the ID if the caller provided us a place for it. */
182*0Sstevel@tonic-gate 	if (opaqueID)
183*0Sstevel@tonic-gate 		opaqueID->opaque = id;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 	if (ctx->debug > 7) {
186*0Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evSetTimer:\n");
187*0Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
188*0Sstevel@tonic-gate 	}
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	return (0);
191*0Sstevel@tonic-gate }
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate int
194*0Sstevel@tonic-gate evClearTimer(evContext opaqueCtx, evTimerID id) {
195*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
196*0Sstevel@tonic-gate 	evTimer *del = id.opaque;
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	if (ctx->cur != NULL &&
199*0Sstevel@tonic-gate 	    ctx->cur->type == Timer &&
200*0Sstevel@tonic-gate 	    ctx->cur->u.timer.this == del) {
201*0Sstevel@tonic-gate 		evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
202*0Sstevel@tonic-gate 		/*
203*0Sstevel@tonic-gate 		 * Setting the interval to zero ensures that evDrop() will
204*0Sstevel@tonic-gate 		 * clean up the timer.
205*0Sstevel@tonic-gate 		 */
206*0Sstevel@tonic-gate 		del->inter = evConsTime(0, 0);
207*0Sstevel@tonic-gate 		return (0);
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	if (heap_element(ctx->timers, del->index) != del)
211*0Sstevel@tonic-gate 		EV_ERR(ENOENT);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	if (heap_delete(ctx->timers, del->index) < 0)
214*0Sstevel@tonic-gate 		return (-1);
215*0Sstevel@tonic-gate 	FREE(del);
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	if (ctx->debug > 7) {
218*0Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evClearTimer:\n");
219*0Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
220*0Sstevel@tonic-gate 	}
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	return (0);
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate int
226*0Sstevel@tonic-gate evResetTimer(evContext opaqueCtx,
227*0Sstevel@tonic-gate 	     evTimerID id,
228*0Sstevel@tonic-gate 	     evTimerFunc func,
229*0Sstevel@tonic-gate 	     void *uap,
230*0Sstevel@tonic-gate 	     struct timespec due,
231*0Sstevel@tonic-gate 	     struct timespec inter
232*0Sstevel@tonic-gate ) {
233*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
234*0Sstevel@tonic-gate 	evTimer *timer = id.opaque;
235*0Sstevel@tonic-gate 	struct timespec old_due;
236*0Sstevel@tonic-gate 	int result=0;
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	if (heap_element(ctx->timers, timer->index) != timer)
239*0Sstevel@tonic-gate 		EV_ERR(ENOENT);
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	old_due = timer->due;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	timer->func = func;
244*0Sstevel@tonic-gate 	timer->uap = uap;
245*0Sstevel@tonic-gate 	timer->due = due;
246*0Sstevel@tonic-gate 	timer->inter = inter;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	switch (evCmpTime(due, old_due)) {
249*0Sstevel@tonic-gate 	case -1:
250*0Sstevel@tonic-gate 		result = heap_increased(ctx->timers, timer->index);
251*0Sstevel@tonic-gate 		break;
252*0Sstevel@tonic-gate 	case 0:
253*0Sstevel@tonic-gate 		result = 0;
254*0Sstevel@tonic-gate 		break;
255*0Sstevel@tonic-gate 	case 1:
256*0Sstevel@tonic-gate 		result = heap_decreased(ctx->timers, timer->index);
257*0Sstevel@tonic-gate 		break;
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (ctx->debug > 7) {
261*0Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evResetTimer:\n");
262*0Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	return (result);
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate int
269*0Sstevel@tonic-gate evSetIdleTimer(evContext opaqueCtx,
270*0Sstevel@tonic-gate 		evTimerFunc func,
271*0Sstevel@tonic-gate 		void *uap,
272*0Sstevel@tonic-gate 		struct timespec max_idle,
273*0Sstevel@tonic-gate 		evTimerID *opaqueID
274*0Sstevel@tonic-gate ) {
275*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
276*0Sstevel@tonic-gate 	idle_timer *tt;
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	/* Allocate and fill. */
279*0Sstevel@tonic-gate 	OKNEW(tt);
280*0Sstevel@tonic-gate 	tt->func = func;
281*0Sstevel@tonic-gate 	tt->uap = uap;
282*0Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
283*0Sstevel@tonic-gate 	tt->max_idle = max_idle;
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 	if (evSetTimer(opaqueCtx, idle_timeout, tt,
286*0Sstevel@tonic-gate 		       evAddTime(ctx->lastEventTime, max_idle),
287*0Sstevel@tonic-gate 		       max_idle, opaqueID) < 0) {
288*0Sstevel@tonic-gate 		FREE(tt);
289*0Sstevel@tonic-gate 		return (-1);
290*0Sstevel@tonic-gate 	}
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	tt->timer = opaqueID->opaque;
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate 	return (0);
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate int
298*0Sstevel@tonic-gate evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
299*0Sstevel@tonic-gate 	evTimer *del = id.opaque;
300*0Sstevel@tonic-gate 	idle_timer *tt = del->uap;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	FREE(tt);
303*0Sstevel@tonic-gate 	return (evClearTimer(opaqueCtx, id));
304*0Sstevel@tonic-gate }
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate int
307*0Sstevel@tonic-gate evResetIdleTimer(evContext opaqueCtx,
308*0Sstevel@tonic-gate 		 evTimerID opaqueID,
309*0Sstevel@tonic-gate 		 evTimerFunc func,
310*0Sstevel@tonic-gate 		 void *uap,
311*0Sstevel@tonic-gate 		 struct timespec max_idle
312*0Sstevel@tonic-gate ) {
313*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
314*0Sstevel@tonic-gate 	evTimer *timer = opaqueID.opaque;
315*0Sstevel@tonic-gate 	idle_timer *tt = timer->uap;
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	tt->func = func;
318*0Sstevel@tonic-gate 	tt->uap = uap;
319*0Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
320*0Sstevel@tonic-gate 	tt->max_idle = max_idle;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
323*0Sstevel@tonic-gate 			     evAddTime(ctx->lastEventTime, max_idle),
324*0Sstevel@tonic-gate 			     max_idle));
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate int
328*0Sstevel@tonic-gate evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
329*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
330*0Sstevel@tonic-gate 	evTimer *t = id.opaque;
331*0Sstevel@tonic-gate 	idle_timer *tt = t->uap;
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	return (0);
336*0Sstevel@tonic-gate }
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate /* Public to the rest of eventlib. */
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate heap_context
341*0Sstevel@tonic-gate evCreateTimers(const evContext_p *ctx) {
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	UNUSED(ctx);
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	return (heap_new(due_sooner, set_index, 2048));
346*0Sstevel@tonic-gate }
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate void
349*0Sstevel@tonic-gate evDestroyTimers(const evContext_p *ctx) {
350*0Sstevel@tonic-gate 	(void) heap_for_each(ctx->timers, free_timer, NULL);
351*0Sstevel@tonic-gate 	(void) heap_free(ctx->timers);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate /* Private. */
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate static int
357*0Sstevel@tonic-gate due_sooner(void *a, void *b) {
358*0Sstevel@tonic-gate 	evTimer *a_timer, *b_timer;
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	a_timer = a;
361*0Sstevel@tonic-gate 	b_timer = b;
362*0Sstevel@tonic-gate 	return (evCmpTime(a_timer->due, b_timer->due) < 0);
363*0Sstevel@tonic-gate }
364*0Sstevel@tonic-gate 
365*0Sstevel@tonic-gate static void
366*0Sstevel@tonic-gate set_index(void *what, int index) {
367*0Sstevel@tonic-gate 	evTimer *timer;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	timer = what;
370*0Sstevel@tonic-gate 	timer->index = index;
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate 
373*0Sstevel@tonic-gate static void
374*0Sstevel@tonic-gate free_timer(void *what, void *uap) {
375*0Sstevel@tonic-gate 	evTimer *t = what;
376*0Sstevel@tonic-gate 
377*0Sstevel@tonic-gate 	UNUSED(uap);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	FREE(t);
380*0Sstevel@tonic-gate }
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate static void
383*0Sstevel@tonic-gate print_timer(void *what, void *uap) {
384*0Sstevel@tonic-gate 	evTimer *cur = what;
385*0Sstevel@tonic-gate 	evContext_p *ctx = uap;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	cur = what;
388*0Sstevel@tonic-gate 	evPrintf(ctx, 7,
389*0Sstevel@tonic-gate 	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
390*0Sstevel@tonic-gate 		 cur->func, cur->uap,
391*0Sstevel@tonic-gate 		 (long)cur->due.tv_sec, cur->due.tv_nsec,
392*0Sstevel@tonic-gate 		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate static void
396*0Sstevel@tonic-gate idle_timeout(evContext opaqueCtx,
397*0Sstevel@tonic-gate 	     void *uap,
398*0Sstevel@tonic-gate 	     struct timespec due,
399*0Sstevel@tonic-gate 	     struct timespec inter
400*0Sstevel@tonic-gate ) {
401*0Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
402*0Sstevel@tonic-gate 	idle_timer *this = uap;
403*0Sstevel@tonic-gate 	struct timespec idle;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	UNUSED(due);
406*0Sstevel@tonic-gate 	UNUSED(inter);
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
409*0Sstevel@tonic-gate 	if (evCmpTime(idle, this->max_idle) >= 0) {
410*0Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->timer->due,
411*0Sstevel@tonic-gate 			     this->max_idle);
412*0Sstevel@tonic-gate 		/*
413*0Sstevel@tonic-gate 		 * Setting the interval to zero will cause the timer to
414*0Sstevel@tonic-gate 		 * be cleaned up in evDrop().
415*0Sstevel@tonic-gate 		 */
416*0Sstevel@tonic-gate 		this->timer->inter = evConsTime(0, 0);
417*0Sstevel@tonic-gate 		FREE(this);
418*0Sstevel@tonic-gate 	} else {
419*0Sstevel@tonic-gate 		/* evDrop() will reschedule the timer. */
420*0Sstevel@tonic-gate 		this->timer->inter = evSubTime(this->max_idle, idle);
421*0Sstevel@tonic-gate 	}
422*0Sstevel@tonic-gate }
423