[retry] Rewrite unrelicensable portions of retry.c

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/34/head
Michael Brown 2015-03-05 11:04:47 +00:00
parent bfbb2b8f1c
commit 47ad8fc1ba
4 changed files with 72 additions and 41 deletions

View File

@ -7,14 +7,14 @@
* *
*/ */
FILE_LICENCE ( GPL2_OR_LATER ); FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/list.h> #include <ipxe/list.h>
/** Default timeout value */ /** Default minimum timeout value (in ticks) */
#define DEFAULT_MIN_TIMEOUT ( TICKS_PER_SEC / 4 ) #define DEFAULT_MIN_TIMEOUT ( TICKS_PER_SEC / 4 )
/** Limit after which the timeout will be deemed permanent */ /** Default maximum timeout value (in ticks) */
#define DEFAULT_MAX_TIMEOUT ( 10 * TICKS_PER_SEC ) #define DEFAULT_MAX_TIMEOUT ( 10 * TICKS_PER_SEC )
/** A retry timer */ /** A retry timer */
@ -25,16 +25,18 @@ struct retry_timer {
unsigned int running; unsigned int running;
/** Timeout value (in ticks) */ /** Timeout value (in ticks) */
unsigned long timeout; unsigned long timeout;
/** Minimum timeout value (in ticks) /** Minimum timeout value (in ticks), or zero to use default
* *
* A value of zero means "use default timeout." * The timeout will never be reduced below this value.
*/ */
unsigned long min_timeout; unsigned long min;
/** Maximum timeout value before failure (in ticks) /** Maximum timeout value (in ticks), or zero to use default
* *
* A value of zero means "use default timeout." * The timeout will be deemed permanent (according to the
* failure indicator passed to expired()) when it exceeds this
* value.
*/ */
unsigned long max_timeout; unsigned long max;
/** Start time (in ticks) */ /** Start time (in ticks) */
unsigned long start; unsigned long start;
/** Retry count */ /** Retry count */
@ -46,7 +48,7 @@ struct retry_timer {
* *
* The timer will already be stopped when this method is * The timer will already be stopped when this method is
* called. The failure indicator will be True if the retry * called. The failure indicator will be True if the retry
* timeout has already exceeded @c MAX_TIMEOUT. * timeout has already exceeded @c max_timeout.
*/ */
void ( * expired ) ( struct retry_timer *timer, int over ); void ( * expired ) ( struct retry_timer *timer, int over );
/** Reference counter /** Reference counter
@ -109,4 +111,18 @@ timer_running ( struct retry_timer *timer ) {
return ( timer->running ); return ( timer->running );
} }
/**
* Set minimum and maximum timeouts
*
* @v timer Retry timer
* @v min Minimum timeout (in ticks), or zero to use default
* @v max Maximum timeout (in ticks), or zero to use default
*/
static inline __attribute__ (( always_inline )) void
set_timer_limits ( struct retry_timer *timer, unsigned long min,
unsigned long max ) {
timer->min = min;
timer->max = max;
}
#endif /* _IPXE_RETRY_H */ #endif /* _IPXE_RETRY_H */

View File

@ -95,8 +95,8 @@ static struct neighbour * neighbour_create ( struct net_device *netdev,
memcpy ( neighbour->net_dest, net_dest, memcpy ( neighbour->net_dest, net_dest,
net_protocol->net_addr_len ); net_protocol->net_addr_len );
timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt ); timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt );
neighbour->timer.min_timeout = NEIGHBOUR_MIN_TIMEOUT; set_timer_limits ( &neighbour->timer, NEIGHBOUR_MIN_TIMEOUT,
neighbour->timer.max_timeout = NEIGHBOUR_MAX_TIMEOUT; NEIGHBOUR_MAX_TIMEOUT );
INIT_LIST_HEAD ( &neighbour->tx_queue ); INIT_LIST_HEAD ( &neighbour->tx_queue );
/* Transfer ownership to cache */ /* Transfer ownership to cache */

View File

@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA. * 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/ */
FILE_LICENCE ( GPL2_OR_LATER ); FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h> #include <stddef.h>
#include <ipxe/timer.h> #include <ipxe/timer.h>
@ -36,7 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
* This implementation of the timer is designed to satisfy RFC 2988 * This implementation of the timer is designed to satisfy RFC 2988
* and therefore be usable as a TCP retransmission timer. * and therefore be usable as a TCP retransmission timer.
* *
*
*/ */
/* The theoretical minimum that the algorithm in stop_timer() can /* The theoretical minimum that the algorithm in stop_timer() can
@ -49,47 +52,59 @@ FILE_LICENCE ( GPL2_OR_LATER );
static LIST_HEAD ( timers ); static LIST_HEAD ( timers );
/** /**
* Start timer * Start timer with a specified timeout
* *
* @v timer Retry timer * @v timer Retry timer
* @v timeout Timeout, in ticks
* *
* This starts the timer running with the current timeout value. If * This starts the timer running with the specified timeout value. If
* stop_timer() is not called before the timer expires, the timer will * stop_timer() is not called before the timer expires, the timer will
* be stopped and the timer's callback function will be called. * be stopped and the timer's callback function will be called.
*/ */
void start_timer ( struct retry_timer *timer ) { void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) {
/* Add to list of running timers (if applicable) */
if ( ! timer->running ) { if ( ! timer->running ) {
list_add ( &timer->list, &timers ); list_add ( &timer->list, &timers );
ref_get ( timer->refcnt ); ref_get ( timer->refcnt );
timer->running = 1;
} }
timer->start = currticks();
timer->running = 1;
/* 0 means "use default timeout" */ /* Record start time */
if ( timer->min_timeout == 0 ) timer->start = currticks();
timer->min_timeout = DEFAULT_MIN_TIMEOUT;
/* We must never be less than MIN_TIMEOUT under any circumstances */ /* Record timeout */
if ( timer->min_timeout < MIN_TIMEOUT ) timer->timeout = timeout;
timer->min_timeout = MIN_TIMEOUT;
/* Honor user-specified minimum timeout */
if ( timer->timeout < timer->min_timeout )
timer->timeout = timer->min_timeout;
DBG2 ( "Timer %p started at time %ld (expires at %ld)\n", DBG2 ( "Timer %p started at time %ld (expires at %ld)\n",
timer, timer->start, ( timer->start + timer->timeout ) ); timer, timer->start, ( timer->start + timer->timeout ) );
} }
/** /**
* Start timer with a specified fixed timeout * Start timer
* *
* @v timer Retry timer * @v timer Retry timer
* @v timeout Timeout, in ticks *
* This starts the timer running with the current timeout value
* (rounded up to the minimum timeout value). If stop_timer() is not
* called before the timer expires, the timer will be stopped and the
* timer's callback function will be called.
*/ */
void start_timer_fixed ( struct retry_timer *timer, unsigned long timeout ) { void start_timer ( struct retry_timer *timer ) {
start_timer ( timer ); unsigned long timeout = timer->timeout;
timer->timeout = timeout; unsigned long min;
DBG2 ( "Timer %p expiry time changed to %ld\n",
timer, ( timer->start + timer->timeout ) ); /* Calculate minimum timeout */
min = ( timer->min ? timer->min : DEFAULT_MIN_TIMEOUT );
if ( min < MIN_TIMEOUT )
min = MIN_TIMEOUT;
/* Ensure timeout is at least the minimum */
if ( timeout < min )
timeout = min;
/* Start timer with this timeout */
start_timer_fixed ( timer, timeout );
} }
/** /**
@ -150,6 +165,7 @@ void stop_timer ( struct retry_timer *timer ) {
*/ */
static void timer_expired ( struct retry_timer *timer ) { static void timer_expired ( struct retry_timer *timer ) {
struct refcnt *refcnt = timer->refcnt; struct refcnt *refcnt = timer->refcnt;
unsigned long max = ( timer->max ? timer->max : DEFAULT_MAX_TIMEOUT );
int fail; int fail;
/* Stop timer without performing RTT calculations */ /* Stop timer without performing RTT calculations */
@ -162,10 +178,8 @@ static void timer_expired ( struct retry_timer *timer ) {
/* Back off the timeout value */ /* Back off the timeout value */
timer->timeout <<= 1; timer->timeout <<= 1;
if ( timer->max_timeout == 0 ) /* 0 means "use default timeout" */ if ( ( fail = ( timer->timeout > max ) ) )
timer->max_timeout = DEFAULT_MAX_TIMEOUT; timer->timeout = max;
if ( ( fail = ( timer->timeout > timer->max_timeout ) ) )
timer->timeout = timer->max_timeout;
DBG ( "Timer %p timeout backed off to %ld\n", DBG ( "Timer %p timeout backed off to %ld\n",
timer, timer->timeout ); timer, timer->timeout );

View File

@ -278,8 +278,9 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
dhcp->state = state; dhcp->state = state;
dhcp->start = currticks(); dhcp->start = currticks();
stop_timer ( &dhcp->timer ); stop_timer ( &dhcp->timer );
dhcp->timer.min_timeout = state->min_timeout_sec * TICKS_PER_SEC; set_timer_limits ( &dhcp->timer,
dhcp->timer.max_timeout = state->max_timeout_sec * TICKS_PER_SEC; ( state->min_timeout_sec * TICKS_PER_SEC ),
( state->max_timeout_sec * TICKS_PER_SEC ) );
start_timer_nodelay ( &dhcp->timer ); start_timer_nodelay ( &dhcp->timer );
} }