xref: /onnv-gate/usr/src/lib/libresolv2/common/isc/ev_timers.c (revision 11038:74b12212b8a2)
10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
30Sstevel@tonic-gate  * Copyright (c) 1995-1999 by Internet Software Consortium
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate  *
9*11038SRao.Shoaib@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate /* ev_timers.c - implement timers for the eventlib
190Sstevel@tonic-gate  * vix 09sep95 [initial]
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
23*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $";
240Sstevel@tonic-gate #endif
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /* Import. */
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "port_before.h"
290Sstevel@tonic-gate #include "fd_setsize.h"
300Sstevel@tonic-gate 
310Sstevel@tonic-gate #include <errno.h>
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #include <isc/assertions.h>
340Sstevel@tonic-gate #include <isc/eventlib.h>
350Sstevel@tonic-gate #include "eventlib_p.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include "port_after.h"
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /* Constants. */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	MILLION 1000000
420Sstevel@tonic-gate #define BILLION 1000000000
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /* Forward. */
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static int due_sooner(void *, void *);
470Sstevel@tonic-gate static void set_index(void *, int);
480Sstevel@tonic-gate static void free_timer(void *, void *);
490Sstevel@tonic-gate static void print_timer(void *, void *);
500Sstevel@tonic-gate static void idle_timeout(evContext, void *, struct timespec, struct timespec);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* Private type. */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate typedef struct {
550Sstevel@tonic-gate 	evTimerFunc	func;
560Sstevel@tonic-gate 	void *		uap;
570Sstevel@tonic-gate 	struct timespec	lastTouched;
580Sstevel@tonic-gate 	struct timespec	max_idle;
590Sstevel@tonic-gate 	evTimer *	timer;
600Sstevel@tonic-gate } idle_timer;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /* Public. */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate struct timespec
evConsTime(time_t sec,long nsec)650Sstevel@tonic-gate evConsTime(time_t sec, long nsec) {
660Sstevel@tonic-gate 	struct timespec x;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	x.tv_sec = sec;
690Sstevel@tonic-gate 	x.tv_nsec = nsec;
700Sstevel@tonic-gate 	return (x);
710Sstevel@tonic-gate }
720Sstevel@tonic-gate 
730Sstevel@tonic-gate struct timespec
evAddTime(struct timespec addend1,struct timespec addend2)740Sstevel@tonic-gate evAddTime(struct timespec addend1, struct timespec addend2) {
750Sstevel@tonic-gate 	struct timespec x;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
780Sstevel@tonic-gate 	x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
790Sstevel@tonic-gate 	if (x.tv_nsec >= BILLION) {
800Sstevel@tonic-gate 		x.tv_sec++;
810Sstevel@tonic-gate 		x.tv_nsec -= BILLION;
820Sstevel@tonic-gate 	}
830Sstevel@tonic-gate 	return (x);
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate struct timespec
evSubTime(struct timespec minuend,struct timespec subtrahend)870Sstevel@tonic-gate evSubTime(struct timespec minuend, struct timespec subtrahend) {
880Sstevel@tonic-gate 	struct timespec x;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
910Sstevel@tonic-gate 	if (minuend.tv_nsec >= subtrahend.tv_nsec)
920Sstevel@tonic-gate 		x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
930Sstevel@tonic-gate 	else {
940Sstevel@tonic-gate 		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
950Sstevel@tonic-gate 		x.tv_sec--;
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 	return (x);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate int
evCmpTime(struct timespec a,struct timespec b)1010Sstevel@tonic-gate evCmpTime(struct timespec a, struct timespec b) {
1020Sstevel@tonic-gate 	long x = a.tv_sec - b.tv_sec;
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate 	if (x == 0L)
1050Sstevel@tonic-gate 		x = a.tv_nsec - b.tv_nsec;
1060Sstevel@tonic-gate 	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate struct timespec
evNowTime()1100Sstevel@tonic-gate evNowTime() {
1110Sstevel@tonic-gate 	struct timeval now;
112*11038SRao.Shoaib@Sun.COM #ifdef CLOCK_REALTIME
113*11038SRao.Shoaib@Sun.COM 	struct timespec tsnow;
114*11038SRao.Shoaib@Sun.COM 	int m = CLOCK_REALTIME;
1150Sstevel@tonic-gate 
116*11038SRao.Shoaib@Sun.COM #ifdef CLOCK_MONOTONIC
117*11038SRao.Shoaib@Sun.COM 	if (__evOptMonoTime)
118*11038SRao.Shoaib@Sun.COM 		m = CLOCK_MONOTONIC;
119*11038SRao.Shoaib@Sun.COM #endif
120*11038SRao.Shoaib@Sun.COM 	if (clock_gettime(m, &tsnow) == 0)
121*11038SRao.Shoaib@Sun.COM 		return (tsnow);
122*11038SRao.Shoaib@Sun.COM #endif
123*11038SRao.Shoaib@Sun.COM 	if (gettimeofday(&now, NULL) < 0)
124*11038SRao.Shoaib@Sun.COM 		return (evConsTime(0, 0));
125*11038SRao.Shoaib@Sun.COM 	return (evTimeSpec(now));
126*11038SRao.Shoaib@Sun.COM }
127*11038SRao.Shoaib@Sun.COM 
128*11038SRao.Shoaib@Sun.COM struct timespec
evUTCTime()129*11038SRao.Shoaib@Sun.COM evUTCTime() {
130*11038SRao.Shoaib@Sun.COM 	struct timeval now;
131*11038SRao.Shoaib@Sun.COM #ifdef CLOCK_REALTIME
132*11038SRao.Shoaib@Sun.COM 	struct timespec tsnow;
133*11038SRao.Shoaib@Sun.COM 	if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
134*11038SRao.Shoaib@Sun.COM 		return (tsnow);
135*11038SRao.Shoaib@Sun.COM #endif
1360Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) < 0)
1370Sstevel@tonic-gate 		return (evConsTime(0, 0));
1380Sstevel@tonic-gate 	return (evTimeSpec(now));
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate struct timespec
evLastEventTime(evContext opaqueCtx)1420Sstevel@tonic-gate evLastEventTime(evContext opaqueCtx) {
1430Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	return (ctx->lastEventTime);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate struct timespec
evTimeSpec(struct timeval tv)1490Sstevel@tonic-gate evTimeSpec(struct timeval tv) {
1500Sstevel@tonic-gate 	struct timespec ts;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	ts.tv_sec = tv.tv_sec;
1530Sstevel@tonic-gate 	ts.tv_nsec = tv.tv_usec * 1000;
1540Sstevel@tonic-gate 	return (ts);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate struct timeval
evTimeVal(struct timespec ts)1580Sstevel@tonic-gate evTimeVal(struct timespec ts) {
1590Sstevel@tonic-gate 	struct timeval tv;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	tv.tv_sec = ts.tv_sec;
1620Sstevel@tonic-gate 	tv.tv_usec = ts.tv_nsec / 1000;
1630Sstevel@tonic-gate 	return (tv);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate int
evSetTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec due,struct timespec inter,evTimerID * opaqueID)1670Sstevel@tonic-gate evSetTimer(evContext opaqueCtx,
1680Sstevel@tonic-gate 	   evTimerFunc func,
1690Sstevel@tonic-gate 	   void *uap,
1700Sstevel@tonic-gate 	   struct timespec due,
1710Sstevel@tonic-gate 	   struct timespec inter,
1720Sstevel@tonic-gate 	   evTimerID *opaqueID
1730Sstevel@tonic-gate ) {
1740Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1750Sstevel@tonic-gate 	evTimer *id;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	evPrintf(ctx, 1,
1780Sstevel@tonic-gate "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
1790Sstevel@tonic-gate 		 ctx, func, uap,
1800Sstevel@tonic-gate 		 (long)due.tv_sec, due.tv_nsec,
1810Sstevel@tonic-gate 		 (long)inter.tv_sec, inter.tv_nsec);
1820Sstevel@tonic-gate 
183*11038SRao.Shoaib@Sun.COM #ifdef __hpux
184*11038SRao.Shoaib@Sun.COM 	/*
185*11038SRao.Shoaib@Sun.COM 	 * tv_sec and tv_nsec are unsigned.
186*11038SRao.Shoaib@Sun.COM 	 */
187*11038SRao.Shoaib@Sun.COM 	if (due.tv_nsec >= BILLION)
188*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
189*11038SRao.Shoaib@Sun.COM 
190*11038SRao.Shoaib@Sun.COM 	if (inter.tv_nsec >= BILLION)
191*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
192*11038SRao.Shoaib@Sun.COM #else
193*11038SRao.Shoaib@Sun.COM 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
194*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
195*11038SRao.Shoaib@Sun.COM 
196*11038SRao.Shoaib@Sun.COM 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
197*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
198*11038SRao.Shoaib@Sun.COM #endif
199*11038SRao.Shoaib@Sun.COM 
2000Sstevel@tonic-gate 	/* due={0,0} is a magic cookie meaning "now." */
201*11038SRao.Shoaib@Sun.COM 	if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
2020Sstevel@tonic-gate 		due = evNowTime();
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/* Allocate and fill. */
2050Sstevel@tonic-gate 	OKNEW(id);
2060Sstevel@tonic-gate 	id->func = func;
2070Sstevel@tonic-gate 	id->uap = uap;
2080Sstevel@tonic-gate 	id->due = due;
2090Sstevel@tonic-gate 	id->inter = inter;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	if (heap_insert(ctx->timers, id) < 0)
2120Sstevel@tonic-gate 		return (-1);
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	/* Remember the ID if the caller provided us a place for it. */
2150Sstevel@tonic-gate 	if (opaqueID)
2160Sstevel@tonic-gate 		opaqueID->opaque = id;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (ctx->debug > 7) {
2190Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evSetTimer:\n");
2200Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	return (0);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate int
evClearTimer(evContext opaqueCtx,evTimerID id)2270Sstevel@tonic-gate evClearTimer(evContext opaqueCtx, evTimerID id) {
2280Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2290Sstevel@tonic-gate 	evTimer *del = id.opaque;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	if (ctx->cur != NULL &&
2320Sstevel@tonic-gate 	    ctx->cur->type == Timer &&
2330Sstevel@tonic-gate 	    ctx->cur->u.timer.this == del) {
2340Sstevel@tonic-gate 		evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
2350Sstevel@tonic-gate 		/*
2360Sstevel@tonic-gate 		 * Setting the interval to zero ensures that evDrop() will
2370Sstevel@tonic-gate 		 * clean up the timer.
2380Sstevel@tonic-gate 		 */
2390Sstevel@tonic-gate 		del->inter = evConsTime(0, 0);
2400Sstevel@tonic-gate 		return (0);
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (heap_element(ctx->timers, del->index) != del)
2440Sstevel@tonic-gate 		EV_ERR(ENOENT);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (heap_delete(ctx->timers, del->index) < 0)
2470Sstevel@tonic-gate 		return (-1);
2480Sstevel@tonic-gate 	FREE(del);
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (ctx->debug > 7) {
2510Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evClearTimer:\n");
2520Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	return (0);
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate int
evConfigTimer(evContext opaqueCtx,evTimerID id,const char * param,int value)259*11038SRao.Shoaib@Sun.COM evConfigTimer(evContext opaqueCtx,
260*11038SRao.Shoaib@Sun.COM 	     evTimerID id,
261*11038SRao.Shoaib@Sun.COM 	     const char *param,
262*11038SRao.Shoaib@Sun.COM 	     int value
263*11038SRao.Shoaib@Sun.COM ) {
264*11038SRao.Shoaib@Sun.COM 	evContext_p *ctx = opaqueCtx.opaque;
265*11038SRao.Shoaib@Sun.COM 	evTimer *timer = id.opaque;
266*11038SRao.Shoaib@Sun.COM 	int result=0;
267*11038SRao.Shoaib@Sun.COM 
268*11038SRao.Shoaib@Sun.COM 	UNUSED(value);
269*11038SRao.Shoaib@Sun.COM 
270*11038SRao.Shoaib@Sun.COM 	if (heap_element(ctx->timers, timer->index) != timer)
271*11038SRao.Shoaib@Sun.COM 		EV_ERR(ENOENT);
272*11038SRao.Shoaib@Sun.COM 
273*11038SRao.Shoaib@Sun.COM 	if (strcmp(param, "rate") == 0)
274*11038SRao.Shoaib@Sun.COM 		timer->mode |= EV_TMR_RATE;
275*11038SRao.Shoaib@Sun.COM 	else if (strcmp(param, "interval") == 0)
276*11038SRao.Shoaib@Sun.COM 		timer->mode &= ~EV_TMR_RATE;
277*11038SRao.Shoaib@Sun.COM 	else
278*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
279*11038SRao.Shoaib@Sun.COM 
280*11038SRao.Shoaib@Sun.COM 	return (result);
281*11038SRao.Shoaib@Sun.COM }
282*11038SRao.Shoaib@Sun.COM 
283*11038SRao.Shoaib@Sun.COM int
evResetTimer(evContext opaqueCtx,evTimerID id,evTimerFunc func,void * uap,struct timespec due,struct timespec inter)2840Sstevel@tonic-gate evResetTimer(evContext opaqueCtx,
2850Sstevel@tonic-gate 	     evTimerID id,
2860Sstevel@tonic-gate 	     evTimerFunc func,
2870Sstevel@tonic-gate 	     void *uap,
2880Sstevel@tonic-gate 	     struct timespec due,
2890Sstevel@tonic-gate 	     struct timespec inter
2900Sstevel@tonic-gate ) {
2910Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2920Sstevel@tonic-gate 	evTimer *timer = id.opaque;
2930Sstevel@tonic-gate 	struct timespec old_due;
2940Sstevel@tonic-gate 	int result=0;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	if (heap_element(ctx->timers, timer->index) != timer)
2970Sstevel@tonic-gate 		EV_ERR(ENOENT);
2980Sstevel@tonic-gate 
299*11038SRao.Shoaib@Sun.COM #ifdef __hpux
300*11038SRao.Shoaib@Sun.COM 	/*
301*11038SRao.Shoaib@Sun.COM 	 * tv_sec and tv_nsec are unsigned.
302*11038SRao.Shoaib@Sun.COM 	 */
303*11038SRao.Shoaib@Sun.COM 	if (due.tv_nsec >= BILLION)
304*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
305*11038SRao.Shoaib@Sun.COM 
306*11038SRao.Shoaib@Sun.COM 	if (inter.tv_nsec >= BILLION)
307*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
308*11038SRao.Shoaib@Sun.COM #else
309*11038SRao.Shoaib@Sun.COM 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
310*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
311*11038SRao.Shoaib@Sun.COM 
312*11038SRao.Shoaib@Sun.COM 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
313*11038SRao.Shoaib@Sun.COM 		EV_ERR(EINVAL);
314*11038SRao.Shoaib@Sun.COM #endif
315*11038SRao.Shoaib@Sun.COM 
3160Sstevel@tonic-gate 	old_due = timer->due;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	timer->func = func;
3190Sstevel@tonic-gate 	timer->uap = uap;
3200Sstevel@tonic-gate 	timer->due = due;
3210Sstevel@tonic-gate 	timer->inter = inter;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	switch (evCmpTime(due, old_due)) {
3240Sstevel@tonic-gate 	case -1:
3250Sstevel@tonic-gate 		result = heap_increased(ctx->timers, timer->index);
3260Sstevel@tonic-gate 		break;
3270Sstevel@tonic-gate 	case 0:
3280Sstevel@tonic-gate 		result = 0;
3290Sstevel@tonic-gate 		break;
3300Sstevel@tonic-gate 	case 1:
3310Sstevel@tonic-gate 		result = heap_decreased(ctx->timers, timer->index);
3320Sstevel@tonic-gate 		break;
3330Sstevel@tonic-gate 	}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	if (ctx->debug > 7) {
3360Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evResetTimer:\n");
3370Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	return (result);
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate int
evSetIdleTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec max_idle,evTimerID * opaqueID)3440Sstevel@tonic-gate evSetIdleTimer(evContext opaqueCtx,
3450Sstevel@tonic-gate 		evTimerFunc func,
3460Sstevel@tonic-gate 		void *uap,
3470Sstevel@tonic-gate 		struct timespec max_idle,
3480Sstevel@tonic-gate 		evTimerID *opaqueID
3490Sstevel@tonic-gate ) {
3500Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
3510Sstevel@tonic-gate 	idle_timer *tt;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/* Allocate and fill. */
3540Sstevel@tonic-gate 	OKNEW(tt);
3550Sstevel@tonic-gate 	tt->func = func;
3560Sstevel@tonic-gate 	tt->uap = uap;
3570Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
3580Sstevel@tonic-gate 	tt->max_idle = max_idle;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	if (evSetTimer(opaqueCtx, idle_timeout, tt,
3610Sstevel@tonic-gate 		       evAddTime(ctx->lastEventTime, max_idle),
3620Sstevel@tonic-gate 		       max_idle, opaqueID) < 0) {
3630Sstevel@tonic-gate 		FREE(tt);
3640Sstevel@tonic-gate 		return (-1);
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	tt->timer = opaqueID->opaque;
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	return (0);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate int
evClearIdleTimer(evContext opaqueCtx,evTimerID id)3730Sstevel@tonic-gate evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
3740Sstevel@tonic-gate 	evTimer *del = id.opaque;
3750Sstevel@tonic-gate 	idle_timer *tt = del->uap;
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	FREE(tt);
3780Sstevel@tonic-gate 	return (evClearTimer(opaqueCtx, id));
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate int
evResetIdleTimer(evContext opaqueCtx,evTimerID opaqueID,evTimerFunc func,void * uap,struct timespec max_idle)3820Sstevel@tonic-gate evResetIdleTimer(evContext opaqueCtx,
3830Sstevel@tonic-gate 		 evTimerID opaqueID,
3840Sstevel@tonic-gate 		 evTimerFunc func,
3850Sstevel@tonic-gate 		 void *uap,
3860Sstevel@tonic-gate 		 struct timespec max_idle
3870Sstevel@tonic-gate ) {
3880Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
3890Sstevel@tonic-gate 	evTimer *timer = opaqueID.opaque;
3900Sstevel@tonic-gate 	idle_timer *tt = timer->uap;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	tt->func = func;
3930Sstevel@tonic-gate 	tt->uap = uap;
3940Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
3950Sstevel@tonic-gate 	tt->max_idle = max_idle;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
3980Sstevel@tonic-gate 			     evAddTime(ctx->lastEventTime, max_idle),
3990Sstevel@tonic-gate 			     max_idle));
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate int
evTouchIdleTimer(evContext opaqueCtx,evTimerID id)4030Sstevel@tonic-gate evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
4040Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
4050Sstevel@tonic-gate 	evTimer *t = id.opaque;
4060Sstevel@tonic-gate 	idle_timer *tt = t->uap;
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	return (0);
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate /* Public to the rest of eventlib. */
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate heap_context
evCreateTimers(const evContext_p * ctx)4160Sstevel@tonic-gate evCreateTimers(const evContext_p *ctx) {
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 	UNUSED(ctx);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	return (heap_new(due_sooner, set_index, 2048));
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate void
evDestroyTimers(const evContext_p * ctx)4240Sstevel@tonic-gate evDestroyTimers(const evContext_p *ctx) {
4250Sstevel@tonic-gate 	(void) heap_for_each(ctx->timers, free_timer, NULL);
4260Sstevel@tonic-gate 	(void) heap_free(ctx->timers);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate /* Private. */
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate static int
due_sooner(void * a,void * b)4320Sstevel@tonic-gate due_sooner(void *a, void *b) {
4330Sstevel@tonic-gate 	evTimer *a_timer, *b_timer;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	a_timer = a;
4360Sstevel@tonic-gate 	b_timer = b;
4370Sstevel@tonic-gate 	return (evCmpTime(a_timer->due, b_timer->due) < 0);
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate static void
set_index(void * what,int index)4410Sstevel@tonic-gate set_index(void *what, int index) {
4420Sstevel@tonic-gate 	evTimer *timer;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	timer = what;
4450Sstevel@tonic-gate 	timer->index = index;
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate static void
free_timer(void * what,void * uap)4490Sstevel@tonic-gate free_timer(void *what, void *uap) {
4500Sstevel@tonic-gate 	evTimer *t = what;
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	UNUSED(uap);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	FREE(t);
4550Sstevel@tonic-gate }
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate static void
print_timer(void * what,void * uap)4580Sstevel@tonic-gate print_timer(void *what, void *uap) {
4590Sstevel@tonic-gate 	evTimer *cur = what;
4600Sstevel@tonic-gate 	evContext_p *ctx = uap;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	cur = what;
4630Sstevel@tonic-gate 	evPrintf(ctx, 7,
4640Sstevel@tonic-gate 	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
4650Sstevel@tonic-gate 		 cur->func, cur->uap,
4660Sstevel@tonic-gate 		 (long)cur->due.tv_sec, cur->due.tv_nsec,
4670Sstevel@tonic-gate 		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate static void
idle_timeout(evContext opaqueCtx,void * uap,struct timespec due,struct timespec inter)4710Sstevel@tonic-gate idle_timeout(evContext opaqueCtx,
4720Sstevel@tonic-gate 	     void *uap,
4730Sstevel@tonic-gate 	     struct timespec due,
4740Sstevel@tonic-gate 	     struct timespec inter
4750Sstevel@tonic-gate ) {
4760Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
4770Sstevel@tonic-gate 	idle_timer *this = uap;
4780Sstevel@tonic-gate 	struct timespec idle;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	UNUSED(due);
4810Sstevel@tonic-gate 	UNUSED(inter);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
4840Sstevel@tonic-gate 	if (evCmpTime(idle, this->max_idle) >= 0) {
4850Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->timer->due,
4860Sstevel@tonic-gate 			     this->max_idle);
4870Sstevel@tonic-gate 		/*
4880Sstevel@tonic-gate 		 * Setting the interval to zero will cause the timer to
4890Sstevel@tonic-gate 		 * be cleaned up in evDrop().
4900Sstevel@tonic-gate 		 */
4910Sstevel@tonic-gate 		this->timer->inter = evConsTime(0, 0);
4920Sstevel@tonic-gate 		FREE(this);
4930Sstevel@tonic-gate 	} else {
4940Sstevel@tonic-gate 		/* evDrop() will reschedule the timer. */
4950Sstevel@tonic-gate 		this->timer->inter = evSubTime(this->max_idle, idle);
4960Sstevel@tonic-gate 	}
4970Sstevel@tonic-gate }
498*11038SRao.Shoaib@Sun.COM 
499*11038SRao.Shoaib@Sun.COM /*! \file */
500