Towards an RFC2988-compliant timer.
authorMichael Brown <mcb30@etherboot.org>
Wed, 9 Aug 2006 15:54:17 +0000 (15:54 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 9 Aug 2006 15:54:17 +0000 (15:54 +0000)
src/include/gpxe/retry.h
src/net/retry.c

index 8f197bc..7291db2 100644 (file)
@@ -17,6 +17,8 @@ struct retry_timer {
        unsigned long timeout;
        /** Start time (in ticks) */
        unsigned long start;
+       /** Retry count */
+       unsigned int count;
        /** Timer expired callback
         *
         * @v timer     Retry timer
index 531a1b9..07b4af4 100644 (file)
  *
  * A retry timer is a binary exponential backoff timer.  It can be
  * used to build automatic retransmission into network protocols.
+ *
+ * This implementation of the timer is designed to satisfy RFC 2988
+ * and therefore be usable as a TCP retransmission timer.
+ *
+ * 
  */
 
 /** Default timeout value */
@@ -94,14 +99,41 @@ void stop_timer ( struct retry_timer *timer ) {
         * t := ( 7 t / 8 ) + ( r / 2 )
         *
         */
-       timer->timeout -= ( timer->timeout >> 3 );
-       timer->timeout += ( runtime >> 1 );
-       if ( timer->timeout != old_timeout ) {
-               DBG ( "Timer updated to %dms\n",
-                     ( ( 1000 * timer->timeout ) / TICKS_PER_SEC ) );
+       if ( timer->count ) {
+               timer->count--;
+       } else {
+               timer->timeout -= ( timer->timeout >> 3 );
+               timer->timeout += ( runtime >> 1 );
+               if ( timer->timeout != old_timeout ) {
+                       DBG ( "Timer updated to %dms\n",
+                             ( ( 1000 * timer->timeout ) / TICKS_PER_SEC ) );
+               }
        }
 }
 
+/**
+ * Handle expired timer
+ *
+ * @v timer            Retry timer
+ */
+static void timer_expired ( struct retry_timer *timer ) {
+       int fail;
+
+       /* Stop timer without performing RTT calculations */
+       list_del ( &timer->list );
+       timer->count++;
+
+       /* Back off the timeout value */
+       timer->timeout <<= 1;
+       if ( ( fail = ( timer->timeout > MAX_TIMEOUT ) ) )
+               timer->timeout = MAX_TIMEOUT;
+       DBG ( "Timer backed off to %dms\n",
+             ( ( 1000 * timer->timeout ) / TICKS_PER_SEC ) );
+
+       /* Call expiry callback */
+       timer->expired ( timer, fail ); 
+}
+
 /**
  * Single-step the retry timer list
  *
@@ -112,22 +144,11 @@ static void retry_step ( struct process *process ) {
        struct retry_timer *tmp;
        unsigned long now = currticks();
        unsigned long used;
-       int fail;
 
        list_for_each_entry_safe ( timer, tmp, &timers, list ) {
                used = ( now - timer->start );
-               if ( used >= timer->timeout ) {
-                       /* Stop timer without performing RTT calculations */
-                       list_del ( &timer->list );
-                       /* Back off the timeout value */
-                       timer->timeout <<= 1;
-                       if ( ( fail = ( timer->timeout > MAX_TIMEOUT ) ) )
-                               timer->timeout = MAX_TIMEOUT;
-                       DBG ( "Timer backed off to %dms\n",
-                             ( ( 1000 * timer->timeout ) / TICKS_PER_SEC ) );
-                       /* Call expiry callback */
-                       timer->expired ( timer, fail );
-               }
+               if ( used >= timer->timeout )
+                       timer_expired ( timer );
        }
 
        schedule ( process );