other-licenses/android/ev_timers.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/other-licenses/android/ev_timers.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,522 @@
     1.4 +/*	$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $	*/
     1.5 +
     1.6 +/*
     1.7 + * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
     1.8 + * Copyright (c) 1995-1999 by Internet Software Consortium
     1.9 + *
    1.10 + * Permission to use, copy, modify, and distribute this software for any
    1.11 + * purpose with or without fee is hereby granted, provided that the above
    1.12 + * copyright notice and this permission notice appear in all copies.
    1.13 + *
    1.14 + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
    1.15 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    1.16 + * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
    1.17 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    1.18 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    1.19 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
    1.20 + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    1.21 + */
    1.22 +
    1.23 +/* ev_timers.c - implement timers for the eventlib
    1.24 + * vix 09sep95 [initial]
    1.25 + */
    1.26 +
    1.27 +/*
    1.28 + * This version of this file is derived from Android 2.3 "Gingerbread",
    1.29 + * which contains uncredited changes by Android/Google developers.  It has
    1.30 + * been modified in 2011 for use in the Android build of Mozilla Firefox by
    1.31 + * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>,
    1.32 + * and Steve Workman <sjhworkman@gmail.com>).
    1.33 + * These changes are offered under the same license as the original NetBSD
    1.34 + * file, whose copyright and license are unchanged above.
    1.35 + */
    1.36 +
    1.37 +#define ANDROID_CHANGES 1
    1.38 +#define MOZILLA_NECKO_EXCLUDE_CODE 1
    1.39 +
    1.40 +#include <sys/cdefs.h>
    1.41 +#if !defined(LINT) && !defined(CODECENTER) && !defined(lint)
    1.42 +#ifdef notdef
    1.43 +static const char rcsid[] = "Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp";
    1.44 +#else
    1.45 +__RCSID("$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $");
    1.46 +#endif
    1.47 +#endif
    1.48 +
    1.49 +/* Import. */
    1.50 +
    1.51 +#include <errno.h>
    1.52 +#include <time.h>
    1.53 +
    1.54 +#include "assertions.h"
    1.55 +#include "eventlib.h"
    1.56 +#include "eventlib_p.h"
    1.57 +
    1.58 +/* Constants. */
    1.59 +
    1.60 +#define	MILLION 1000000
    1.61 +#define BILLION 1000000000
    1.62 +
    1.63 +/* Forward. */
    1.64 +
    1.65 +#ifndef _LIBC
    1.66 +static int due_sooner(void *, void *);
    1.67 +static void set_index(void *, int);
    1.68 +static void free_timer(void *, void *);
    1.69 +static void print_timer(void *, void *);
    1.70 +static void idle_timeout(evContext, void *, struct timespec, struct timespec);
    1.71 +
    1.72 +/* Private type. */
    1.73 +
    1.74 +typedef struct {
    1.75 +	evTimerFunc	func;
    1.76 +	void *		uap;
    1.77 +	struct timespec	lastTouched;
    1.78 +	struct timespec	max_idle;
    1.79 +	evTimer *	timer;
    1.80 +} idle_timer;
    1.81 +#endif
    1.82 +
    1.83 +/* Public. */
    1.84 +
    1.85 +struct timespec
    1.86 +evConsTime(time_t sec, long nsec) {
    1.87 +	struct timespec x;
    1.88 +
    1.89 +	x.tv_sec = sec;
    1.90 +	x.tv_nsec = nsec;
    1.91 +	return (x);
    1.92 +}
    1.93 +
    1.94 +struct timespec
    1.95 +evAddTime(struct timespec addend1, struct timespec addend2) {
    1.96 +	struct timespec x;
    1.97 +
    1.98 +	x.tv_sec = addend1.tv_sec + addend2.tv_sec;
    1.99 +	x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
   1.100 +	if (x.tv_nsec >= BILLION) {
   1.101 +		x.tv_sec++;
   1.102 +		x.tv_nsec -= BILLION;
   1.103 +	}
   1.104 +	return (x);
   1.105 +}
   1.106 +
   1.107 +struct timespec
   1.108 +evSubTime(struct timespec minuend, struct timespec subtrahend) {
   1.109 +	struct timespec x;
   1.110 +
   1.111 +	x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
   1.112 +	if (minuend.tv_nsec >= subtrahend.tv_nsec)
   1.113 +		x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
   1.114 +	else {
   1.115 +		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
   1.116 +		x.tv_sec--;
   1.117 +	}
   1.118 +	return (x);
   1.119 +}
   1.120 +
   1.121 +int
   1.122 +evCmpTime(struct timespec a, struct timespec b) {
   1.123 +	long x = a.tv_sec - b.tv_sec;
   1.124 +
   1.125 +	if (x == 0L)
   1.126 +		x = a.tv_nsec - b.tv_nsec;
   1.127 +	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
   1.128 +}
   1.129 +
   1.130 +struct timespec
   1.131 +evNowTime() {
   1.132 +	struct timeval now;
   1.133 +#ifdef CLOCK_REALTIME
   1.134 +	struct timespec tsnow;
   1.135 +	int m = CLOCK_REALTIME;
   1.136 +
   1.137 +#ifdef CLOCK_MONOTONIC
   1.138 +	if (__evOptMonoTime)
   1.139 +		m = CLOCK_MONOTONIC;
   1.140 +#endif
   1.141 +	if (clock_gettime(m, &tsnow) == 0)
   1.142 +		return (tsnow);
   1.143 +#endif
   1.144 +	if (gettimeofday(&now, NULL) < 0)
   1.145 +		return (evConsTime(0L, 0L));
   1.146 +	return (evTimeSpec(now));
   1.147 +}
   1.148 +
   1.149 +#ifndef MOZILLA_NECKO_EXCLUDE_CODE
   1.150 +struct timespec
   1.151 +evUTCTime(void) {
   1.152 +	struct timeval now;
   1.153 +#ifdef CLOCK_REALTIME
   1.154 +	struct timespec tsnow;
   1.155 +	if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
   1.156 +		return (tsnow);
   1.157 +#endif
   1.158 +	if (gettimeofday(&now, NULL) < 0)
   1.159 +		return (evConsTime(0L, 0L));
   1.160 +	return (evTimeSpec(now));
   1.161 +}
   1.162 +
   1.163 +#ifndef _LIBC
   1.164 +struct timespec
   1.165 +evLastEventTime(evContext opaqueCtx) {
   1.166 +	evContext_p *ctx = opaqueCtx.opaque;
   1.167 +
   1.168 +	return (ctx->lastEventTime);
   1.169 +}
   1.170 +#endif
   1.171 +#endif
   1.172 +
   1.173 +struct timespec
   1.174 +evTimeSpec(struct timeval tv) {
   1.175 +	struct timespec ts;
   1.176 +
   1.177 +	ts.tv_sec = tv.tv_sec;
   1.178 +	ts.tv_nsec = tv.tv_usec * 1000;
   1.179 +	return (ts);
   1.180 +}
   1.181 +
   1.182 +#ifndef MOZILLA_NECKO_EXCLUDE_CODE
   1.183 +struct timeval
   1.184 +evTimeVal(struct timespec ts) {
   1.185 +	struct timeval tv;
   1.186 +
   1.187 +	tv.tv_sec = ts.tv_sec;
   1.188 +	tv.tv_usec = ts.tv_nsec / 1000;
   1.189 +	return (tv);
   1.190 +}
   1.191 +
   1.192 +#ifndef _LIBC
   1.193 +int
   1.194 +evSetTimer(evContext opaqueCtx,
   1.195 +	   evTimerFunc func,
   1.196 +	   void *uap,
   1.197 +	   struct timespec due,
   1.198 +	   struct timespec inter,
   1.199 +	   evTimerID *opaqueID
   1.200 +) {
   1.201 +	evContext_p *ctx = opaqueCtx.opaque;
   1.202 +	evTimer *id;
   1.203 +
   1.204 +	printf("evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
   1.205 +		 ctx, func, uap,
   1.206 +		 (long)due.tv_sec, due.tv_nsec,
   1.207 +		 (long)inter.tv_sec, inter.tv_nsec);
   1.208 +
   1.209 +#ifdef __hpux
   1.210 +	/*
   1.211 +	 * tv_sec and tv_nsec are unsigned.
   1.212 +	 */
   1.213 +	if (due.tv_nsec >= BILLION)
   1.214 +		EV_ERR(EINVAL);
   1.215 +
   1.216 +	if (inter.tv_nsec >= BILLION)
   1.217 +		EV_ERR(EINVAL);
   1.218 +#else
   1.219 +	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
   1.220 +		EV_ERR(EINVAL);
   1.221 +
   1.222 +	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
   1.223 +		EV_ERR(EINVAL);
   1.224 +#endif
   1.225 +
   1.226 +	/* due={0,0} is a magic cookie meaning "now." */
   1.227 +	if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
   1.228 +		due = evNowTime();
   1.229 +
   1.230 +	/* Allocate and fill. */
   1.231 +	OKNEW(id);
   1.232 +	id->func = func;
   1.233 +	id->uap = uap;
   1.234 +	id->due = due;
   1.235 +	id->inter = inter;
   1.236 +
   1.237 +	if (heap_insert(ctx->timers, id) < 0)
   1.238 +		return (-1);
   1.239 +
   1.240 +	/* Remember the ID if the caller provided us a place for it. */
   1.241 +	if (opaqueID)
   1.242 +		opaqueID->opaque = id;
   1.243 +
   1.244 +	if (ctx->debug > 7) {
   1.245 +		printf("timers after evSetTimer:\n");
   1.246 +		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
   1.247 +	}
   1.248 +
   1.249 +	return (0);
   1.250 +}
   1.251 +
   1.252 +int
   1.253 +evClearTimer(evContext opaqueCtx, evTimerID id) {
   1.254 +	evContext_p *ctx = opaqueCtx.opaque;
   1.255 +	evTimer *del = id.opaque;
   1.256 +
   1.257 +	if (ctx->cur != NULL &&
   1.258 +	    ctx->cur->type == Timer &&
   1.259 +	    ctx->cur->u.timer.this == del) {
   1.260 +		printf("deferring delete of timer (executing)\n");
   1.261 +		/*
   1.262 +		 * Setting the interval to zero ensures that evDrop() will
   1.263 +		 * clean up the timer.
   1.264 +		 */
   1.265 +		del->inter = evConsTime(0, 0);
   1.266 +		return (0);
   1.267 +	}
   1.268 +
   1.269 +	if (heap_element(ctx->timers, del->index) != del)
   1.270 +		EV_ERR(ENOENT);
   1.271 +
   1.272 +	if (heap_delete(ctx->timers, del->index) < 0)
   1.273 +		return (-1);
   1.274 +	FREE(del);
   1.275 +
   1.276 +	if (ctx->debug > 7) {
   1.277 +		printf("timers after evClearTimer:\n");
   1.278 +		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
   1.279 +	}
   1.280 +
   1.281 +	return (0);
   1.282 +}
   1.283 +
   1.284 +int
   1.285 +evConfigTimer(evContext opaqueCtx,
   1.286 +	     evTimerID id,
   1.287 +	     const char *param,
   1.288 +	     int value
   1.289 +) {
   1.290 +	evContext_p *ctx = opaqueCtx.opaque;
   1.291 +	evTimer *timer = id.opaque;
   1.292 +	int result=0;
   1.293 +
   1.294 +	UNUSED(value);
   1.295 +
   1.296 +	if (heap_element(ctx->timers, timer->index) != timer)
   1.297 +		EV_ERR(ENOENT);
   1.298 +
   1.299 +	if (strcmp(param, "rate") == 0)
   1.300 +		timer->mode |= EV_TMR_RATE;
   1.301 +	else if (strcmp(param, "interval") == 0)
   1.302 +		timer->mode &= ~EV_TMR_RATE;
   1.303 +	else
   1.304 +		EV_ERR(EINVAL);
   1.305 +
   1.306 +	return (result);
   1.307 +}
   1.308 +
   1.309 +int
   1.310 +evResetTimer(evContext opaqueCtx,
   1.311 +	     evTimerID id,
   1.312 +	     evTimerFunc func,
   1.313 +	     void *uap,
   1.314 +	     struct timespec due,
   1.315 +	     struct timespec inter
   1.316 +) {
   1.317 +	evContext_p *ctx = opaqueCtx.opaque;
   1.318 +	evTimer *timer = id.opaque;
   1.319 +	struct timespec old_due;
   1.320 +	int result=0;
   1.321 +
   1.322 +	if (heap_element(ctx->timers, timer->index) != timer)
   1.323 +		EV_ERR(ENOENT);
   1.324 +
   1.325 +#ifdef __hpux
   1.326 +	/*
   1.327 +	 * tv_sec and tv_nsec are unsigned.
   1.328 +	 */
   1.329 +	if (due.tv_nsec >= BILLION)
   1.330 +		EV_ERR(EINVAL);
   1.331 +
   1.332 +	if (inter.tv_nsec >= BILLION)
   1.333 +		EV_ERR(EINVAL);
   1.334 +#else
   1.335 +	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
   1.336 +		EV_ERR(EINVAL);
   1.337 +
   1.338 +	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
   1.339 +		EV_ERR(EINVAL);
   1.340 +#endif
   1.341 +
   1.342 +	old_due = timer->due;
   1.343 +
   1.344 +	timer->func = func;
   1.345 +	timer->uap = uap;
   1.346 +	timer->due = due;
   1.347 +	timer->inter = inter;
   1.348 +
   1.349 +	switch (evCmpTime(due, old_due)) {
   1.350 +	case -1:
   1.351 +		result = heap_increased(ctx->timers, timer->index);
   1.352 +		break;
   1.353 +	case 0:
   1.354 +		result = 0;
   1.355 +		break;
   1.356 +	case 1:
   1.357 +		result = heap_decreased(ctx->timers, timer->index);
   1.358 +		break;
   1.359 +	}
   1.360 +
   1.361 +	if (ctx->debug > 7) {
   1.362 +		printf("timers after evResetTimer:\n");
   1.363 +		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
   1.364 +	}
   1.365 +
   1.366 +	return (result);
   1.367 +}
   1.368 +
   1.369 +int
   1.370 +evSetIdleTimer(evContext opaqueCtx,
   1.371 +		evTimerFunc func,
   1.372 +		void *uap,
   1.373 +		struct timespec max_idle,
   1.374 +		evTimerID *opaqueID
   1.375 +) {
   1.376 +	evContext_p *ctx = opaqueCtx.opaque;
   1.377 +	idle_timer *tt;
   1.378 +
   1.379 +	/* Allocate and fill. */
   1.380 +	OKNEW(tt);
   1.381 +	tt->func = func;
   1.382 +	tt->uap = uap;
   1.383 +	tt->lastTouched = ctx->lastEventTime;
   1.384 +	tt->max_idle = max_idle;
   1.385 +
   1.386 +	if (evSetTimer(opaqueCtx, idle_timeout, tt,
   1.387 +		       evAddTime(ctx->lastEventTime, max_idle),
   1.388 +		       max_idle, opaqueID) < 0) {
   1.389 +		FREE(tt);
   1.390 +		return (-1);
   1.391 +	}
   1.392 +
   1.393 +	tt->timer = opaqueID->opaque;
   1.394 +
   1.395 +	return (0);
   1.396 +}
   1.397 +
   1.398 +int
   1.399 +evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
   1.400 +	evTimer *del = id.opaque;
   1.401 +	idle_timer *tt = del->uap;
   1.402 +
   1.403 +	FREE(tt);
   1.404 +	return (evClearTimer(opaqueCtx, id));
   1.405 +}
   1.406 +
   1.407 +int
   1.408 +evResetIdleTimer(evContext opaqueCtx,
   1.409 +		 evTimerID opaqueID,
   1.410 +		 evTimerFunc func,
   1.411 +		 void *uap,
   1.412 +		 struct timespec max_idle
   1.413 +) {
   1.414 +	evContext_p *ctx = opaqueCtx.opaque;
   1.415 +	evTimer *timer = opaqueID.opaque;
   1.416 +	idle_timer *tt = timer->uap;
   1.417 +
   1.418 +	tt->func = func;
   1.419 +	tt->uap = uap;
   1.420 +	tt->lastTouched = ctx->lastEventTime;
   1.421 +	tt->max_idle = max_idle;
   1.422 +
   1.423 +	return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
   1.424 +			     evAddTime(ctx->lastEventTime, max_idle),
   1.425 +			     max_idle));
   1.426 +}
   1.427 +
   1.428 +int
   1.429 +evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
   1.430 +	evContext_p *ctx = opaqueCtx.opaque;
   1.431 +	evTimer *t = id.opaque;
   1.432 +	idle_timer *tt = t->uap;
   1.433 +
   1.434 +	tt->lastTouched = ctx->lastEventTime;
   1.435 +
   1.436 +	return (0);
   1.437 +}
   1.438 +
   1.439 +/* Public to the rest of eventlib. */
   1.440 +
   1.441 +heap_context
   1.442 +evCreateTimers(const evContext_p *ctx) {
   1.443 +
   1.444 +	UNUSED(ctx);
   1.445 +
   1.446 +	return (heap_new(due_sooner, set_index, 2048));
   1.447 +}
   1.448 +
   1.449 +void
   1.450 +evDestroyTimers(const evContext_p *ctx) {
   1.451 +	(void) heap_for_each(ctx->timers, free_timer, NULL);
   1.452 +	(void) heap_free(ctx->timers);
   1.453 +}
   1.454 +
   1.455 +/* Private. */
   1.456 +
   1.457 +static int
   1.458 +due_sooner(void *a, void *b) {
   1.459 +	evTimer *a_timer, *b_timer;
   1.460 +
   1.461 +	a_timer = a;
   1.462 +	b_timer = b;
   1.463 +	return (evCmpTime(a_timer->due, b_timer->due) < 0);
   1.464 +}
   1.465 +
   1.466 +static void
   1.467 +set_index(void *what, int idx) {
   1.468 +	evTimer *timer;
   1.469 +
   1.470 +	timer = what;
   1.471 +	timer->index = idx;
   1.472 +}
   1.473 +
   1.474 +static void
   1.475 +free_timer(void *what, void *uap) {
   1.476 +	evTimer *t = what;
   1.477 +
   1.478 +	UNUSED(uap);
   1.479 +
   1.480 +	FREE(t);
   1.481 +}
   1.482 +
   1.483 +static void
   1.484 +print_timer(void *what, void *uap) {
   1.485 +	evTimer *cur = what;
   1.486 +	evContext_p *ctx = uap;
   1.487 +
   1.488 +	cur = what;
   1.489 +	evPrintf(ctx, 7,
   1.490 +	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
   1.491 +		 cur->func, cur->uap,
   1.492 +		 (long)cur->due.tv_sec, cur->due.tv_nsec,
   1.493 +		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
   1.494 +}
   1.495 +
   1.496 +static void
   1.497 +idle_timeout(evContext opaqueCtx,
   1.498 +	     void *uap,
   1.499 +	     struct timespec due,
   1.500 +	     struct timespec inter
   1.501 +) {
   1.502 +	evContext_p *ctx = opaqueCtx.opaque;
   1.503 +	idle_timer *this = uap;
   1.504 +	struct timespec idle;
   1.505 +
   1.506 +	UNUSED(due);
   1.507 +	UNUSED(inter);
   1.508 +	
   1.509 +	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
   1.510 +	if (evCmpTime(idle, this->max_idle) >= 0) {
   1.511 +		(this->func)(opaqueCtx, this->uap, this->timer->due,
   1.512 +			     this->max_idle);
   1.513 +		/*
   1.514 +		 * Setting the interval to zero will cause the timer to
   1.515 +		 * be cleaned up in evDrop().
   1.516 +		 */
   1.517 +		this->timer->inter = evConsTime(0L, 0L);
   1.518 +		FREE(this);
   1.519 +	} else {
   1.520 +		/* evDrop() will reschedule the timer. */
   1.521 +		this->timer->inter = evSubTime(this->max_idle, idle);
   1.522 +	}
   1.523 +}
   1.524 +#endif
   1.525 +#endif

mercurial