struct session *s;
struct http_txn *txn;
struct task *t;
- struct bref *bref, *back;
int cfd;
int max_accept = global.tune.maxaccept;
out_free_task:
pool_free2(pool2_task, t);
out_free_session:
- list_for_each_entry_safe(bref, back, &s->back_refs, users) {
- LIST_DEL(&bref->users);
- LIST_ADDQ(&LIST_ELEM(s->list.n, struct session *, list)->back_refs, &bref->users);
- bref->ref = s->list.n;
- }
LIST_DEL(&s->list);
pool_free2(pool2_session, s);
out_close:
* reference to the last session being dumped.
*/
if (s->data_state == DATA_ST_LIST) {
- if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users))
+ if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users)) {
LIST_DEL(&s->data_ctx.sess.bref.users);
+ LIST_INIT(&s->data_ctx.sess.bref.users);
+ }
}
s->data_state = DATA_ST_FIN;
buffer_stop_hijack(rep);
case DATA_ST_INIT:
/* the function had not been called yet, let's prepare the
* buffer for a response. We initialize the current session
- * pointer to the first in the global list.
+ * pointer to the first in the global list. When a target
+ * session is being destroyed, it is responsible for updating
+ * this pointer. We know we have reached the end when this
+ * pointer points back to the head of the sessions list.
*/
stream_int_retnclose(rep->cons, &msg);
LIST_INIT(&s->data_ctx.sess.bref.users);
/* fall through */
case DATA_ST_LIST:
+ /* first, let's detach the back-ref from a possible previous session */
+ if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users)) {
+ LIST_DEL(&s->data_ctx.sess.bref.users);
+ LIST_INIT(&s->data_ctx.sess.bref.users);
+ }
+
+ /* and start from where we stopped */
while (s->data_ctx.sess.bref.ref != &sessions) {
char pn[INET6_ADDRSTRLEN + strlen(":65535")];
struct session *curr_sess;
curr_sess = LIST_ELEM(s->data_ctx.sess.bref.ref, struct session *, list);
- /* first, let's detach the back-ref from a possible previous session */
- if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users))
- LIST_DEL(&s->data_ctx.sess.bref.users);
-
chunk_printf(&msg, sizeof(trash),
"%p: proto=%s",
curr_sess,
: "never");
if (buffer_write_chunk(rep, &msg) >= 0) {
- /* let's try again later */
+ /* let's try again later from this session. We add ourselves into
+ * this session's users so that it can remove us upon termination.
+ */
LIST_ADDQ(&curr_sess->back_refs, &s->data_ctx.sess.bref.users);
return;
}
struct listener *l = fdtab[fd].owner;
struct session *s;
struct task *t;
- struct bref *bref, *back;
int cfd;
int max_accept;
out_free_task:
pool_free2(pool2_task, t);
out_free_session:
- list_for_each_entry_safe(bref, back, &s->back_refs, users) {
- LIST_DEL(&bref->users);
- LIST_ADDQ(&LIST_ELEM(s->list.n, struct session *, list)->back_refs, &bref->users);
- bref->ref = s->list.n;
- }
LIST_DEL(&s->list);
pool_free2(pool2_session, s);
out_close:
pool_free2(pool2_capture, txn->srv_cookie);
list_for_each_entry_safe(bref, back, &s->back_refs, users) {
+ /* we have to unlink all watchers. We must not relink them if
+ * this session was the last one in the list.
+ */
LIST_DEL(&bref->users);
- LIST_ADDQ(&LIST_ELEM(s->list.n, struct session *, list)->back_refs, &bref->users);
+ LIST_INIT(&bref->users);
+ if (s->list.n != &sessions)
+ LIST_ADDQ(&LIST_ELEM(s->list.n, struct session *, list)->back_refs, &bref->users);
bref->ref = s->list.n;
}
LIST_DEL(&s->list);