Annotation of embedaddon/thttpd/timers.c, revision 1.1.1.1

1.1       misho       1: /* timers.c - simple timer routines
                      2: **
                      3: ** Copyright © 1995,1998,2000 by Jef Poskanzer <jef@mail.acme.com>.
                      4: ** All rights reserved.
                      5: **
                      6: ** Redistribution and use in source and binary forms, with or without
                      7: ** modification, are permitted provided that the following conditions
                      8: ** are met:
                      9: ** 1. Redistributions of source code must retain the above copyright
                     10: **    notice, this list of conditions and the following disclaimer.
                     11: ** 2. Redistributions in binary form must reproduce the above copyright
                     12: **    notice, this list of conditions and the following disclaimer in the
                     13: **    documentation and/or other materials provided with the distribution.
                     14: **
                     15: ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     16: ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     17: ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     18: ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19: ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20: ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     21: ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22: ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23: ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24: ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25: ** SUCH DAMAGE.
                     26: */
                     27: 
                     28: #include <sys/types.h>
                     29: 
                     30: #include <stdlib.h>
                     31: #include <stdio.h>
                     32: #include <syslog.h>
                     33: 
                     34: #include "timers.h"
                     35: 
                     36: 
                     37: #define HASH_SIZE 67
                     38: static Timer* timers[HASH_SIZE];
                     39: static Timer* free_timers;
                     40: static int alloc_count, active_count, free_count;
                     41: 
                     42: ClientData JunkClientData;
                     43: 
                     44: 
                     45: 
                     46: static unsigned int
                     47: hash( Timer* t )
                     48:     {
                     49:     /* We can hash on the trigger time, even though it can change over
                     50:     ** the life of a timer via either the periodic bit or the tmr_reset()
                     51:     ** call.  This is because both of those guys call l_resort(), which
                     52:     ** recomputes the hash and moves the timer to the appropriate list.
                     53:     */
                     54:     return (
                     55:        (unsigned int) t->time.tv_sec ^
                     56:        (unsigned int) t->time.tv_usec ) % HASH_SIZE;
                     57:     }
                     58: 
                     59: 
                     60: static void
                     61: l_add( Timer* t )
                     62:     {
                     63:     int h = t->hash;
                     64:     register Timer* t2;
                     65:     register Timer* t2prev;
                     66: 
                     67:     t2 = timers[h];
                     68:     if ( t2 == (Timer*) 0 )
                     69:        {
                     70:        /* The list is empty. */
                     71:        timers[h] = t;
                     72:        t->prev = t->next = (Timer*) 0;
                     73:        }
                     74:     else
                     75:        {
                     76:        if ( t->time.tv_sec < t2->time.tv_sec ||
                     77:             ( t->time.tv_sec == t2->time.tv_sec &&
                     78:               t->time.tv_usec <= t2->time.tv_usec ) )
                     79:            {
                     80:            /* The new timer goes at the head of the list. */
                     81:            timers[h] = t;
                     82:            t->prev = (Timer*) 0;
                     83:            t->next = t2;
                     84:            t2->prev = t;
                     85:            }
                     86:        else
                     87:            {
                     88:            /* Walk the list to find the insertion point. */
                     89:            for ( t2prev = t2, t2 = t2->next; t2 != (Timer*) 0;
                     90:                  t2prev = t2, t2 = t2->next )
                     91:                {
                     92:                if ( t->time.tv_sec < t2->time.tv_sec ||
                     93:                     ( t->time.tv_sec == t2->time.tv_sec &&
                     94:                       t->time.tv_usec <= t2->time.tv_usec ) )
                     95:                    {
                     96:                    /* Found it. */
                     97:                    t2prev->next = t;
                     98:                    t->prev = t2prev;
                     99:                    t->next = t2;
                    100:                    t2->prev = t;
                    101:                    return;
                    102:                    }
                    103:                }
                    104:            /* Oops, got to the end of the list.  Add to tail. */
                    105:            t2prev->next = t;
                    106:            t->prev = t2prev;
                    107:            t->next = (Timer*) 0;
                    108:            }
                    109:        }
                    110:     }
                    111: 
                    112: 
                    113: static void
                    114: l_remove( Timer* t )
                    115:     {
                    116:     int h = t->hash;
                    117: 
                    118:     if ( t->prev == (Timer*) 0 )
                    119:        timers[h] = t->next;
                    120:     else
                    121:        t->prev->next = t->next;
                    122:     if ( t->next != (Timer*) 0 )
                    123:        t->next->prev = t->prev;
                    124:     }
                    125: 
                    126: 
                    127: static void
                    128: l_resort( Timer* t )
                    129:     {
                    130:     /* Remove the timer from its old list. */
                    131:     l_remove( t );
                    132:     /* Recompute the hash. */
                    133:     t->hash = hash( t );
                    134:     /* And add it back in to its new list, sorted correctly. */
                    135:     l_add( t );
                    136:     }
                    137: 
                    138: 
                    139: void
                    140: tmr_init( void )
                    141:     {
                    142:     int h;
                    143: 
                    144:     for ( h = 0; h < HASH_SIZE; ++h )
                    145:        timers[h] = (Timer*) 0;
                    146:     free_timers = (Timer*) 0;
                    147:     alloc_count = active_count = free_count = 0;
                    148:     }
                    149: 
                    150: 
                    151: Timer*
                    152: tmr_create(
                    153:     struct timeval* nowP, TimerProc* timer_proc, ClientData client_data,
                    154:     long msecs, int periodic )
                    155:     {
                    156:     Timer* t;
                    157: 
                    158:     if ( free_timers != (Timer*) 0 )
                    159:        {
                    160:        t = free_timers;
                    161:        free_timers = t->next;
                    162:        --free_count;
                    163:        }
                    164:     else
                    165:        {
                    166:        t = (Timer*) malloc( sizeof(Timer) );
                    167:        if ( t == (Timer*) 0 )
                    168:            return (Timer*) 0;
                    169:        ++alloc_count;
                    170:        }
                    171: 
                    172:     t->timer_proc = timer_proc;
                    173:     t->client_data = client_data;
                    174:     t->msecs = msecs;
                    175:     t->periodic = periodic;
                    176:     if ( nowP != (struct timeval*) 0 )
                    177:        t->time = *nowP;
                    178:     else
                    179:        (void) gettimeofday( &t->time, (struct timezone*) 0 );
                    180:     t->time.tv_sec += msecs / 1000L;
                    181:     t->time.tv_usec += ( msecs % 1000L ) * 1000L;
                    182:     if ( t->time.tv_usec >= 1000000L )
                    183:        {
                    184:        t->time.tv_sec += t->time.tv_usec / 1000000L;
                    185:        t->time.tv_usec %= 1000000L;
                    186:        }
                    187:     t->hash = hash( t );
                    188:     /* Add the new timer to the proper active list. */
                    189:     l_add( t );
                    190:     ++active_count;
                    191: 
                    192:     return t;
                    193:     }
                    194: 
                    195: 
                    196: struct timeval*
                    197: tmr_timeout( struct timeval* nowP )
                    198:     {
                    199:     long msecs;
                    200:     static struct timeval timeout;
                    201: 
                    202:     msecs = tmr_mstimeout( nowP );
                    203:     if ( msecs == INFTIM )
                    204:        return (struct timeval*) 0;
                    205:     timeout.tv_sec = msecs / 1000L;
                    206:     timeout.tv_usec = ( msecs % 1000L ) * 1000L;
                    207:     return &timeout;
                    208:     }
                    209: 
                    210: 
                    211: long
                    212: tmr_mstimeout( struct timeval* nowP )
                    213:     {
                    214:     int h;
                    215:     int gotone;
                    216:     long msecs, m;
                    217:     register Timer* t;
                    218: 
                    219:     gotone = 0;
                    220:     msecs = 0;          /* make lint happy */
                    221:     /* Since the lists are sorted, we only need to look at the
                    222:     ** first timer on each one.
                    223:     */
                    224:     for ( h = 0; h < HASH_SIZE; ++h )
                    225:        {
                    226:        t = timers[h];
                    227:        if ( t != (Timer*) 0 )
                    228:            {
                    229:            m = ( t->time.tv_sec - nowP->tv_sec ) * 1000L +
                    230:                ( t->time.tv_usec - nowP->tv_usec ) / 1000L;
                    231:            if ( ! gotone )
                    232:                {
                    233:                msecs = m;
                    234:                gotone = 1;
                    235:                }
                    236:            else if ( m < msecs )
                    237:                msecs = m;
                    238:            }
                    239:        }
                    240:     if ( ! gotone )
                    241:        return INFTIM;
                    242:     if ( msecs <= 0 )
                    243:        msecs = 0;
                    244:     return msecs;
                    245:     }
                    246: 
                    247: 
                    248: void
                    249: tmr_run( struct timeval* nowP )
                    250:     {
                    251:     int h;
                    252:     Timer* t;
                    253:     Timer* next;
                    254: 
                    255:     for ( h = 0; h < HASH_SIZE; ++h )
                    256:        for ( t = timers[h]; t != (Timer*) 0; t = next )
                    257:            {
                    258:            next = t->next;
                    259:            /* Since the lists are sorted, as soon as we find a timer
                    260:            ** that isn't ready yet, we can go on to the next list.
                    261:            */
                    262:            if ( t->time.tv_sec > nowP->tv_sec ||
                    263:                 ( t->time.tv_sec == nowP->tv_sec &&
                    264:                   t->time.tv_usec > nowP->tv_usec ) )
                    265:                break;
                    266:            (t->timer_proc)( t->client_data, nowP );
                    267:            if ( t->periodic )
                    268:                {
                    269:                /* Reschedule. */
                    270:                t->time.tv_sec += t->msecs / 1000L;
                    271:                t->time.tv_usec += ( t->msecs % 1000L ) * 1000L;
                    272:                if ( t->time.tv_usec >= 1000000L )
                    273:                    {
                    274:                    t->time.tv_sec += t->time.tv_usec / 1000000L;
                    275:                    t->time.tv_usec %= 1000000L;
                    276:                    }
                    277:                l_resort( t );
                    278:                }
                    279:            else
                    280:                tmr_cancel( t );
                    281:            }
                    282:     }
                    283: 
                    284: 
                    285: void
                    286: tmr_reset( struct timeval* nowP, Timer* t )
                    287:     {
                    288:     t->time = *nowP;
                    289:     t->time.tv_sec += t->msecs / 1000L;
                    290:     t->time.tv_usec += ( t->msecs % 1000L ) * 1000L;
                    291:     if ( t->time.tv_usec >= 1000000L )
                    292:        {
                    293:        t->time.tv_sec += t->time.tv_usec / 1000000L;
                    294:        t->time.tv_usec %= 1000000L;
                    295:        }
                    296:     l_resort( t );
                    297:     }
                    298: 
                    299: 
                    300: void
                    301: tmr_cancel( Timer* t )
                    302:     {
                    303:     /* Remove it from its active list. */
                    304:     l_remove( t );
                    305:     --active_count;
                    306:     /* And put it on the free list. */
                    307:     t->next = free_timers;
                    308:     free_timers = t;
                    309:     ++free_count;
                    310:     t->prev = (Timer*) 0;
                    311:     }
                    312: 
                    313: 
                    314: void
                    315: tmr_cleanup( void )
                    316:     {
                    317:     Timer* t;
                    318: 
                    319:     while ( free_timers != (Timer*) 0 )
                    320:        {
                    321:        t = free_timers;
                    322:        free_timers = t->next;
                    323:        --free_count;
                    324:        free( (void*) t );
                    325:        --alloc_count;
                    326:        }
                    327:     }
                    328: 
                    329: 
                    330: void
                    331: tmr_destroy( void )
                    332:     {
                    333:     int h;
                    334: 
                    335:     for ( h = 0; h < HASH_SIZE; ++h )
                    336:        while ( timers[h] != (Timer*) 0 )
                    337:            tmr_cancel( timers[h] );
                    338:     tmr_cleanup();
                    339:     }
                    340: 
                    341: 
                    342: /* Generate debugging statistics syslog message. */
                    343: void
                    344: tmr_logstats( long secs )
                    345:     {
                    346:     syslog(
                    347:        LOG_INFO, "  timers - %d allocated, %d active, %d free",
                    348:        alloc_count, active_count, free_count );
                    349:     if ( active_count + free_count != alloc_count )
                    350:        syslog( LOG_ERR, "timer counts don't add up!" );
                    351:     }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>