diff options
-rw-r--r-- | src/include/ipxe/retry.h | 36 | ||||
-rw-r--r-- | src/net/neighbour.c | 4 | ||||
-rw-r--r-- | src/net/retry.c | 68 | ||||
-rw-r--r-- | src/net/udp/dhcp.c | 5 |
4 files changed, 72 insertions, 41 deletions
diff --git a/src/include/ipxe/retry.h b/src/include/ipxe/retry.h index c514822b..76d45fbd 100644 --- a/src/include/ipxe/retry.h +++ b/src/include/ipxe/retry.h @@ -7,14 +7,14 @@ * */ -FILE_LICENCE ( GPL2_OR_LATER ); +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/list.h> -/** Default timeout value */ +/** Default minimum timeout value (in ticks) */ #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 ) /** A retry timer */ @@ -25,16 +25,18 @@ struct retry_timer { unsigned int running; /** Timeout value (in ticks) */ 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; - /** Maximum timeout value before failure (in ticks) + unsigned long min; + /** 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) */ unsigned long start; /** Retry count */ @@ -46,7 +48,7 @@ struct retry_timer { * * The timer will already be stopped when this method is * 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 ); /** Reference counter @@ -109,4 +111,18 @@ timer_running ( struct retry_timer *timer ) { 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 */ diff --git a/src/net/neighbour.c b/src/net/neighbour.c index d3961857..f70896a1 100644 --- a/src/net/neighbour.c +++ b/src/net/neighbour.c @@ -95,8 +95,8 @@ static struct neighbour * neighbour_create ( struct net_device *netdev, memcpy ( neighbour->net_dest, net_dest, net_protocol->net_addr_len ); timer_init ( &neighbour->timer, neighbour_expired, &neighbour->refcnt ); - neighbour->timer.min_timeout = NEIGHBOUR_MIN_TIMEOUT; - neighbour->timer.max_timeout = NEIGHBOUR_MAX_TIMEOUT; + set_timer_limits ( &neighbour->timer, NEIGHBOUR_MIN_TIMEOUT, + NEIGHBOUR_MAX_TIMEOUT ); INIT_LIST_HEAD ( &neighbour->tx_queue ); /* Transfer ownership to cache */ diff --git a/src/net/retry.c b/src/net/retry.c index 8f210bdc..035b324e 100644 --- a/src/net/retry.c +++ b/src/net/retry.c @@ -15,9 +15,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 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 <ipxe/timer.h> @@ -35,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * This implementation of the timer is designed to satisfy RFC 2988 * and therefore be usable as a TCP retransmission timer. - * * */ @@ -49,47 +52,59 @@ FILE_LICENCE ( GPL2_OR_LATER ); static LIST_HEAD ( timers ); /** - * Start timer + * Start timer with a specified timeout * * @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 * 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 ) { list_add ( &timer->list, &timers ); ref_get ( timer->refcnt ); + timer->running = 1; } + + /* Record start time */ timer->start = currticks(); - timer->running = 1; - - /* 0 means "use default timeout" */ - if ( timer->min_timeout == 0 ) - timer->min_timeout = DEFAULT_MIN_TIMEOUT; - /* We must never be less than MIN_TIMEOUT under any circumstances */ - if ( timer->min_timeout < MIN_TIMEOUT ) - timer->min_timeout = MIN_TIMEOUT; - /* Honor user-specified minimum timeout */ - if ( timer->timeout < timer->min_timeout ) - timer->timeout = timer->min_timeout; + + /* Record timeout */ + timer->timeout = timeout; DBG2 ( "Timer %p started at time %ld (expires at %ld)\n", timer, timer->start, ( timer->start + timer->timeout ) ); } /** - * Start timer with a specified fixed timeout + * Start 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 ) { - start_timer ( timer ); - timer->timeout = timeout; - DBG2 ( "Timer %p expiry time changed to %ld\n", - timer, ( timer->start + timer->timeout ) ); +void start_timer ( struct retry_timer *timer ) { + unsigned long timeout = timer->timeout; + unsigned long min; + + /* 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 ) { struct refcnt *refcnt = timer->refcnt; + unsigned long max = ( timer->max ? timer->max : DEFAULT_MAX_TIMEOUT ); int fail; /* Stop timer without performing RTT calculations */ @@ -162,10 +178,8 @@ static void timer_expired ( struct retry_timer *timer ) { /* Back off the timeout value */ timer->timeout <<= 1; - if ( timer->max_timeout == 0 ) /* 0 means "use default timeout" */ - timer->max_timeout = DEFAULT_MAX_TIMEOUT; - if ( ( fail = ( timer->timeout > timer->max_timeout ) ) ) - timer->timeout = timer->max_timeout; + if ( ( fail = ( timer->timeout > max ) ) ) + timer->timeout = max; DBG ( "Timer %p timeout backed off to %ld\n", timer, timer->timeout ); diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 2e75ac81..8fe2774f 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -278,8 +278,9 @@ static void dhcp_set_state ( struct dhcp_session *dhcp, dhcp->state = state; dhcp->start = currticks(); stop_timer ( &dhcp->timer ); - dhcp->timer.min_timeout = state->min_timeout_sec * TICKS_PER_SEC; - dhcp->timer.max_timeout = state->max_timeout_sec * TICKS_PER_SEC; + set_timer_limits ( &dhcp->timer, + ( state->min_timeout_sec * TICKS_PER_SEC ), + ( state->max_timeout_sec * TICKS_PER_SEC ) ); start_timer_nodelay ( &dhcp->timer ); } |