diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-03-19 21:04:13 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-03-19 21:04:13 +0000 |
commit | 7cc856ea2f1808e98387ea66537ecbc6c3de2f88 (patch) | |
tree | 673b6eef191373f0607e5b9a9f79ad390e9bb970 /apps/netutils/thttpd/timers.c | |
parent | 7267882ebd0a6aa79cf88b7f42675804eaff1bcf (diff) | |
download | nuttx-7cc856ea2f1808e98387ea66537ecbc6c3de2f88.tar.gz nuttx-7cc856ea2f1808e98387ea66537ecbc6c3de2f88.tar.bz2 nuttx-7cc856ea2f1808e98387ea66537ecbc6c3de2f88.zip |
Move nuttx/netutils to apps/netutils
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3401 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'apps/netutils/thttpd/timers.c')
-rw-r--r-- | apps/netutils/thttpd/timers.c | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/apps/netutils/thttpd/timers.c b/apps/netutils/thttpd/timers.c new file mode 100644 index 000000000..8edd7b21b --- /dev/null +++ b/apps/netutils/thttpd/timers.c @@ -0,0 +1,365 @@ +/**************************************************************************** + * netutils/thttpd/timers.c + * Simple Timer Routines + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * Derived from the file of the same name in the original THTTPD package: + * + * Copyright © 1995,1998,2000 by Jef Poskanzer <jef@mail.acme.com>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <sys/time.h> + +#include <stdlib.h> +#include <stdio.h> +#include <debug.h> + +#include "thttpd_alloc.h" +#include "timers.h" + +/**************************************************************************** + * Pre-Processor Definitons + ****************************************************************************/ + +#define HASH_SIZE 67 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static Timer *timers[HASH_SIZE]; +static Timer *free_timers; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +ClientData JunkClientData; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static unsigned int hash(Timer *tmr) +{ + /* We can hash on the trigger time, even though it can change over the + * life of a timer via the periodic bit. + * This is because both of those guys call l_resort(), which * recomputes + * the hash and moves the timer to the appropriate list. + */ + + return ((unsigned int)tmr->time.tv_sec ^ + (unsigned int)tmr->time.tv_usec) % HASH_SIZE; +} + +static void l_add(Timer *tmr) +{ + int h = tmr->hash; + register Timer *tmr2; + register Timer *tmr2prev; + + tmr2 = timers[h]; + if (tmr2 == NULL) + { + /* The list is empty. */ + timers[h] = tmr; + tmr->prev = tmr->next = NULL; + } + else + { + if (tmr->time.tv_sec < tmr2->time.tv_sec || + (tmr->time.tv_sec == tmr2->time.tv_sec && + tmr->time.tv_usec <= tmr2->time.tv_usec)) + { + /* The new timer goes at the head of the list. */ + + timers[h] = tmr; + tmr->prev = NULL; + tmr->next = tmr2; + tmr2->prev = tmr; + } + else + { + /* Walk the list to find the insertion point. */ + + for (tmr2prev = tmr2, tmr2 = tmr2->next; tmr2 != NULL; + tmr2prev = tmr2, tmr2 = tmr2->next) + { + if (tmr->time.tv_sec < tmr2->time.tv_sec || + (tmr->time.tv_sec == tmr2->time.tv_sec && + tmr->time.tv_usec <= tmr2->time.tv_usec)) + { + /* Found it. */ + tmr2prev->next = tmr; + tmr->prev = tmr2prev; + tmr->next = tmr2; + tmr2->prev = tmr; + return; + } + } + + /* Oops, got to the end of the list. Add to tail. */ + + tmr2prev->next = tmr; + tmr->prev = tmr2prev; + tmr->next = NULL; + } + } +} + +static void l_remove(Timer *tmr) +{ + int h = tmr->hash; + + if (tmr->prev == NULL) + { + timers[h] = tmr->next; + } + else + { + tmr->prev->next = tmr->next; + } + + if (tmr->next != NULL) + { + tmr->next->prev = tmr->prev; + } +} + +static void l_resort(Timer *tmr) +{ + /* Remove the timer from its old list. */ + + l_remove(tmr); + + /* Recompute the hash. */ + + tmr->hash = hash(tmr); + + /* And add it back in to its new list, sorted correctly. */ + + l_add(tmr); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void tmr_init(void) +{ + int h; + + for (h = 0; h < HASH_SIZE; ++h) + { + timers[h] = NULL; + } + + free_timers = NULL; +} + +Timer *tmr_create(struct timeval *now, TimerProc *timer_proc, + ClientData client_data, long msecs, int periodic) +{ + Timer *tmr; + + if (free_timers != NULL) + { + tmr = free_timers; + free_timers = tmr->next; + } + else + { + tmr = (Timer*)httpd_malloc(sizeof(Timer)); + if (!tmr) + { + return NULL; + } + } + + tmr->timer_proc = timer_proc; + tmr->client_data = client_data; + tmr->msecs = msecs; + tmr->periodic = periodic; + + if (now != NULL) + { + tmr->time = *now; + } + else + { + (void)gettimeofday(&tmr->time, NULL); + } + + tmr->time.tv_sec += msecs / 1000L; + tmr->time.tv_usec += (msecs % 1000L) * 1000L; + if (tmr->time.tv_usec >= 1000000L) + { + tmr->time.tv_sec += tmr->time.tv_usec / 1000000L; + tmr->time.tv_usec %= 1000000L; + } + tmr->hash = hash(tmr); + + /* Add the new timer to the proper active list. */ + + l_add(tmr); + return tmr; +} + +long tmr_mstimeout(struct timeval *now) +{ + int h; + int gotone; + long msecs, m; + register Timer *tmr; + + gotone = 0; + msecs = 0; + + /* Since the lists are sorted, we only need to look at the * first timer on + * each one. + */ + + for (h = 0; h < HASH_SIZE; ++h) + { + tmr = timers[h]; + if (tmr != NULL) + { + m = (tmr->time.tv_sec - now->tv_sec) * 1000L + + (tmr->time.tv_usec - now->tv_usec) / 1000L; + if (!gotone) + { + msecs = m; + gotone = 1; + } + else if (m < msecs) + { + msecs = m; + } + } + } + + if (!gotone) + { + return INFTIM; + } + + if (msecs <= 0) + { + msecs = 0; + } + + return msecs; +} + +void tmr_run(struct timeval *now) +{ + int h; + Timer *tmr; + Timer *next; + + for (h = 0; h < HASH_SIZE; ++h) + { + for (tmr = timers[h]; tmr != NULL; tmr = next) + { + next = tmr->next; + + /* Since the lists are sorted, as soon as we find a timer * that isn'tmr + * ready yet, we can go on to the next list + */ + + if (tmr->time.tv_sec > now->tv_sec || + (tmr->time.tv_sec == now->tv_sec && tmr->time.tv_usec > now->tv_usec)) + { + break; + } + + (tmr->timer_proc)(tmr->client_data, now); + if (tmr->periodic) + { + /* Reschedule. */ + + tmr->time.tv_sec += tmr->msecs / 1000L; + tmr->time.tv_usec += (tmr->msecs % 1000L) * 1000L; + if (tmr->time.tv_usec >= 1000000L) + { + tmr->time.tv_sec += tmr->time.tv_usec / 1000000L; + tmr->time.tv_usec %= 1000000L; + } + l_resort(tmr); + } + else + { + tmr_cancel(tmr); + } + } + } +} + +void tmr_cancel(Timer *tmr) +{ + /* Remove it from its active list. */ + + l_remove(tmr); + + /* And put it on the free list. */ + + tmr->next = free_timers; + free_timers = tmr; + tmr->prev = NULL; +} + +void tmr_cleanup(void) +{ + Timer *tmr; + + while (free_timers != NULL) + { + tmr = free_timers; + free_timers = tmr->next; + httpd_free((void*)tmr); + } +} + +void tmr_destroy(void) +{ + int h; + + for (h = 0; h < HASH_SIZE; ++h) + { + while (timers[h] != NULL) + { + tmr_cancel(timers[h]); + } + } + tmr_cleanup(); +} |