This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
@@ -57,6 +57,29 @@ struct channel_s {
CHANNEL_CLOSE_FOR_ERROR
} reason_for_closing;
/** State variable for use by the scheduler */
enum {
/*
* The channel is not open, or it has a full output buffer but no queued
* cells.
*/
SCHED_CHAN_IDLE = 0,
/*
* The channel has space on its output buffer to write, but no queued
* cells.
*/
SCHED_CHAN_WAITING_FOR_CELLS,
/*
* The scheduler has queued cells but no output buffer space to write.
*/
SCHED_CHAN_WAITING_TO_WRITE,
/*
* The scheduler has both queued cells and output buffer space, and is
* eligible for the scheduler loop.
*/
SCHED_CHAN_PENDING
} scheduler_state;
/** Timestamps for both cell channels and listeners */
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
@@ -24,12 +24,13 @@
#defineSCHED_Q_HIGH_WATER (2 * SCHED_Q_LOW_WATER)
/*
* Write scheduling works by keeping track of lists of channels that can
* Write scheduling works by keeping track of which channels can
* accept cells, and have cells to write. From the scheduler's perspective,
* a channel can be in four possible states:
*
* 1.) Not open for writes, no cells to send
* - Not much to do here, and the channel will appear in neither list.
* - Not much to do here, and the channel will have scheduler_state ==
* SCHED_CHAN_IDLE
* - Transitions from:
* - Open for writes/has cells by simultaneously draining all circuit
* queues and filling the output buffer.
@@ -41,7 +42,8 @@
*
* 2.) Open for writes, no cells to send
* - Not much here either; this will be the state an idle but open channel
* can be expected to settle in.
* can be expected to settle in. It will have scheduler_state ==
* SCHED_CHAN_WAITING_FOR_CELLS
* - Transitions from:
* - Not open for writes/no cells by flushing some of the output
* buffer.
@@ -55,6 +57,7 @@
* 3.) Not open for writes, cells to send
* - This is the state of a busy circuit limited by output bandwidth;
* cells have piled up in the circuit queues waiting to be relayed.
* The channel will have scheduler_state == SCHED_CHAN_WAITING_TO_WRITE.
* - Transitions from:
* - Not open for writes/no cells by arrival of cells on an attached
* circuit
@@ -66,7 +69,8 @@
*
* 4.) Open for writes, cells to send
* - This connection is ready to relay some cells and waiting for
* the scheduler to choose it
* the scheduler to choose it. The channel will have scheduler_state ==
* SCHED_CHAN_PENDING.
* - Transitions from:
* - Not open for writes/has cells by the connection_or_flushed_some()
* path
@@ -91,29 +95,11 @@
/* Scheduler global data structures */
/*
* We keep lists of channels that either have cells queued, can accept
* writes, or both (states 2, 3 and 4 above) - no explicit list of state
* 1 channels is kept, so we don't have to worry about registering new
* channels here or anything. The scheduler will learn about them when
* it needs to. We can check how many channels in state 4 in O(1), so
* the test whether we have anything to do in scheduler_run() is fast
* and there's no harm in calling it opportunistically whenever we get
* the chance.
*
* Note that it takes time O(n) to search for a channel in these smartlists
* or move one; I don't think the number of channels on a relay will be large
* enough for this to be a severe problem, but this would benefit from using
* a doubly-linked list rather than smartlist_t, together with a hash map from
* channel identifiers to pointers to list entries, so we can perform those
* operations in O(log(n)).
* We keep a list of channels that are pending - i.e, have cells to write
* and can accept them to send. The enum scheduler_state in channel_t
* is reserved for our use.
*/
/* List of channels that can write but have no cells (state 2 above) */