Annotation of embedaddon/thttpd/timers.c, revision 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>