|
@@ -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);
|
|
|
- }
|
|
|
+
|
|
|
+ * 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) {
|