Skip to content

Commit

Permalink
ofproto-dpif-upcall: Allow main thread to pause all revalidators.
Browse files Browse the repository at this point in the history
This commit adds logic using ovs barrier to allow main thread pause
all revalidators.  This new feature will be used in a later patch.

Signed-off-by: Alex Wang <ee07b291@gmail.com>
Acked-by: Joe Stringer <joestringer@nicira.com>
  • Loading branch information
yew011 committed Sep 2, 2015
1 parent 8d6e551 commit dba82d3
Showing 1 changed file with 63 additions and 0 deletions.
63 changes: 63 additions & 0 deletions ofproto/ofproto-dpif-upcall.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ struct udpif {
struct seq *dump_seq; /* Increments each dump iteration. */
atomic_bool enable_ufid; /* If true, skip dumping flow attrs. */

/* These variables provide a mechanism for the main thread to pause
* all revalidation without having to completely shut the threads down.
* 'pause_latch' is shared between the main thread and the lead
* revalidator thread, so when it is desirable to halt revalidation, the
* main thread will set the latch. 'pause' and 'pause_barrier' are shared
* by revalidator threads. The lead revalidator will set 'pause' when it
* observes the latch has been set, and this will cause all revalidator
* threads to wait on 'pause_barrier' at the beginning of the next
* revalidation round. */
bool pause; /* Set by leader on 'pause_latch. */
struct latch pause_latch; /* Set to force revalidators pause. */
struct ovs_barrier pause_barrier; /* Barrier used to pause all */
/* revalidators by main thread. */

/* There are 'N_UMAPS' maps containing 'struct udpif_key' elements.
*
* During the flow dump phase, revalidators insert into these with a random
Expand Down Expand Up @@ -267,10 +281,13 @@ static void handle_upcalls(struct udpif *, struct upcall *, size_t n_upcalls);
static void udpif_stop_threads(struct udpif *);
static void udpif_start_threads(struct udpif *, size_t n_handlers,
size_t n_revalidators);
static void udpif_pause_revalidators(struct udpif *);
static void udpif_resume_revalidators(struct udpif *);
static void *udpif_upcall_handler(void *);
static void *udpif_revalidator(void *);
static unsigned long udpif_get_n_flows(struct udpif *);
static void revalidate(struct revalidator *);
static void revalidator_pause(struct revalidator *);
static void revalidator_sweep(struct revalidator *);
static void revalidator_purge(struct revalidator *);
static void upcall_unixctl_show(struct unixctl_conn *conn, int argc,
Expand Down Expand Up @@ -356,6 +373,7 @@ udpif_create(struct dpif_backer *backer, struct dpif *dpif)
udpif->reval_seq = seq_create();
udpif->dump_seq = seq_create();
latch_init(&udpif->exit_latch);
latch_init(&udpif->pause_latch);
list_push_back(&all_udpifs, &udpif->list_node);
atomic_init(&udpif->enable_ufid, false);
atomic_init(&udpif->n_flows, 0);
Expand Down Expand Up @@ -401,6 +419,7 @@ udpif_destroy(struct udpif *udpif)

list_remove(&udpif->list_node);
latch_destroy(&udpif->exit_latch);
latch_destroy(&udpif->pause_latch);
seq_destroy(udpif->reval_seq);
seq_destroy(udpif->dump_seq);
ovs_mutex_destroy(&udpif->n_flows_mutex);
Expand Down Expand Up @@ -440,6 +459,7 @@ udpif_stop_threads(struct udpif *udpif)
latch_poll(&udpif->exit_latch);

ovs_barrier_destroy(&udpif->reval_barrier);
ovs_barrier_destroy(&udpif->pause_barrier);

free(udpif->revalidators);
udpif->revalidators = NULL;
Expand Down Expand Up @@ -479,7 +499,9 @@ udpif_start_threads(struct udpif *udpif, size_t n_handlers,
dpif_enable_upcall(udpif->dpif);

ovs_barrier_init(&udpif->reval_barrier, udpif->n_revalidators);
ovs_barrier_init(&udpif->pause_barrier, udpif->n_revalidators + 1);
udpif->reval_exit = false;
udpif->pause = false;
udpif->revalidators = xzalloc(udpif->n_revalidators
* sizeof *udpif->revalidators);
for (i = 0; i < udpif->n_revalidators; i++) {
Expand All @@ -492,6 +514,25 @@ udpif_start_threads(struct udpif *udpif, size_t n_handlers,
}
}

/* Pauses all revalidators. Should only be called by the main thread.
* When function returns, all revalidators are paused and will proceed
* only after udpif_resume_revalidators() is called. */
static void
udpif_pause_revalidators(struct udpif *udpif)
{
latch_set(&udpif->pause_latch);
ovs_barrier_block(&udpif->pause_barrier);
}

/* Resumes the pausing of revalidators. Should only be called by the
* main thread. */
static void
udpif_resume_revalidators(struct udpif *udpif)
{
latch_poll(&udpif->pause_latch);
ovs_barrier_block(&udpif->pause_barrier);
}

/* Tells 'udpif' how many threads it should use to handle upcalls.
* 'n_handlers' and 'n_revalidators' can never be zero. 'udpif''s
* datapath handle must have packet reception enabled before starting
Expand Down Expand Up @@ -774,6 +815,12 @@ udpif_revalidator(void *arg)
udpif->max_n_flows = MAX(n_flows, udpif->max_n_flows);
udpif->avg_n_flows = (udpif->avg_n_flows + n_flows) / 2;

/* Only the leader checks the pause latch to prevent a race where
* some threads think it's false and proceed to block on
* reval_barrier and others think it's true and block indefinitely
* on the pause_barrier */
udpif->pause = latch_is_set(&udpif->pause_latch);

/* Only the leader checks the exit latch to prevent a race where
* some threads think it's true and exit and others think it's
* false and block indefinitely on the reval_barrier */
Expand All @@ -790,6 +837,10 @@ udpif_revalidator(void *arg)

/* Wait for the leader to start the flow dump. */
ovs_barrier_block(&udpif->reval_barrier);
if (udpif->pause) {
revalidator_pause(revalidator);
}

if (udpif->reval_exit) {
break;
}
Expand Down Expand Up @@ -832,6 +883,7 @@ udpif_revalidator(void *arg)
poll_timer_wait_until(start_time + MIN(ofproto_max_idle, 500));
seq_wait(udpif->reval_seq, last_reval_seq);
latch_wait(&udpif->exit_latch);
latch_wait(&udpif->pause_latch);
poll_block();
}
}
Expand Down Expand Up @@ -2108,6 +2160,17 @@ revalidate(struct revalidator *revalidator)
ofpbuf_uninit(&odp_actions);
}

/* Pauses the 'revalidator', can only proceed after main thread
* calls udpif_resume_revalidators(). */
static void
revalidator_pause(struct revalidator *revalidator)
{
/* The first block is for sync'ing the pause with main thread. */
ovs_barrier_block(&revalidator->udpif->pause_barrier);
/* The second block is for pausing until main thread resumes. */
ovs_barrier_block(&revalidator->udpif->pause_barrier);
}

static void
revalidator_sweep__(struct revalidator *revalidator, bool purge)
{
Expand Down

0 comments on commit dba82d3

Please sign in to comment.