[BACK]Return to ev_timers.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / isc

Annotation of src/lib/libc/isc/ev_timers.c, Revision 1.8.6.1

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

CVSweb <webmaster@jp.NetBSD.org>