mirror of https://github.com/ipxe/ipxe.git
Towards an RFC2988-compliant timer.
parent
f0718d562f
commit
c3a4f3c5da
|
@ -17,6 +17,8 @@ struct retry_timer {
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
/** Start time (in ticks) */
|
/** Start time (in ticks) */
|
||||||
unsigned long start;
|
unsigned long start;
|
||||||
|
/** Retry count */
|
||||||
|
unsigned int count;
|
||||||
/** Timer expired callback
|
/** Timer expired callback
|
||||||
*
|
*
|
||||||
* @v timer Retry timer
|
* @v timer Retry timer
|
||||||
|
|
|
@ -29,6 +29,11 @@
|
||||||
*
|
*
|
||||||
* A retry timer is a binary exponential backoff timer. It can be
|
* A retry timer is a binary exponential backoff timer. It can be
|
||||||
* used to build automatic retransmission into network protocols.
|
* 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 */
|
/** Default timeout value */
|
||||||
|
@ -94,12 +99,39 @@ void stop_timer ( struct retry_timer *timer ) {
|
||||||
* t := ( 7 t / 8 ) + ( r / 2 )
|
* t := ( 7 t / 8 ) + ( r / 2 )
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
if ( timer->count ) {
|
||||||
|
timer->count--;
|
||||||
|
} else {
|
||||||
timer->timeout -= ( timer->timeout >> 3 );
|
timer->timeout -= ( timer->timeout >> 3 );
|
||||||
timer->timeout += ( runtime >> 1 );
|
timer->timeout += ( runtime >> 1 );
|
||||||
if ( timer->timeout != old_timeout ) {
|
if ( timer->timeout != old_timeout ) {
|
||||||
DBG ( "Timer updated to %dms\n",
|
DBG ( "Timer updated to %dms\n",
|
||||||
( ( 1000 * timer->timeout ) / TICKS_PER_SEC ) );
|
( ( 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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,22 +144,11 @@ static void retry_step ( struct process *process ) {
|
||||||
struct retry_timer *tmp;
|
struct retry_timer *tmp;
|
||||||
unsigned long now = currticks();
|
unsigned long now = currticks();
|
||||||
unsigned long used;
|
unsigned long used;
|
||||||
int fail;
|
|
||||||
|
|
||||||
list_for_each_entry_safe ( timer, tmp, &timers, list ) {
|
list_for_each_entry_safe ( timer, tmp, &timers, list ) {
|
||||||
used = ( now - timer->start );
|
used = ( now - timer->start );
|
||||||
if ( used >= timer->timeout ) {
|
if ( used >= timer->timeout )
|
||||||
/* Stop timer without performing RTT calculations */
|
timer_expired ( timer );
|
||||||
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 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule ( process );
|
schedule ( process );
|
||||||
|
|
Loading…
Reference in New Issue