other-licenses/android/ev_timers.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /*	$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $	*/
     3 /*
     4  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
     5  * Copyright (c) 1995-1999 by Internet Software Consortium
     6  *
     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.
    10  *
    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.
    18  */
    20 /* ev_timers.c - implement timers for the eventlib
    21  * vix 09sep95 [initial]
    22  */
    24 /*
    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.
    32  */
    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)
    39 #ifdef notdef
    40 static const char rcsid[] = "Id: ev_timers.c,v 1.2.2.1.4.5 2004/03/17 02:39:13 marka Exp";
    41 #else
    42 __RCSID("$NetBSD: ev_timers.c,v 1.2 2004/05/20 19:52:31 christos Exp $");
    43 #endif
    44 #endif
    46 /* Import. */
    48 #include <errno.h>
    49 #include <time.h>
    51 #include "assertions.h"
    52 #include "eventlib.h"
    53 #include "eventlib_p.h"
    55 /* Constants. */
    57 #define	MILLION 1000000
    58 #define BILLION 1000000000
    60 /* Forward. */
    62 #ifndef _LIBC
    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);
    69 /* Private type. */
    71 typedef struct {
    72 	evTimerFunc	func;
    73 	void *		uap;
    74 	struct timespec	lastTouched;
    75 	struct timespec	max_idle;
    76 	evTimer *	timer;
    77 } idle_timer;
    78 #endif
    80 /* Public. */
    82 struct timespec
    83 evConsTime(time_t sec, long nsec) {
    84 	struct timespec x;
    86 	x.tv_sec = sec;
    87 	x.tv_nsec = nsec;
    88 	return (x);
    89 }
    91 struct timespec
    92 evAddTime(struct timespec addend1, struct timespec addend2) {
    93 	struct timespec x;
    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) {
    98 		x.tv_sec++;
    99 		x.tv_nsec -= BILLION;
   100 	}
   101 	return (x);
   102 }
   104 struct timespec
   105 evSubTime(struct timespec minuend, struct timespec subtrahend) {
   106 	struct timespec x;
   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;
   111 	else {
   112 		x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
   113 		x.tv_sec--;
   114 	}
   115 	return (x);
   116 }
   118 int
   119 evCmpTime(struct timespec a, struct timespec b) {
   120 	long x = a.tv_sec - b.tv_sec;
   122 	if (x == 0L)
   123 		x = a.tv_nsec - b.tv_nsec;
   124 	return (x < 0L ? (-1) : x > 0L ? (1) : (0));
   125 }
   127 struct timespec
   128 evNowTime() {
   129 	struct timeval now;
   130 #ifdef CLOCK_REALTIME
   131 	struct timespec tsnow;
   132 	int m = CLOCK_REALTIME;
   134 #ifdef CLOCK_MONOTONIC
   135 	if (__evOptMonoTime)
   136 		m = CLOCK_MONOTONIC;
   137 #endif
   138 	if (clock_gettime(m, &tsnow) == 0)
   139 		return (tsnow);
   140 #endif
   141 	if (gettimeofday(&now, NULL) < 0)
   142 		return (evConsTime(0L, 0L));
   143 	return (evTimeSpec(now));
   144 }
   146 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
   147 struct timespec
   148 evUTCTime(void) {
   149 	struct timeval now;
   150 #ifdef CLOCK_REALTIME
   151 	struct timespec tsnow;
   152 	if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
   153 		return (tsnow);
   154 #endif
   155 	if (gettimeofday(&now, NULL) < 0)
   156 		return (evConsTime(0L, 0L));
   157 	return (evTimeSpec(now));
   158 }
   160 #ifndef _LIBC
   161 struct timespec
   162 evLastEventTime(evContext opaqueCtx) {
   163 	evContext_p *ctx = opaqueCtx.opaque;
   165 	return (ctx->lastEventTime);
   166 }
   167 #endif
   168 #endif
   170 struct timespec
   171 evTimeSpec(struct timeval tv) {
   172 	struct timespec ts;
   174 	ts.tv_sec = tv.tv_sec;
   175 	ts.tv_nsec = tv.tv_usec * 1000;
   176 	return (ts);
   177 }
   179 #ifndef MOZILLA_NECKO_EXCLUDE_CODE
   180 struct timeval
   181 evTimeVal(struct timespec ts) {
   182 	struct timeval tv;
   184 	tv.tv_sec = ts.tv_sec;
   185 	tv.tv_usec = ts.tv_nsec / 1000;
   186 	return (tv);
   187 }
   189 #ifndef _LIBC
   190 int
   191 evSetTimer(evContext opaqueCtx,
   192 	   evTimerFunc func,
   193 	   void *uap,
   194 	   struct timespec due,
   195 	   struct timespec inter,
   196 	   evTimerID *opaqueID
   197 ) {
   198 	evContext_p *ctx = opaqueCtx.opaque;
   199 	evTimer *id;
   201 	printf("evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
   202 		 ctx, func, uap,
   203 		 (long)due.tv_sec, due.tv_nsec,
   204 		 (long)inter.tv_sec, inter.tv_nsec);
   206 #ifdef __hpux
   207 	/*
   208 	 * tv_sec and tv_nsec are unsigned.
   209 	 */
   210 	if (due.tv_nsec >= BILLION)
   211 		EV_ERR(EINVAL);
   213 	if (inter.tv_nsec >= BILLION)
   214 		EV_ERR(EINVAL);
   215 #else
   216 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
   217 		EV_ERR(EINVAL);
   219 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
   220 		EV_ERR(EINVAL);
   221 #endif
   223 	/* due={0,0} is a magic cookie meaning "now." */
   224 	if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
   225 		due = evNowTime();
   227 	/* Allocate and fill. */
   228 	OKNEW(id);
   229 	id->func = func;
   230 	id->uap = uap;
   231 	id->due = due;
   232 	id->inter = inter;
   234 	if (heap_insert(ctx->timers, id) < 0)
   235 		return (-1);
   237 	/* Remember the ID if the caller provided us a place for it. */
   238 	if (opaqueID)
   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);
   244 	}
   246 	return (0);
   247 }
   249 int
   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");
   258 		/*
   259 		 * Setting the interval to zero ensures that evDrop() will
   260 		 * clean up the timer.
   261 		 */
   262 		del->inter = evConsTime(0, 0);
   263 		return (0);
   264 	}
   266 	if (heap_element(ctx->timers, del->index) != del)
   267 		EV_ERR(ENOENT);
   269 	if (heap_delete(ctx->timers, del->index) < 0)
   270 		return (-1);
   271 	FREE(del);
   273 	if (ctx->debug > 7) {
   274 		printf("timers after evClearTimer:\n");
   275 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
   276 	}
   278 	return (0);
   279 }
   281 int
   282 evConfigTimer(evContext opaqueCtx,
   283 	     evTimerID id,
   284 	     const char *param,
   285 	     int value
   286 ) {
   287 	evContext_p *ctx = opaqueCtx.opaque;
   288 	evTimer *timer = id.opaque;
   289 	int result=0;
   291 	UNUSED(value);
   293 	if (heap_element(ctx->timers, timer->index) != timer)
   294 		EV_ERR(ENOENT);
   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;
   300 	else
   301 		EV_ERR(EINVAL);
   303 	return (result);
   304 }
   306 int
   307 evResetTimer(evContext opaqueCtx,
   308 	     evTimerID id,
   309 	     evTimerFunc func,
   310 	     void *uap,
   311 	     struct timespec due,
   312 	     struct timespec inter
   313 ) {
   314 	evContext_p *ctx = opaqueCtx.opaque;
   315 	evTimer *timer = id.opaque;
   316 	struct timespec old_due;
   317 	int result=0;
   319 	if (heap_element(ctx->timers, timer->index) != timer)
   320 		EV_ERR(ENOENT);
   322 #ifdef __hpux
   323 	/*
   324 	 * tv_sec and tv_nsec are unsigned.
   325 	 */
   326 	if (due.tv_nsec >= BILLION)
   327 		EV_ERR(EINVAL);
   329 	if (inter.tv_nsec >= BILLION)
   330 		EV_ERR(EINVAL);
   331 #else
   332 	if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
   333 		EV_ERR(EINVAL);
   335 	if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
   336 		EV_ERR(EINVAL);
   337 #endif
   339 	old_due = timer->due;
   341 	timer->func = func;
   342 	timer->uap = uap;
   343 	timer->due = due;
   344 	timer->inter = inter;
   346 	switch (evCmpTime(due, old_due)) {
   347 	case -1:
   348 		result = heap_increased(ctx->timers, timer->index);
   349 		break;
   350 	case 0:
   351 		result = 0;
   352 		break;
   353 	case 1:
   354 		result = heap_decreased(ctx->timers, timer->index);
   355 		break;
   356 	}
   358 	if (ctx->debug > 7) {
   359 		printf("timers after evResetTimer:\n");
   360 		(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
   361 	}
   363 	return (result);
   364 }
   366 int
   367 evSetIdleTimer(evContext opaqueCtx,
   368 		evTimerFunc func,
   369 		void *uap,
   370 		struct timespec max_idle,
   371 		evTimerID *opaqueID
   372 ) {
   373 	evContext_p *ctx = opaqueCtx.opaque;
   374 	idle_timer *tt;
   376 	/* Allocate and fill. */
   377 	OKNEW(tt);
   378 	tt->func = func;
   379 	tt->uap = uap;
   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) {
   386 		FREE(tt);
   387 		return (-1);
   388 	}
   390 	tt->timer = opaqueID->opaque;
   392 	return (0);
   393 }
   395 int
   396 evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
   397 	evTimer *del = id.opaque;
   398 	idle_timer *tt = del->uap;
   400 	FREE(tt);
   401 	return (evClearTimer(opaqueCtx, id));
   402 }
   404 int
   405 evResetIdleTimer(evContext opaqueCtx,
   406 		 evTimerID opaqueID,
   407 		 evTimerFunc func,
   408 		 void *uap,
   409 		 struct timespec max_idle
   410 ) {
   411 	evContext_p *ctx = opaqueCtx.opaque;
   412 	evTimer *timer = opaqueID.opaque;
   413 	idle_timer *tt = timer->uap;
   415 	tt->func = func;
   416 	tt->uap = 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),
   422 			     max_idle));
   423 }
   425 int
   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;
   433 	return (0);
   434 }
   436 /* Public to the rest of eventlib. */
   438 heap_context
   439 evCreateTimers(const evContext_p *ctx) {
   441 	UNUSED(ctx);
   443 	return (heap_new(due_sooner, set_index, 2048));
   444 }
   446 void
   447 evDestroyTimers(const evContext_p *ctx) {
   448 	(void) heap_for_each(ctx->timers, free_timer, NULL);
   449 	(void) heap_free(ctx->timers);
   450 }
   452 /* Private. */
   454 static int
   455 due_sooner(void *a, void *b) {
   456 	evTimer *a_timer, *b_timer;
   458 	a_timer = a;
   459 	b_timer = b;
   460 	return (evCmpTime(a_timer->due, b_timer->due) < 0);
   461 }
   463 static void
   464 set_index(void *what, int idx) {
   465 	evTimer *timer;
   467 	timer = what;
   468 	timer->index = idx;
   469 }
   471 static void
   472 free_timer(void *what, void *uap) {
   473 	evTimer *t = what;
   475 	UNUSED(uap);
   477 	FREE(t);
   478 }
   480 static void
   481 print_timer(void *what, void *uap) {
   482 	evTimer *cur = what;
   483 	evContext_p *ctx = uap;
   485 	cur = what;
   486 	evPrintf(ctx, 7,
   487 	    "  func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
   488 		 cur->func, cur->uap,
   489 		 (long)cur->due.tv_sec, cur->due.tv_nsec,
   490 		 (long)cur->inter.tv_sec, cur->inter.tv_nsec);
   491 }
   493 static void
   494 idle_timeout(evContext opaqueCtx,
   495 	     void *uap,
   496 	     struct timespec due,
   497 	     struct timespec inter
   498 ) {
   499 	evContext_p *ctx = opaqueCtx.opaque;
   500 	idle_timer *this = uap;
   501 	struct timespec idle;
   503 	UNUSED(due);
   504 	UNUSED(inter);
   506 	idle = evSubTime(ctx->lastEventTime, this->lastTouched);
   507 	if (evCmpTime(idle, this->max_idle) >= 0) {
   508 		(this->func)(opaqueCtx, this->uap, this->timer->due,
   509 			     this->max_idle);
   510 		/*
   511 		 * Setting the interval to zero will cause the timer to
   512 		 * be cleaned up in evDrop().
   513 		 */
   514 		this->timer->inter = evConsTime(0L, 0L);
   515 		FREE(this);
   516 	} else {
   517 		/* evDrop() will reschedule the timer. */
   518 		this->timer->inter = evSubTime(this->max_idle, idle);
   519 	}
   520 }
   521 #endif
   522 #endif

mercurial