other-licenses/android/ev_timers.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial