[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

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

CVSweb <webmaster@jp.NetBSD.org>