summaryrefslogtreecommitdiff
path: root/src/or/scheduler.c
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2018-02-02 08:48:34 -0500
committerNick Mathewson <nickm@torproject.org>2018-02-02 12:03:27 -0500
commit005e228f80f0bd241d01c106f87e6bfe6dda6127 (patch)
treedc2c4a5e6b5fc7cd38c4e76574211fcdd70fcf55 /src/or/scheduler.c
parent77634795b0258f04a31a51d827d45eab40557f65 (diff)
downloadtor-005e228f80f0bd241d01c106f87e6bfe6dda6127.tar.gz
tor-005e228f80f0bd241d01c106f87e6bfe6dda6127.zip
sched: When releasing a channel, do not BUG() if absent from the pending list
The current code flow makes it that we can release a channel in a PENDING state but not in the pending list. This happens while the channel is being processed in the scheduler loop. Fixes #25125 Signed-off-by: David Goulet <dgoulet@torproject.org>
Diffstat (limited to 'src/or/scheduler.c')
-rw-r--r--src/or/scheduler.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/src/or/scheduler.c b/src/or/scheduler.c
index 47141c538c..1984084feb 100644
--- a/src/or/scheduler.c
+++ b/src/or/scheduler.c
@@ -628,17 +628,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) {