[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.6

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

CVSweb <webmaster@jp.NetBSD.org>