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