1 /* $NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $ */
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1995-1999 by Internet Software Consortium
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 /* ev_timers.c - implement timers for the eventlib
21 * vix 09sep95 [initial]
25 * This version of this file is derived from Android 2.3 "Gingerbread",
26 * which contains uncredited changes by Android/Google developers. It has
27 * been modified in 2011 for use in the Android build of Mozilla Firefox by
28 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
29 * and Steve Workman <sjhworkman@gmail.com>).
30 * These changes are offered under the same license as the original NetBSD
31 * file, whose copyright and license are unchanged above.
34 #define ANDROID_CHANGES 1
35 #define MOZILLA_NECKO_EXCLUDE_CODE 1
37 #include <sys/cdefs.h>
38 #if !defined(LINT) && !defined(CODECENTER) && !defined(lint)
40 static const char rcsid
[] = "Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp";
42 __RCSID("$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $");
51 #include "assertions.h"
53 #include "eventlib_p.h"
57 #define MILLION 1000000
58 #define BILLION 1000000000
63 static int due_sooner(void *, void *);
64 static void set_index(void *, int);
65 static void free_timer(void *, void *);
66 static void print_timer(void *, void *);
67 static void idle_timeout(evContext
, void *, struct timespec
, struct timespec
);
74 struct timespec lastTouched
;
75 struct timespec max_idle
;
83 evConsTime(time_t sec
, long nsec
) {
92 evAddTime(struct timespec addend1
, struct timespec addend2
) {
95 x
.tv_sec
= addend1
.tv_sec
+ addend2
.tv_sec
;
96 x
.tv_nsec
= addend1
.tv_nsec
+ addend2
.tv_nsec
;
97 if (x
.tv_nsec
>= BILLION
) {
105 evSubTime(struct timespec minuend
, struct timespec subtrahend
) {
108 x
.tv_sec
= minuend
.tv_sec
- subtrahend
.tv_sec
;
109 if (minuend
.tv_nsec
>= subtrahend
.tv_nsec
)
110 x
.tv_nsec
= minuend
.tv_nsec
- subtrahend
.tv_nsec
;
112 x
.tv_nsec
= BILLION
- subtrahend
.tv_nsec
+ minuend
.tv_nsec
;
119 evCmpTime(struct timespec a
, struct timespec b
) {
120 long x
= a
.tv_sec
- b
.tv_sec
;
123 x
= a
.tv_nsec
- b
.tv_nsec
;
124 return (x
< 0L ? (-1) : x
> 0L ? (1) : (0));
130 #ifdef CLOCK_REALTIME
131 struct timespec tsnow
;
132 int m
= CLOCK_REALTIME
;
134 #ifdef CLOCK_MONOTONIC
138 if (clock_gettime(m
, &tsnow
) == 0)
141 if (gettimeofday(&now
, NULL
) < 0)
142 return (evConsTime(0L, 0L));
143 return (evTimeSpec(now
));
146 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
150 #ifdef CLOCK_REALTIME
151 struct timespec tsnow
;
152 if (clock_gettime(CLOCK_REALTIME
, &tsnow
) == 0)
155 if (gettimeofday(&now
, NULL
) < 0)
156 return (evConsTime(0L, 0L));
157 return (evTimeSpec(now
));
162 evLastEventTime(evContext opaqueCtx
) {
163 evContext_p
*ctx
= opaqueCtx
.opaque
;
165 return (ctx
->lastEventTime
);
171 evTimeSpec(struct timeval tv
) {
174 ts
.tv_sec
= tv
.tv_sec
;
175 ts
.tv_nsec
= tv
.tv_usec
* 1000;
179 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
181 evTimeVal(struct timespec ts
) {
184 tv
.tv_sec
= ts
.tv_sec
;
185 tv
.tv_usec
= ts
.tv_nsec
/ 1000;
191 evSetTimer(evContext opaqueCtx
,
195 struct timespec inter
,
198 evContext_p
*ctx
= opaqueCtx
.opaque
;
201 printf("evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
203 (long)due
.tv_sec
, due
.tv_nsec
,
204 (long)inter
.tv_sec
, inter
.tv_nsec
);
208 * tv_sec and tv_nsec are unsigned.
210 if (due
.tv_nsec
>= BILLION
)
213 if (inter
.tv_nsec
>= BILLION
)
216 if (due
.tv_sec
< 0 || due
.tv_nsec
< 0 || due
.tv_nsec
>= BILLION
)
219 if (inter
.tv_sec
< 0 || inter
.tv_nsec
< 0 || inter
.tv_nsec
>= BILLION
)
223 /* due={0,0} is a magic cookie meaning "now." */
224 if (due
.tv_sec
== (time_t)0 && due
.tv_nsec
== 0L)
227 /* Allocate and fill. */
234 if (heap_insert(ctx
->timers
, id
) < 0)
237 /* Remember the ID if the caller provided us a place for it. */
239 opaqueID
->opaque
= id
;
241 if (ctx
->debug
> 7) {
242 printf("timers after evSetTimer:\n");
243 (void) heap_for_each(ctx
->timers
, print_timer
, (void *)ctx
);
250 evClearTimer(evContext opaqueCtx
, evTimerID id
) {
251 evContext_p
*ctx
= opaqueCtx
.opaque
;
252 evTimer
*del
= id
.opaque
;
254 if (ctx
->cur
!= NULL
&&
255 ctx
->cur
->type
== Timer
&&
256 ctx
->cur
->u
.timer
.this == del
) {
257 printf("deferring delete of timer (executing)\n");
259 * Setting the interval to zero ensures that evDrop() will
260 * clean up the timer.
262 del
->inter
= evConsTime(0, 0);
266 if (heap_element(ctx
->timers
, del
->index
) != del
)
269 if (heap_delete(ctx
->timers
, del
->index
) < 0)
273 if (ctx
->debug
> 7) {
274 printf("timers after evClearTimer:\n");
275 (void) heap_for_each(ctx
->timers
, print_timer
, (void *)ctx
);
282 evConfigTimer(evContext opaqueCtx
,
287 evContext_p
*ctx
= opaqueCtx
.opaque
;
288 evTimer
*timer
= id
.opaque
;
293 if (heap_element(ctx
->timers
, timer
->index
) != timer
)
296 if (strcmp(param
, "rate") == 0)
297 timer
->mode
|= EV_TMR_RATE
;
298 else if (strcmp(param
, "interval") == 0)
299 timer
->mode
&= ~EV_TMR_RATE
;
307 evResetTimer(evContext opaqueCtx
,
312 struct timespec inter
314 evContext_p
*ctx
= opaqueCtx
.opaque
;
315 evTimer
*timer
= id
.opaque
;
316 struct timespec old_due
;
319 if (heap_element(ctx
->timers
, timer
->index
) != timer
)
324 * tv_sec and tv_nsec are unsigned.
326 if (due
.tv_nsec
>= BILLION
)
329 if (inter
.tv_nsec
>= BILLION
)
332 if (due
.tv_sec
< 0 || due
.tv_nsec
< 0 || due
.tv_nsec
>= BILLION
)
335 if (inter
.tv_sec
< 0 || inter
.tv_nsec
< 0 || inter
.tv_nsec
>= BILLION
)
339 old_due
= timer
->due
;
344 timer
->inter
= inter
;
346 switch (evCmpTime(due
, old_due
)) {
348 result
= heap_increased(ctx
->timers
, timer
->index
);
354 result
= heap_decreased(ctx
->timers
, timer
->index
);
358 if (ctx
->debug
> 7) {
359 printf("timers after evResetTimer:\n");
360 (void) heap_for_each(ctx
->timers
, print_timer
, (void *)ctx
);
367 evSetIdleTimer(evContext opaqueCtx
,
370 struct timespec max_idle
,
373 evContext_p
*ctx
= opaqueCtx
.opaque
;
376 /* Allocate and fill. */
380 tt
->lastTouched
= ctx
->lastEventTime
;
381 tt
->max_idle
= max_idle
;
383 if (evSetTimer(opaqueCtx
, idle_timeout
, tt
,
384 evAddTime(ctx
->lastEventTime
, max_idle
),
385 max_idle
, opaqueID
) < 0) {
390 tt
->timer
= opaqueID
->opaque
;
396 evClearIdleTimer(evContext opaqueCtx
, evTimerID id
) {
397 evTimer
*del
= id
.opaque
;
398 idle_timer
*tt
= del
->uap
;
401 return (evClearTimer(opaqueCtx
, id
));
405 evResetIdleTimer(evContext opaqueCtx
,
409 struct timespec max_idle
411 evContext_p
*ctx
= opaqueCtx
.opaque
;
412 evTimer
*timer
= opaqueID
.opaque
;
413 idle_timer
*tt
= timer
->uap
;
417 tt
->lastTouched
= ctx
->lastEventTime
;
418 tt
->max_idle
= max_idle
;
420 return (evResetTimer(opaqueCtx
, opaqueID
, idle_timeout
, tt
,
421 evAddTime(ctx
->lastEventTime
, max_idle
),
426 evTouchIdleTimer(evContext opaqueCtx
, evTimerID id
) {
427 evContext_p
*ctx
= opaqueCtx
.opaque
;
428 evTimer
*t
= id
.opaque
;
429 idle_timer
*tt
= t
->uap
;
431 tt
->lastTouched
= ctx
->lastEventTime
;
436 /* Public to the rest of eventlib. */
439 evCreateTimers(const evContext_p
*ctx
) {
443 return (heap_new(due_sooner
, set_index
, 2048));
447 evDestroyTimers(const evContext_p
*ctx
) {
448 (void) heap_for_each(ctx
->timers
, free_timer
, NULL
);
449 (void) heap_free(ctx
->timers
);
455 due_sooner(void *a
, void *b
) {
456 evTimer
*a_timer
, *b_timer
;
460 return (evCmpTime(a_timer
->due
, b_timer
->due
) < 0);
464 set_index(void *what
, int idx
) {
472 free_timer(void *what
, void *uap
) {
481 print_timer(void *what
, void *uap
) {
483 evContext_p
*ctx
= uap
;
487 " func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
489 (long)cur
->due
.tv_sec
, cur
->due
.tv_nsec
,
490 (long)cur
->inter
.tv_sec
, cur
->inter
.tv_nsec
);
494 idle_timeout(evContext opaqueCtx
,
497 struct timespec inter
499 evContext_p
*ctx
= opaqueCtx
.opaque
;
500 idle_timer
*this = uap
;
501 struct timespec idle
;
506 idle
= evSubTime(ctx
->lastEventTime
, this->lastTouched
);
507 if (evCmpTime(idle
, this->max_idle
) >= 0) {
508 (this->func
)(opaqueCtx
, this->uap
, this->timer
->due
,
511 * Setting the interval to zero will cause the timer to
512 * be cleaned up in evDrop().
514 this->timer
->inter
= evConsTime(0L, 0L);
517 /* evDrop() will reschedule the timer. */
518 this->timer
->inter
= evSubTime(this->max_idle
, idle
);