mirror of https://github.com/ipxe/ipxe.git
[retry] Rewrite unrelicensable portions of retry.c
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/34/head
parent
bfbb2b8f1c
commit
47ad8fc1ba
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue