Main Page | Class List | File List | Class Members | File Members

tcptimer.c

Go to the documentation of this file.
00001 /* TCP timer code.
00002  *
00003  */
00004 
00005 #include <stdio.h>
00006 #include <pthread.h>
00007 #include <assert.h>
00008 #include <semaphore.h>
00009 
00010 #include "misc.h"
00011 #include "tcpproxy.h"
00012 #include "tcp.h"
00013 #include "tcptimer.h"
00014 
00015 /* Timer queue event structure. */
00016 typedef struct timerq_event {
00017     long time_left;             /* Time left to go (ms).                */
00018     long time_queued;           /* Time this entry was queued (ms).     */
00019     void (*func)(void *);       /* Function to call at time.            */
00020     void *arg;                  /* Pointer to function argument.        */
00021     struct timerq_event *next;  /* Next event in the timer queue.       */
00022 } Ttimerq_event;
00023 
00024 static const struct timespec tick = { TIMER_MTICK/1000, 1000000*TIMER_MTICK };
00025 static pthread_mutex_t timerq_mut = PTHREAD_MUTEX_INITIALIZER;
00026 static Ttimerq_event *timerq_head = NULL;
00027 
00028 /*----------------------------------------------------------------------
00029  * init_timer -  perform timer initialisation.
00030  *----------------------------------------------------------------------
00031  */
00032 void init_timer()
00033 {
00034     //DPRINT("init_timer: entered.\n");
00035 }
00036 
00037 /*----------------------------------------------------------------------
00038  * cleanup_timer -  performs timer cleanup
00039  *----------------------------------------------------------------------
00040  */
00041 void cleanup_timer()
00042 {
00043     Ttimerq_event *event;  /* Pointer to an event.  */
00044     int count = 0;
00045 
00046     //DPRINT("cleanup_timer: entered.\n");
00047 
00048     while(timerq_head != NULL) {
00049         event = timerq_head;
00050         timerq_head = timerq_head->next;
00051         xfree(event);
00052         count++;
00053     }
00054     
00055     if(count > 0)
00056         DPRINT("cleanup_timer: cleared %d events from the queue.\n", count);
00057 }
00058 
00059 /*----------------------------------------------------------------------
00060  * clear_timer -  clear the specified timer
00061  *                returns the time in milliseconds that the event spent
00062  *                in the queue, or -1 if the timer is not in the queue.
00063  *----------------------------------------------------------------------
00064  */
00065 long clear_timer(void (*func)(void *), void *arg)
00066 {
00067     Ttimerq_event *ptr, *prev_ptr;
00068     long dur;
00069     
00070     //DPRINT("clear_timer: entered.\n");
00071 
00072     mutex_lock("clear_timer", &timerq_mut);
00073 
00074     prev_ptr = NULL;
00075     for(ptr=timerq_head; ptr; ptr=ptr->next) {
00076         if(ptr->func == func && ptr->arg == arg) {
00077             //DPRINT("clear_timer: removing event.\n");
00078             /* Calculate time event spent in the queue. */
00079             dur = get_mclock() - ptr->time_queued;
00080 
00081             /* Remove event from queue. */
00082             if(prev_ptr)
00083                 prev_ptr->next = ptr->next;
00084             else
00085                 timerq_head = ptr->next;
00086             if(ptr->next)  /* Add time_left to next event in the queue. */
00087               ptr->next->time_left += ptr->time_left;
00088 
00089             mutex_unlock("clear_timer", &timerq_mut);
00090             xfree(ptr);
00091             return dur;
00092         }
00093     }
00094     mutex_unlock("clear_timer", &timerq_mut);
00095     return -1;
00096 }
00097 
00098 /*----------------------------------------------------------------------
00099  * clear_tcp_timer -  clear timers for the specified TCP connection
00100  *----------------------------------------------------------------------
00101  */
00102 void clear_tcp_timers(void *arg)
00103 {
00104     //DPRINT("clear_tcp_timers: entered.\n");
00105     clear_timer(tcp_timeout, arg);
00106 }
00107 
00108 /*----------------------------------------------------------------------
00109  * left_timer -  returns the time left for a timer, or -1 if the timer
00110  *               is not in the queue.
00111  *----------------------------------------------------------------------
00112  */
00113 long left_timer(void (*func)(void *), void *arg)
00114 {
00115     Ttimerq_event *ptr;
00116     long dur = 0;
00117     
00118     DPRINT("left_timer: entered.\n");
00119 
00120     mutex_lock("left_timer", &timerq_mut);
00121     for(ptr=timerq_head; ptr; ptr=ptr->next) {
00122         dur += ptr->time_left;
00123         if(ptr->func == func && ptr->arg == arg) {
00124             mutex_unlock("left_timer", &timerq_mut);
00125             return dur;
00126         }
00127     }
00128     mutex_unlock("left_timer", &timerq_mut);
00129     return -1;
00130 }
00131 
00132 /*----------------------------------------------------------------------
00133  * add_timer -  adds a TCP timer with pointers to the function to be
00134  *              called, and a tcp control block.
00135  *----------------------------------------------------------------------
00136  */
00137 int add_timer(long mdelay, void (*func)(void *), void *arg)
00138 {
00139     Ttimerq_event *event;
00140     Ttimerq_event *ptr, *prev_ptr;
00141     
00142     //DPRINT("add_timer: entered.\n");
00143 
00144     assert(mdelay >= 0);
00145 
00146     /* Allocate memory for and fill new event. */
00147     event = (Ttimerq_event *) xmalloc(sizeof(Ttimerq_event));
00148     event->time_left = mdelay;
00149     event->time_queued = get_mclock();
00150     event->func = func;
00151     event->arg = arg;
00152     event->next = NULL;
00153 
00154     clear_timer(func, arg);  /* Clear any duplicate timers. */
00155 
00156     mutex_lock("add_timer", &timerq_mut);
00157 
00158     if(timerq_head == NULL) {      /* Queue is empty, so just set head to event */
00159         //DPRINT("add_timer: queue empty, adding to head.\n");
00160         timerq_head = event;
00161         mutex_unlock("add_timer", &timerq_mut);
00162         return 0;
00163     }
00164 
00165     /* Search the list for insertion point. */
00166     prev_ptr = NULL;
00167     for(ptr=timerq_head; ptr; ptr=ptr->next) {
00168         if(event->time_left < ptr->time_left)  /* Need to insert event before ptr. */
00169             break;
00170         /* Decrement time left of new event by time left of events we pass. */
00171         event->time_left -= ptr->time_left;
00172         prev_ptr = ptr;
00173     }
00174 
00175     if(prev_ptr)
00176         prev_ptr->next = event;
00177     else
00178         timerq_head = event;
00179     event->next = ptr;
00180     if(ptr)
00181         ptr->time_left -= event->time_left;    
00182 
00183     mutex_unlock("add_timer", &timerq_mut);    
00184     return 0;
00185 }
00186 
00187 /*----------------------------------------------------------------------
00188  * tcp_timer -  entry point of timer thread
00189  *----------------------------------------------------------------------
00190  */
00191 void tcp_timer(void *sig_mask)
00192 {
00193     long now, last_run, delta;    /* Times in milliseconds.             */
00194     struct timespec time_rem;     /* Remaining time set by nanosleep.   */
00195     Ttimerq_event *event;         /* Temporary event variable.          */
00196     Ttimerq_event *expired_head;  /* Head of list of expired events.    */
00197     Ttimerq_event *expired_tail;  /* Tail of list of expired events.    */
00198 
00199     //DPRINT("tcp_timer: entered.\n");
00200 
00201     if(pthread_sigmask(SIG_BLOCK, sig_mask, NULL)) {
00202         EPRINT("tcp_timer: error blocking signals.\n");
00203     }
00204 
00205     last_run = get_mclock();
00206     
00207     while(!request_exit) {      
00208         while(nanosleep(&time_rem, &time_rem) == -1)
00209             DPRINT("tcp_timer: nanosleep returned -1, sleeping again.\n");
00210 
00211         mutex_lock("tcp_timer", &timerq_mut);
00212 
00213         now = get_mclock();
00214         delta = now - last_run;
00215 
00216         last_run = now;
00217         expired_head = timerq_head;
00218 
00219         /* Work through event list; expired events automatically
00220          * 'added' to expired list. */
00221         while(timerq_head != NULL && timerq_head->time_left <= delta) {
00222             delta -= timerq_head->time_left;
00223             timerq_head = timerq_head->next;
00224         }
00225         if(timerq_head != NULL)
00226             timerq_head->time_left -= delta;
00227 
00228         /* Assign timerq_hd to expired_tl (hd isn't usable with mutex unlocked. */
00229         expired_tail = timerq_head;
00230 
00231         mutex_unlock("tcp_timer", &timerq_mut);
00232 
00233         /* Now activate expired events, with timerq_mut unlocked. */
00234         while(expired_head != timerq_head) {
00235             event = expired_head;
00236             expired_head = expired_head->next;
00237             event->func(event->arg);  /* Call function. */
00238             xfree(event);           
00239         }
00240     }
00241 }

Generated on Sun May 14 13:36:52 2006 by  doxygen 1.4.2