h2_release_buf(h2c, &h2c->mbuf);
if (h2c->task) {
- task_delete(h2c->task);
- task_free(h2c->task);
+ h2c->task->context = NULL;
+ task_wakeup(h2c->task, TASK_WOKEN_OTHER);
h2c->task = NULL;
}
struct h2c *h2c = t->context;
int expired = tick_is_expired(t->expire, now_ms);
- if (!expired)
+ if (!expired && h2c)
return t;
+ task_delete(t);
+ task_free(t);
+
+ if (!h2c) {
+ /* resources were already deleted */
+ return NULL;
+ }
+
+ h2c->task = NULL;
h2c_error(h2c, H2_ERR_NO_ERROR);
h2_wake_some_streams(h2c, 0, 0);
if (h2c->mbuf->o && !(h2c->flags & H2_CF_GOAWAY_FAILED) && conn_xprt_ready(h2c->conn))
h2c->conn->xprt->snd_buf(h2c->conn, h2c->mbuf, 0);
- if (!eb_is_empty(&h2c->streams_by_id))
- goto wait;
-
- h2_release(h2c->conn);
- return NULL;
+ /* either we can release everything now or it will be done later once
+ * the last stream closes.
+ */
+ if (eb_is_empty(&h2c->streams_by_id))
+ h2_release(h2c->conn);
- wait:
- /* the streams have been notified, we must let them finish and close */
- h2c->task = NULL;
- task_delete(t);
- task_free(t);
return NULL;
}