aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-02-02 12:03:54 -0500
committerNick Mathewson <nickm@torproject.org>2018-02-02 12:03:54 -0500
commit9e48338a12fd1fef840dc49c702b4a628af67cc0 (patch)
tree66c5cfc1018caf8061b7dbb1e19fabfe484f07bf /src
parent0fd91772b1ece9e0f8adc270147f5a4164158473 (diff)
parent4ceae7c6b9742ce6b14f8bed34725e44522e52f2 (diff)
downloadtor-9e48338a12fd1fef840dc49c702b4a628af67cc0.tar.gz
tor-9e48338a12fd1fef840dc49c702b4a628af67cc0.zip
Merge branch 'maint-0.3.2'
Diffstat (limited to 'src')
-rw-r--r--src/or/scheduler.c26
-rw-r--r--src/test/test_scheduler.c12
2 files changed, 27 insertions, 11 deletions
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 931122f8d6..382b3e3ca9 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -644,17 +644,21 @@ scheduler_release_channel,(channel_t *chan))
return;
}
- if (chan->scheduler_state == SCHED_CHAN_PENDING) {
- if (SCHED_BUG(smartlist_pos(channels_pending, chan) == -1, chan)) {
- log_warn(LD_SCHED, "Scheduler asked to release channel %" PRIu64 " "
- "but it wasn't in channels_pending",
- chan->global_identifier);
- } else {
- smartlist_pqueue_remove(channels_pending,
- scheduler_compare_channels,
- offsetof(channel_t, sched_heap_idx),
- chan);
- }
+ /* Try to remove the channel from the pending list regardless of its
+ * scheduler state. We can release a channel in many places in the tor code
+ * so we can't rely on the channel state (PENDING) to remove it from the
+ * list.
+ *
+ * For instance, the channel can change state from OPEN to CLOSING while
+ * being handled in the scheduler loop leading to the channel being in
+ * PENDING state but not in the pending list. Furthermore, we release the
+ * channel when it changes state to close and a second time when we free it.
+ * Not ideal at all but for now that is the way it is. */
+ if (chan->sched_heap_idx != -1) {
+ smartlist_pqueue_remove(channels_pending,
+ scheduler_compare_channels,
+ offsetof(channel_t, sched_heap_idx),
+ chan);
}
if (the_scheduler->on_channel_free) {
diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c
index eac66dd27a..ebba71266c 100644
--- a/src/test/test_scheduler.c
+++ b/src/test/test_scheduler.c
@@ -495,6 +495,18 @@ perform_channel_state_tests(int KISTSchedRunInterval, int sched_type)
scheduler_touch_channel(ch1);
tt_assert(scheduler_compare_channels_mock_ctr > old_count);
+ /* Release the ch2 and then do it another time to make sure it doesn't blow
+ * up and we are still in a quiescent state. */
+ scheduler_release_channel(ch2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
+ /* Cheat a bit so make the release more confused but also will tells us if
+ * the release did put the channel in the right state. */
+ ch2->scheduler_state = SCHED_CHAN_PENDING;
+ scheduler_release_channel(ch2);
+ tt_int_op(ch2->scheduler_state, OP_EQ, SCHED_CHAN_IDLE);
+ tt_int_op(smartlist_len(channels_pending), OP_EQ, 1);
+
/* Close */
channel_mark_for_close(ch1);
tt_int_op(ch1->state, OP_EQ, CHANNEL_STATE_CLOSING);