17c478bd9Sstevel@tonic-gate /*
29525b14bSRao Shoaib  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
37c478bd9Sstevel@tonic-gate  * Copyright (c) 1995-1999 by Internet Software Consortium
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
67c478bd9Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
77c478bd9Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
87c478bd9Sstevel@tonic-gate  *
99525b14bSRao Shoaib  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
109525b14bSRao Shoaib  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119525b14bSRao Shoaib  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
129525b14bSRao Shoaib  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139525b14bSRao Shoaib  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149525b14bSRao Shoaib  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
159525b14bSRao Shoaib  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
167c478bd9Sstevel@tonic-gate  */
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate /* ev_timers.c - implement timers for the eventlib
197c478bd9Sstevel@tonic-gate  * vix 09sep95 [initial]
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate #include "port_before.h"
237c478bd9Sstevel@tonic-gate #include "fd_setsize.h"
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <errno.h>
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <isc/assertions.h>
287c478bd9Sstevel@tonic-gate #include <isc/eventlib.h>
297c478bd9Sstevel@tonic-gate #include "eventlib_p.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "port_after.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate /* Constants. */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #define	MILLION 1000000
367c478bd9Sstevel@tonic-gate #define BILLION 1000000000
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /* Forward. */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static int due_sooner(void *, void *);
417c478bd9Sstevel@tonic-gate static void set_index(void *, int);
427c478bd9Sstevel@tonic-gate static void free_timer(void *, void *);
437c478bd9Sstevel@tonic-gate static void print_timer(void *, void *);
447c478bd9Sstevel@tonic-gate static void idle_timeout(evContext, void *, struct timespec, struct timespec);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate /* Private type. */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate typedef struct {
497c478bd9Sstevel@tonic-gate 	evTimerFunc	func;
507c478bd9Sstevel@tonic-gate 	void *		uap;
517c478bd9Sstevel@tonic-gate 	struct timespec	lastTouched;
527c478bd9Sstevel@tonic-gate 	struct timespec	max_idle;
537c478bd9Sstevel@tonic-gate 	evTimer *	timer;
547c478bd9Sstevel@tonic-gate } idle_timer;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Public. */
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate struct timespec
evConsTime(time_t sec,long nsec)597c478bd9Sstevel@tonic-gate evConsTime(time_t sec, long nsec) {
607c478bd9Sstevel@tonic-gate 	struct timespec x;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	x.tv_sec = sec;
637c478bd9Sstevel@tonic-gate 	x.tv_nsec = nsec;
647c478bd9Sstevel@tonic-gate 	return (x);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate struct timespec
evAddTime(struct timespec addend1,struct timespec addend2)687c478bd9Sstevel@tonic-gate evAddTime(struct timespec addend1, struct timespec addend2) {
697c478bd9Sstevel@tonic-gate 	struct timespec x;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
727c478bd9Sstevel@tonic-gate 	x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
737c478bd9Sstevel@tonic-gate 	if (x.tv_nsec >= BILLION) {
747c478bd9Sstevel@tonic-gate 		x.tv_sec++;
757c478bd9Sstevel@tonic-gate 		x.tv_nsec -= BILLION;
767c478bd9Sstevel@tonic-gate 	}
777c478bd9Sstevel@tonic-gate 	return (x);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate struct timespec
evSubTime(struct timespec minuend,struct timespec subtrahend)817c478bd9Sstevel@tonic-gate evSubTime(struct timespec minuend, struct timespec subtrahend) {
827c478bd9Sstevel@tonic-gate 	struct timespec x;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
857c478bd9Sstevel@tonic-gate 	if (minuend.tv_nsec >= subtrahend.tv_nsec)
867c478bd9Sstevel@tonic-gate 		x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
877c478bd9Sstevel@tonic-gate 	else {
887c478bd9Sstevel@tonic-gate 		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
897c478bd9Sstevel@tonic-gate 		x.tv_sec--;
907c478bd9Sstevel@tonic-gate 	}
917c478bd9Sstevel@tonic-gate 	return (x);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate int
evCmpTime(struct timespec a,struct timespec b)957c478bd9Sstevel@tonic-gate evCmpTime(struct timespec a, struct timespec b) {
967c478bd9Sstevel@tonic-gate 	long x = a.tv_sec - b.tv_sec;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (x == 0L)
997c478bd9Sstevel@tonic-gate 		x = a.tv_nsec - b.tv_nsec;
1007c478bd9Sstevel@tonic-gate 	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate struct timespec
evNowTime()1047c478bd9Sstevel@tonic-gate evNowTime() {
1057c478bd9Sstevel@tonic-gate 	struct timeval now;
1069525b14bSRao Shoaib #ifdef CLOCK_REALTIME
1079525b14bSRao Shoaib 	struct timespec tsnow;
1089525b14bSRao Shoaib 	int m = CLOCK_REALTIME;
1097c478bd9Sstevel@tonic-gate 
1109525b14bSRao Shoaib #ifdef CLOCK_MONOTONIC
1119525b14bSRao Shoaib 	if (__evOptMonoTime)
1129525b14bSRao Shoaib 		m = CLOCK_MONOTONIC;
1139525b14bSRao Shoaib #endif
1149525b14bSRao Shoaib 	if (clock_gettime(m, &tsnow) == 0)
1159525b14bSRao Shoaib 		return (tsnow);
1169525b14bSRao Shoaib #endif
1179525b14bSRao Shoaib 	if (gettimeofday(&now, NULL) < 0)
1189525b14bSRao Shoaib 		return (evConsTime(0, 0));
1199525b14bSRao Shoaib 	return (evTimeSpec(now));
1209525b14bSRao Shoaib }
1219525b14bSRao Shoaib 
1229525b14bSRao Shoaib struct timespec
evUTCTime()1239525b14bSRao Shoaib evUTCTime() {
1249525b14bSRao Shoaib 	struct timeval now;
1259525b14bSRao Shoaib #ifdef CLOCK_REALTIME
1269525b14bSRao Shoaib 	struct timespec tsnow;
1279525b14bSRao Shoaib 	if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
1289525b14bSRao Shoaib 		return (tsnow);
1299525b14bSRao Shoaib #endif
1307c478bd9Sstevel@tonic-gate 	if (gettimeofday(&now, NULL) < 0)
1317c478bd9Sstevel@tonic-gate 		return (evConsTime(0, 0));
1327c478bd9Sstevel@tonic-gate 	return (evTimeSpec(now));
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate struct timespec
evLastEventTime(evContext opaqueCtx)1367c478bd9Sstevel@tonic-gate evLastEventTime(evContext opaqueCtx) {
1377c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	return (ctx->lastEventTime);
1407c478bd9Sstevel@tonic-gate }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate struct timespec
evTimeSpec(struct timeval tv)1437c478bd9Sstevel@tonic-gate evTimeSpec(struct timeval tv) {
1447c478bd9Sstevel@tonic-gate 	struct timespec ts;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	ts.tv_sec = tv.tv_sec;
1477c478bd9Sstevel@tonic-gate 	ts.tv_nsec = tv.tv_usec * 1000;
1487c478bd9Sstevel@tonic-gate 	return (ts);
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate struct timeval
evTimeVal(struct timespec ts)1527c478bd9Sstevel@tonic-gate evTimeVal(struct timespec ts) {
1537c478bd9Sstevel@tonic-gate 	struct timeval tv;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	tv.tv_sec = ts.tv_sec;
1567c478bd9Sstevel@tonic-gate 	tv.tv_usec = ts.tv_nsec / 1000;
1577c478bd9Sstevel@tonic-gate 	return (tv);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate int
evSetTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec due,struct timespec inter,evTimerID * opaqueID)1617c478bd9Sstevel@tonic-gate evSetTimer(evContext opaqueCtx,
1627c478bd9Sstevel@tonic-gate 	   evTimerFunc func,
1637c478bd9Sstevel@tonic-gate 	   void *uap,
1647c478bd9Sstevel@tonic-gate 	   struct timespec due,
1657c478bd9Sstevel@tonic-gate 	   struct timespec inter,
1667c478bd9Sstevel@tonic-gate 	   evTimerID *opaqueID
1677c478bd9Sstevel@tonic-gate ) {
1687c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
1697c478bd9Sstevel@tonic-gate 	evTimer *id;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	evPrintf(ctx, 1,
1727c478bd9Sstevel@tonic-gate "evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
1737c478bd9Sstevel@tonic-gate 		 ctx, func, uap,
1747c478bd9Sstevel@tonic-gate 		 (long)due.tv_sec, due.tv_nsec,
1757c478bd9Sstevel@tonic-gate 		 (long)inter.tv_sec, inter.tv_nsec);
1767c478bd9Sstevel@tonic-gate 
1779525b14bSRao Shoaib #ifdef __hpux
1789525b14bSRao Shoaib 	/*
1799525b14bSRao Shoaib 	 * tv_sec and tv_nsec are unsigned.
1809525b14bSRao Shoaib 	 */
1819525b14bSRao Shoaib 	if (due.tv_nsec >= BILLION)
1829525b14bSRao Shoaib 		EV_ERR(EINVAL);
1839525b14bSRao Shoaib 
1849525b14bSRao Shoaib 	if (inter.tv_nsec >= BILLION)
1859525b14bSRao Shoaib 		EV_ERR(EINVAL);
1869525b14bSRao Shoaib #else
1879525b14bSRao Shoaib 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
1889525b14bSRao Shoaib 		EV_ERR(EINVAL);
1899525b14bSRao Shoaib 
1909525b14bSRao Shoaib 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
1919525b14bSRao Shoaib 		EV_ERR(EINVAL);
1929525b14bSRao Shoaib #endif
1939525b14bSRao Shoaib 
1947c478bd9Sstevel@tonic-gate 	/* due={0,0} is a magic cookie meaning "now." */
1959525b14bSRao Shoaib 	if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
1967c478bd9Sstevel@tonic-gate 		due = evNowTime();
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	/* Allocate and fill. */
1997c478bd9Sstevel@tonic-gate 	OKNEW(id);
2007c478bd9Sstevel@tonic-gate 	id->func = func;
2017c478bd9Sstevel@tonic-gate 	id->uap = uap;
2027c478bd9Sstevel@tonic-gate 	id->due = due;
2037c478bd9Sstevel@tonic-gate 	id->inter = inter;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (heap_insert(ctx->timers, id) < 0)
2067c478bd9Sstevel@tonic-gate 		return (-1);
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	/* Remember the ID if the caller provided us a place for it. */
2097c478bd9Sstevel@tonic-gate 	if (opaqueID)
2107c478bd9Sstevel@tonic-gate 		opaqueID->opaque = id;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if (ctx->debug > 7) {
2137c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evSetTimer:\n");
2147c478bd9Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	return (0);
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate int
evClearTimer(evContext opaqueCtx,evTimerID id)2217c478bd9Sstevel@tonic-gate evClearTimer(evContext opaqueCtx, evTimerID id) {
2227c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2237c478bd9Sstevel@tonic-gate 	evTimer *del = id.opaque;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (ctx->cur != NULL &&
2267c478bd9Sstevel@tonic-gate 	    ctx->cur->type == Timer &&
2277c478bd9Sstevel@tonic-gate 	    ctx->cur->u.timer.this == del) {
2287c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
2297c478bd9Sstevel@tonic-gate 		/*
2307c478bd9Sstevel@tonic-gate 		 * Setting the interval to zero ensures that evDrop() will
2317c478bd9Sstevel@tonic-gate 		 * clean up the timer.
2327c478bd9Sstevel@tonic-gate 		 */
2337c478bd9Sstevel@tonic-gate 		del->inter = evConsTime(0, 0);
2347c478bd9Sstevel@tonic-gate 		return (0);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if (heap_element(ctx->timers, del->index) != del)
2387c478bd9Sstevel@tonic-gate 		EV_ERR(ENOENT);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (heap_delete(ctx->timers, del->index) < 0)
2417c478bd9Sstevel@tonic-gate 		return (-1);
2427c478bd9Sstevel@tonic-gate 	FREE(del);
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (ctx->debug > 7) {
2457c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evClearTimer:\n");
2467c478bd9Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	return (0);
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2529525b14bSRao Shoaib int
evConfigTimer(evContext opaqueCtx,evTimerID id,const char * param,int value)2539525b14bSRao Shoaib evConfigTimer(evContext opaqueCtx,
2549525b14bSRao Shoaib 	     evTimerID id,
2559525b14bSRao Shoaib 	     const char *param,
2569525b14bSRao Shoaib 	     int value
2579525b14bSRao Shoaib ) {
2589525b14bSRao Shoaib 	evContext_p *ctx = opaqueCtx.opaque;
2599525b14bSRao Shoaib 	evTimer *timer = id.opaque;
2609525b14bSRao Shoaib 	int result=0;
2619525b14bSRao Shoaib 
2629525b14bSRao Shoaib 	UNUSED(value);
2639525b14bSRao Shoaib 
2649525b14bSRao Shoaib 	if (heap_element(ctx->timers, timer->index) != timer)
2659525b14bSRao Shoaib 		EV_ERR(ENOENT);
2669525b14bSRao Shoaib 
2679525b14bSRao Shoaib 	if (strcmp(param, "rate") == 0)
2689525b14bSRao Shoaib 		timer->mode |= EV_TMR_RATE;
2699525b14bSRao Shoaib 	else if (strcmp(param, "interval") == 0)
2709525b14bSRao Shoaib 		timer->mode &= ~EV_TMR_RATE;
2719525b14bSRao Shoaib 	else
2729525b14bSRao Shoaib 		EV_ERR(EINVAL);
2739525b14bSRao Shoaib 
2749525b14bSRao Shoaib 	return (result);
2759525b14bSRao Shoaib }
2769525b14bSRao Shoaib 
2777c478bd9Sstevel@tonic-gate int
evResetTimer(evContext opaqueCtx,evTimerID id,evTimerFunc func,void * uap,struct timespec due,struct timespec inter)2787c478bd9Sstevel@tonic-gate evResetTimer(evContext opaqueCtx,
2797c478bd9Sstevel@tonic-gate 	     evTimerID id,
2807c478bd9Sstevel@tonic-gate 	     evTimerFunc func,
2817c478bd9Sstevel@tonic-gate 	     void *uap,
2827c478bd9Sstevel@tonic-gate 	     struct timespec due,
2837c478bd9Sstevel@tonic-gate 	     struct timespec inter
2847c478bd9Sstevel@tonic-gate ) {
2857c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
2867c478bd9Sstevel@tonic-gate 	evTimer *timer = id.opaque;
2877c478bd9Sstevel@tonic-gate 	struct timespec old_due;
2887c478bd9Sstevel@tonic-gate 	int result=0;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (heap_element(ctx->timers, timer->index) != timer)
2917c478bd9Sstevel@tonic-gate 		EV_ERR(ENOENT);
2927c478bd9Sstevel@tonic-gate 
2939525b14bSRao Shoaib #ifdef __hpux
2949525b14bSRao Shoaib 	/*
2959525b14bSRao Shoaib 	 * tv_sec and tv_nsec are unsigned.
2969525b14bSRao Shoaib 	 */
2979525b14bSRao Shoaib 	if (due.tv_nsec >= BILLION)
2989525b14bSRao Shoaib 		EV_ERR(EINVAL);
2999525b14bSRao Shoaib 
3009525b14bSRao Shoaib 	if (inter.tv_nsec >= BILLION)
3019525b14bSRao Shoaib 		EV_ERR(EINVAL);
3029525b14bSRao Shoaib #else
3039525b14bSRao Shoaib 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
3049525b14bSRao Shoaib 		EV_ERR(EINVAL);
3059525b14bSRao Shoaib 
3069525b14bSRao Shoaib 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
3079525b14bSRao Shoaib 		EV_ERR(EINVAL);
3089525b14bSRao Shoaib #endif
3099525b14bSRao Shoaib 
3107c478bd9Sstevel@tonic-gate 	old_due = timer->due;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	timer->func = func;
3137c478bd9Sstevel@tonic-gate 	timer->uap = uap;
3147c478bd9Sstevel@tonic-gate 	timer->due = due;
3157c478bd9Sstevel@tonic-gate 	timer->inter = inter;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	switch (evCmpTime(due, old_due)) {
3187c478bd9Sstevel@tonic-gate 	case -1:
3197c478bd9Sstevel@tonic-gate 		result = heap_increased(ctx->timers, timer->index);
3207c478bd9Sstevel@tonic-gate 		break;
3217c478bd9Sstevel@tonic-gate 	case 0:
3227c478bd9Sstevel@tonic-gate 		result = 0;
3237c478bd9Sstevel@tonic-gate 		break;
3247c478bd9Sstevel@tonic-gate 	case 1:
3257c478bd9Sstevel@tonic-gate 		result = heap_decreased(ctx->timers, timer->index);
3267c478bd9Sstevel@tonic-gate 		break;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if (ctx->debug > 7) {
3307c478bd9Sstevel@tonic-gate 		evPrintf(ctx, 7, "timers after evResetTimer:\n");
3317c478bd9Sstevel@tonic-gate 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
3327c478bd9Sstevel@tonic-gate 	}
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	return (result);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate int
evSetIdleTimer(evContext opaqueCtx,evTimerFunc func,void * uap,struct timespec max_idle,evTimerID * opaqueID)3387c478bd9Sstevel@tonic-gate evSetIdleTimer(evContext opaqueCtx,
3397c478bd9Sstevel@tonic-gate 		evTimerFunc func,
3407c478bd9Sstevel@tonic-gate 		void *uap,
3417c478bd9Sstevel@tonic-gate 		struct timespec max_idle,
3427c478bd9Sstevel@tonic-gate 		evTimerID *opaqueID
3437c478bd9Sstevel@tonic-gate ) {
3447c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
3457c478bd9Sstevel@tonic-gate 	idle_timer *tt;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/* Allocate and fill. */
3487c478bd9Sstevel@tonic-gate 	OKNEW(tt);
3497c478bd9Sstevel@tonic-gate 	tt->func = func;
3507c478bd9Sstevel@tonic-gate 	tt->uap = uap;
3517c478bd9Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
3527c478bd9Sstevel@tonic-gate 	tt->max_idle = max_idle;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (evSetTimer(opaqueCtx, idle_timeout, tt,
3557c478bd9Sstevel@tonic-gate 		       evAddTime(ctx->lastEventTime, max_idle),
3567c478bd9Sstevel@tonic-gate 		       max_idle, opaqueID) < 0) {
3577c478bd9Sstevel@tonic-gate 		FREE(tt);
3587c478bd9Sstevel@tonic-gate 		return (-1);
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	tt->timer = opaqueID->opaque;
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	return (0);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate int
evClearIdleTimer(evContext opaqueCtx,evTimerID id)3677c478bd9Sstevel@tonic-gate evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
3687c478bd9Sstevel@tonic-gate 	evTimer *del = id.opaque;
3697c478bd9Sstevel@tonic-gate 	idle_timer *tt = del->uap;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	FREE(tt);
3727c478bd9Sstevel@tonic-gate 	return (evClearTimer(opaqueCtx, id));
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate int
evResetIdleTimer(evContext opaqueCtx,evTimerID opaqueID,evTimerFunc func,void * uap,struct timespec max_idle)3767c478bd9Sstevel@tonic-gate evResetIdleTimer(evContext opaqueCtx,
3777c478bd9Sstevel@tonic-gate 		 evTimerID opaqueID,
3787c478bd9Sstevel@tonic-gate 		 evTimerFunc func,
3797c478bd9Sstevel@tonic-gate 		 void *uap,
3807c478bd9Sstevel@tonic-gate 		 struct timespec max_idle
3817c478bd9Sstevel@tonic-gate ) {
3827c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
3837c478bd9Sstevel@tonic-gate 	evTimer *timer = opaqueID.opaque;
3847c478bd9Sstevel@tonic-gate 	idle_timer *tt = timer->uap;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	tt->func = func;
3877c478bd9Sstevel@tonic-gate 	tt->uap = uap;
3887c478bd9Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
3897c478bd9Sstevel@tonic-gate 	tt->max_idle = max_idle;
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
3927c478bd9Sstevel@tonic-gate 			     evAddTime(ctx->lastEventTime, max_idle),
3937c478bd9Sstevel@tonic-gate 			     max_idle));
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate int
evTouchIdleTimer(evContext opaqueCtx,evTimerID id)3977c478bd9Sstevel@tonic-gate evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
3987c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
3997c478bd9Sstevel@tonic-gate 	evTimer *t = id.opaque;
4007c478bd9Sstevel@tonic-gate 	idle_timer *tt = t->uap;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	tt->lastTouched = ctx->lastEventTime;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	return (0);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /* Public to the rest of eventlib. */
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate heap_context
evCreateTimers(const evContext_p * ctx)4107c478bd9Sstevel@tonic-gate evCreateTimers(const evContext_p *ctx) {
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	UNUSED(ctx);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	return (heap_new(due_sooner, set_index, 2048));
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate void
evDestroyTimers(const evContext_p * ctx)4187c478bd9Sstevel@tonic-gate evDestroyTimers(const evContext_p *ctx) {
4197c478bd9Sstevel@tonic-gate 	(void) heap_for_each(ctx->timers, free_timer, NULL);
4207c478bd9Sstevel@tonic-gate 	(void) heap_free(ctx->timers);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /* Private. */
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate static int
due_sooner(void * a,void * b)4267c478bd9Sstevel@tonic-gate due_sooner(void *a, void *b) {
4277c478bd9Sstevel@tonic-gate 	evTimer *a_timer, *b_timer;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	a_timer = a;
4307c478bd9Sstevel@tonic-gate 	b_timer = b;
4317c478bd9Sstevel@tonic-gate 	return (evCmpTime(a_timer->due, b_timer->due) < 0);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate static void
set_index(void * what,int index)4357c478bd9Sstevel@tonic-gate set_index(void *what, int index) {
4367c478bd9Sstevel@tonic-gate 	evTimer *timer;
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	timer = what;
4397c478bd9Sstevel@tonic-gate 	timer->index = index;
4407c478bd9Sstevel@tonic-gate }
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate static void
free_timer(void * what,void * uap)4437c478bd9Sstevel@tonic-gate free_timer(void *what, void *uap) {
4447c478bd9Sstevel@tonic-gate 	evTimer *t = what;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	UNUSED(uap);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	FREE(t);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate static void
print_timer(void * what,void * uap)4527c478bd9Sstevel@tonic-gate print_timer(void *what, void *uap) {
4537c478bd9Sstevel@tonic-gate 	evTimer *cur = what;
4547c478bd9Sstevel@tonic-gate 	evContext_p *ctx = uap;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	cur = what;
4577c478bd9Sstevel@tonic-gate 	evPrintf(ctx, 7,
4587c478bd9Sstevel@tonic-gate 	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
4597c478bd9Sstevel@tonic-gate 		 cur->func, cur->uap,
4607c478bd9Sstevel@tonic-gate 		 (long)cur->due.tv_sec, cur->due.tv_nsec,
4617c478bd9Sstevel@tonic-gate 		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static void
idle_timeout(evContext opaqueCtx,void * uap,struct timespec due,struct timespec inter)4657c478bd9Sstevel@tonic-gate idle_timeout(evContext opaqueCtx,
4667c478bd9Sstevel@tonic-gate 	     void *uap,
4677c478bd9Sstevel@tonic-gate 	     struct timespec due,
4687c478bd9Sstevel@tonic-gate 	     struct timespec inter
4697c478bd9Sstevel@tonic-gate ) {
4707c478bd9Sstevel@tonic-gate 	evContext_p *ctx = opaqueCtx.opaque;
4717c478bd9Sstevel@tonic-gate 	idle_timer *this = uap;
4727c478bd9Sstevel@tonic-gate 	struct timespec idle;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	UNUSED(due);
4757c478bd9Sstevel@tonic-gate 	UNUSED(inter);
476*55fea89dSDan Cross 
4777c478bd9Sstevel@tonic-gate 	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
4787c478bd9Sstevel@tonic-gate 	if (evCmpTime(idle, this->max_idle) >= 0) {
4797c478bd9Sstevel@tonic-gate 		(this->func)(opaqueCtx, this->uap, this->timer->due,
4807c478bd9Sstevel@tonic-gate 			     this->max_idle);
4817c478bd9Sstevel@tonic-gate 		/*
4827c478bd9Sstevel@tonic-gate 		 * Setting the interval to zero will cause the timer to
4837c478bd9Sstevel@tonic-gate 		 * be cleaned up in evDrop().
4847c478bd9Sstevel@tonic-gate 		 */
4857c478bd9Sstevel@tonic-gate 		this->timer->inter = evConsTime(0, 0);
4867c478bd9Sstevel@tonic-gate 		FREE(this);
4877c478bd9Sstevel@tonic-gate 	} else {
4887c478bd9Sstevel@tonic-gate 		/* evDrop() will reschedule the timer. */
4897c478bd9Sstevel@tonic-gate 		this->timer->inter = evSubTime(this->max_idle, idle);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate }
4929525b14bSRao Shoaib 
4939525b14bSRao Shoaib /*! \file */
494