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