Implement circuitmux_make_circuit_inactive(), circuitmux_make_circuit_active() and linked list helper functions in circuitmux.c

This commit is contained in:
Andrea Shepard 2012-09-26 15:04:29 -07:00
parent fd31dd440c
commit 38fa3b7e44

View File

@ -85,7 +85,7 @@ struct circuitmux_s {
* free up on this connection's outbuf. Every time we pull cells from
* a circuit, we advance this pointer to the next circuit in the ring.
*/
struct circuit_t *active_circuits;
struct circuit_t *active_circuits_head, *active_circuits_tail;
/*
* Priority queue of cell_ewma_t for circuits with queued cells waiting
@ -140,9 +140,49 @@ static INLINE unsigned int
chanid_circid_entry_hash(chanid_circid_muxinfo_t *a);
static chanid_circid_muxinfo_t *
circuitmux_find_map_entry(circuitmux_t *cmux, circuit_t *circ);
static void
circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction);
static void
circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction);
static INLINE circuit_t **
circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
static INLINE circuit_t **
circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ);
/* Function definitions */
/**
* Linked list helpers
*/
static INLINE circuit_t **
circuitmux_next_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
{
tor_assert(cmux);
tor_assert(circ);
if (circ->n_mux == cmux) return &(circ->next_active_on_n_chan);
else {
tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
return &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
}
}
static INLINE circuit_t **
circuitmux_prev_active_circ_p(circuitmux_t *cmux, circuit_t *circ)
{
tor_assert(cmux);
tor_assert(circ);
if (circ->n_mux == cmux) return &(circ->prev_active_on_n_chan);
else {
tor_assert(TO_OR_CIRCUIT(circ)->p_mux == cmux);
return &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
}
}
/**
* Helper for chanid_circid_cell_count_map_t hash table: compare the channel
* ID and circuit ID for a and b, and return less than, equal to, or greater
@ -225,12 +265,16 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux)
if (to_remove->muxinfo.direction == CELL_DIRECTION_OUT) {
/* Clear n_mux */
circ->n_mux = NULL;
/* Update active_circuits et al. */
circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_OUT);
} else if (circ->magic == OR_CIRCUIT_MAGIC) {
/*
* It has a sensible p_chan and direction == CELL_DIRECTION_IN,
* so clear p_mux.
*/
TO_OR_CIRCUIT(circ)->p_mux = NULL;
/* Update active_circuits et al. */
circuitmux_make_circuit_inactive(cmux, circ, CELL_DIRECTION_IN);
} else {
/* Complain and move on */
log_warn(LD_CIRC,
@ -239,8 +283,6 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux)
to_remove->circ_id,
U64_PRINTF_ARG(to_remove->chan_id));
}
/* TODO update active_circuits / active_circuit_pqueue */
} else {
/* Complain and move on */
log_warn(LD_CIRC,
@ -432,7 +474,6 @@ circuitmux_num_cells_for_circuit(circuitmux_t *cmux, circuit_t *circ)
return n_cells;
}
/**
* Query total number of available cells on a circuitmux
*/
@ -548,14 +589,14 @@ circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
*/
if (hashent->muxinfo.cell_count > 0 && cell_count == 0) {
--(cmux->n_active_circuits);
circuitmux_make_circuit_inactive(cmux, circ, direction);
} else if (hashent->muxinfo.cell_count == 0 && cell_count > 0) {
++(cmux->n_active_circuits);
circuitmux_make_circuit_active(cmux, circ, direction);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
cmux->n_cells += cell_count;
hashent->muxinfo.cell_count = cell_count;
/* TODO update active_circuits / active_circuit_pqueue */
} else {
/*
* New circuit; add an entry and update the circuit/active circuit
@ -601,8 +642,6 @@ circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
circuitmux_make_circuit_active(cmux, circ, direction);
}
cmux->n_cells += cell_count;
/* TODO update active_circuits / active_circuit_pqueue */
}
}
@ -651,9 +690,11 @@ circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
if (hashent) {
/* Update counters */
--(cmux->n_circuits);
if (hashent->muxinfo.cell_count > 0) --(cmux->n_active_circuits);
if (hashent->muxinfo.cell_count > 0) {
--(cmux->n_active_circuits);
circuitmux_make_circuit_inactive(cmux, circ, last_searched_direction);
}
cmux->n_cells -= hashent->muxinfo.cell_count;
/* TODO update active_circuits / active_circuit_pqueue */
/* Consistency check: the direction must match the direction searched */
tor_assert(last_searched_direction == hashent->muxinfo.direction);
@ -666,6 +707,180 @@ circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
}
}
/**
* Make a circuit active; update active list and policy-specific info, but
* we don't mess with the counters or hash table here.
*/
static void
circuitmux_make_circuit_active(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction)
{
circuit_t **next_active = NULL, **prev_active = NULL, **next_prev = NULL;
circuitmux_t *circuit_cmux = NULL;
channel_t *chan = NULL;
circid_t circ_id;
int already_active;
tor_assert(cmux);
tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_OUT ||
direction == CELL_DIRECTION_IN);
/* Get the right set of active list links for this direction */
if (direction == CELL_DIRECTION_OUT) {
next_active = &(circ->next_active_on_n_chan);
prev_active = &(circ->prev_active_on_n_chan);
circuit_cmux = circ->n_mux;
chan = circ->n_chan;
circ_id = circ->n_circ_id;
} else {
next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
chan = TO_OR_CIRCUIT(circ)->p_chan;
circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
}
/* Assert that it is attached to this mux and a channel */
tor_assert(cmux == circuit_cmux);
tor_assert(chan != NULL);
/*
* Check if the circuit really was inactive; if it's active, at least one
* of the next_active and prev_active pointers will not be NULL, or this
* circuit will be either the head or tail of the list for this cmux.
*/
already_active = (*prev_active != NULL || *next_active != NULL ||
cmux->active_circuits_head == circ ||
cmux->active_circuits_tail == circ);
/* If we're already active, log a warning and finish */
if (already_active) {
log_warn(LD_CIRC,
"Circuit %d on channel " U64_FORMAT " was already active",
circ_id, U64_PRINTF_ARG(chan->global_identifier));
return;
}
/*
* This is going at the head of the list; if the old head is not NULL,
* then its prev pointer should point to this.
*/
*next_active = cmux->active_circuits_head; /* Next is old head */
*prev_active = NULL; /* Prev is NULL (this will be the head) */
if (cmux->active_circuits_head) {
/* The list had an old head; update its prev pointer */
next_prev =
circuitmux_prev_active_circ_p(cmux, cmux->active_circuits_head);
tor_assert(next_prev);
*next_prev = circ;
} else {
/* The list was empty; this becomes the tail as well */
cmux->active_circuits_tail = circ;
}
/* This becomes the new head of the list */
cmux->active_circuits_head = circ;
/* TODO policy-specific notifications */
}
/**
* Make a circuit inactive; update active list and policy-specific info, but
* we don't mess with the counters or hash table here.
*/
static void
circuitmux_make_circuit_inactive(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction)
{
circuit_t **next_active = NULL, **prev_active = NULL;
circuit_t **next_prev = NULL, **prev_next = NULL;
circuitmux_t *circuit_cmux = NULL;
channel_t *chan = NULL;
circid_t circ_id;
int already_inactive;
tor_assert(cmux);
tor_assert(circ);
tor_assert(direction == CELL_DIRECTION_OUT ||
direction == CELL_DIRECTION_IN);
/* Get the right set of active list links for this direction */
if (direction == CELL_DIRECTION_OUT) {
next_active = &(circ->next_active_on_n_chan);
prev_active = &(circ->prev_active_on_n_chan);
circuit_cmux = circ->n_mux;
chan = circ->n_chan;
circ_id = circ->n_circ_id;
} else {
next_active = &(TO_OR_CIRCUIT(circ)->next_active_on_p_chan);
prev_active = &(TO_OR_CIRCUIT(circ)->prev_active_on_p_chan);
circuit_cmux = TO_OR_CIRCUIT(circ)->p_mux;
chan = TO_OR_CIRCUIT(circ)->p_chan;
circ_id = TO_OR_CIRCUIT(circ)->p_circ_id;
}
/* Assert that it is attached to this mux and a channel */
tor_assert(cmux == circuit_cmux);
tor_assert(chan != NULL);
/*
* Check if the circuit really was active; if it's inactive, the
* next_active and prev_active pointers will be NULL and this circuit
* will not be the head or tail of the list for this cmux.
*/
already_inactive = (*prev_active == NULL && *next_active == NULL &&
cmux->active_circuits_head != circ &&
cmux->active_circuits_tail != circ);
/* If we're already inactive, log a warning and finish */
if (already_inactive) {
log_warn(LD_CIRC,
"Circuit %d on channel " U64_FORMAT " was already inactive",
circ_id, U64_PRINTF_ARG(chan->global_identifier));
return;
}
/* Remove from the list; first get next_prev and prev_next */
if (*next_active) {
/*
* If there's a next circuit, its previous circuit becomes this
* circuit's previous circuit.
*/
next_prev = circuitmux_prev_active_circ_p(cmux, *next_active);
} else {
/* Else, the tail becomes this circuit's previous circuit */
next_prev = &(cmux->active_circuits_tail);
}
/* Got next_prev, now prev_next */
if (*prev_active) {
/*
* If there's a previous circuit, its next circuit becomes this circuit's
* next circuit.
*/
prev_next = circuitmux_next_active_circ_p(cmux, *prev_active);
} else {
/* Else, the head becomes this circuit's next circuit */
prev_next = &(cmux->active_circuits_head);
}
/* Assert that we got sensible values for the next/prev pointers */
tor_assert(next_prev != NULL);
tor_assert(prev_next != NULL);
/* Update the next/prev pointers - this removes circ from the list */
*next_prev = *prev_active;
*prev_next = *next_active;
/* Now null out prev_active/next_active */
*prev_active = NULL;
*next_active = NULL;
/* TODO policy-specific notifications */
}
/**
* Clear the cell counter for a circuit on a circuitmux
*/
@ -705,11 +920,11 @@ circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
*/
if (hashent->muxinfo.cell_count > 0 && n_cells == 0) {
--(cmux->n_active_circuits);
/* TODO update active_circuits / active_circuit_pqueue */
circuitmux_make_circuit_inactive(cmux, circ, hashent->muxinfo.direction);
/* Is the old cell count == 0 and the new cell count > 0 ? */
} else if (hashent->muxinfo.cell_count == 0 && n_cells > 0) {
++(cmux->n_active_circuits);
/* TODO update active_circuits / active_circuit_pqueue */
circuitmux_make_circuit_active(cmux, circ, hashent->muxinfo.direction);
}
/* Update hash entry cell counter */