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;
|
||||
/** Start time (in ticks) */
|
||||
unsigned long start;
|
||||
/** Retry count */
|
||||
unsigned int count;
|
||||
/** Timer expired callback
|
||||
*
|
||||
* @v timer Retry timer
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
*
|
||||
* 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,6 +99,9 @@ void stop_timer ( struct retry_timer *timer ) {
|
|||
* t := ( 7 t / 8 ) + ( r / 2 )
|
||||
*
|
||||
*/
|
||||
if ( timer->count ) {
|
||||
timer->count--;
|
||||
} else {
|
||||
timer->timeout -= ( timer->timeout >> 3 );
|
||||
timer->timeout += ( runtime >> 1 );
|
||||
if ( timer->timeout != old_timeout ) {
|
||||
|
@ -101,6 +109,30 @@ void stop_timer ( struct retry_timer *timer ) {
|
|||
( ( 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 );
|
||||
|
|
Loading…
Reference in New Issue