X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Freconnect.c;h=f159f01c0bb526e8f52aca348703885b626258e8;hb=0f07ce33c49ce522d69c0e6aab8ca7ce0757e98c;hp=fadeeb89b20a834522093786698cc45ef5d6a65c;hpb=3ed497fc10033c9857140270d60ef6aa2d7c0c08;p=openvswitch diff --git a/lib/reconnect.c b/lib/reconnect.c index fadeeb89..f159f01c 100644 --- a/lib/reconnect.c +++ b/lib/reconnect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,10 +28,11 @@ #define STATES \ STATE(VOID, 1 << 0) \ STATE(BACKOFF, 1 << 1) \ - STATE(CONNECTING, 1 << 2) \ - STATE(ACTIVE, 1 << 3) \ - STATE(IDLE, 1 << 4) \ - STATE(RECONNECT, 1 << 5) + STATE(START_CONNECT, 1 << 2) \ + STATE(CONNECT_IN_PROGRESS, 1 << 3) \ + STATE(ACTIVE, 1 << 4) \ + STATE(IDLE, 1 << 5) \ + STATE(RECONNECT, 1 << 6) enum state { #define STATE(NAME, VALUE) S_##NAME = VALUE, STATES @@ -57,6 +58,7 @@ struct reconnect { int backoff; long long int last_received; long long int last_connected; + unsigned int max_tries; /* These values are simply for statistics reporting, not otherwise used * directly by anything internal. */ @@ -69,6 +71,7 @@ struct reconnect { static void reconnect_transition__(struct reconnect *, long long int now, enum state state); static long long int reconnect_deadline__(const struct reconnect *); +static bool reconnect_may_retry(struct reconnect *); static const char * reconnect_state_name__(enum state state) @@ -99,6 +102,7 @@ reconnect_create(long long int now) fsm->backoff = 0; fsm->last_received = now; fsm->last_connected = now; + fsm->max_tries = UINT_MAX; fsm->creation_time = now; return fsm; @@ -160,6 +164,26 @@ reconnect_get_probe_interval(const struct reconnect *fsm) return fsm->probe_interval; } +/* Limits the maximum number of times that 'fsm' will ask the client to try to + * reconnect to 'max_tries'. UINT_MAX (the default) means an unlimited number + * of tries. + * + * After the number of tries has expired, the 'fsm' will disable itself + * instead of backing off and retrying. */ +void +reconnect_set_max_tries(struct reconnect *fsm, unsigned int max_tries) +{ + fsm->max_tries = max_tries; +} + +/* Returns the current remaining number of connection attempts, UINT_MAX if + * the number is unlimited. */ +unsigned int +reconnect_get_max_tries(struct reconnect *fsm) +{ + return fsm->max_tries; +} + /* Configures the backoff parameters for 'fsm'. 'min_backoff' is the minimum * number of milliseconds, and 'max_backoff' is the maximum, between connection * attempts. @@ -213,7 +237,7 @@ reconnect_is_enabled(const struct reconnect *fsm) void reconnect_enable(struct reconnect *fsm, long long int now) { - if (fsm->state == S_VOID) { + if (fsm->state == S_VOID && reconnect_may_retry(fsm)) { reconnect_transition__(fsm, now, S_BACKOFF); fsm->backoff = 0; } @@ -236,7 +260,8 @@ reconnect_disable(struct reconnect *fsm, long long int now) void reconnect_force_reconnect(struct reconnect *fsm, long long int now) { - if (fsm->state & (S_CONNECTING | S_ACTIVE | S_IDLE)) { + if (fsm->state & (S_START_CONNECT | S_CONNECT_IN_PROGRESS + | S_ACTIVE | S_IDLE)) { reconnect_transition__(fsm, now, S_RECONNECT); } } @@ -250,7 +275,7 @@ reconnect_force_reconnect(struct reconnect *fsm, long long int now) void reconnect_disconnected(struct reconnect *fsm, long long int now, int error) { - if (fsm->state != S_BACKOFF) { + if (!(fsm->state & (S_BACKOFF | S_VOID))) { /* Report what happened. */ if (fsm->state & (S_ACTIVE | S_IDLE)) { if (error > 0) { @@ -285,7 +310,9 @@ reconnect_disconnected(struct reconnect *fsm, long long int now, int error) VLOG_INFO("%s: waiting %.3g seconds before reconnect\n", fsm->name, fsm->backoff / 1000.0); } - reconnect_transition__(fsm, now, S_BACKOFF); + + reconnect_transition__(fsm, now, + reconnect_may_retry(fsm) ? S_BACKOFF : S_VOID); } } @@ -296,9 +323,9 @@ reconnect_disconnected(struct reconnect *fsm, long long int now, int error) void reconnect_connecting(struct reconnect *fsm, long long int now) { - if (fsm->state != S_CONNECTING) { + if (fsm->state != S_CONNECT_IN_PROGRESS) { VLOG_INFO("%s: connecting...", fsm->name); - reconnect_transition__(fsm, now, S_CONNECTING); + reconnect_transition__(fsm, now, S_CONNECT_IN_PROGRESS); } } @@ -346,7 +373,7 @@ static void reconnect_transition__(struct reconnect *fsm, long long int now, enum state state) { - if (fsm->state == S_CONNECTING) { + if (fsm->state == S_CONNECT_IN_PROGRESS) { fsm->n_attempted_connections++; if (state == S_ACTIVE) { fsm->n_successful_connections++; @@ -375,7 +402,8 @@ reconnect_deadline__(const struct reconnect *fsm) case S_BACKOFF: return fsm->state_entered + fsm->backoff; - case S_CONNECTING: + case S_START_CONNECT: + case S_CONNECT_IN_PROGRESS: return fsm->state_entered + MAX(1000, fsm->backoff); case S_ACTIVE: @@ -432,7 +460,8 @@ reconnect_run(struct reconnect *fsm, long long int now) case S_BACKOFF: return RECONNECT_CONNECT; - case S_CONNECTING: + case S_START_CONNECT: + case S_CONNECT_IN_PROGRESS: return RECONNECT_DISCONNECT; case S_ACTIVE: @@ -453,7 +482,7 @@ reconnect_run(struct reconnect *fsm, long long int now) NOT_REACHED(); } else { - return fsm->state == S_CONNECTING ? RECONNECT_CONNECT : 0; + return fsm->state == S_START_CONNECT ? RECONNECT_CONNECT : 0; } } @@ -521,3 +550,13 @@ reconnect_get_stats(const struct reconnect *fsm, long long int now, stats->state = reconnect_state_name__(fsm->state); stats->state_elapsed = now - fsm->state_entered; } + +static bool +reconnect_may_retry(struct reconnect *fsm) +{ + bool may_retry = fsm->max_tries > 0; + if (may_retry && fsm->max_tries != UINT_MAX) { + fsm->max_tries--; + } + return may_retry; +}