diff --git a/src/client.c b/src/client.c index bf8519f17..4cc3d7ea0 100644 --- a/src/client.c +++ b/src/client.c @@ -66,7 +66,6 @@ int event_accept(int fd) { struct session *s; struct http_txn *txn; struct task *t; - struct bref *bref, *back; int cfd; int max_accept = global.tune.maxaccept; @@ -470,11 +469,6 @@ int event_accept(int fd) { 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: diff --git a/src/dumpstats.c b/src/dumpstats.c index 07e505649..b12fbd0b1 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -1099,8 +1099,10 @@ void stats_dump_sess_to_buffer(struct session *s, struct buffer *rep) * 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); @@ -1118,7 +1120,10 @@ void stats_dump_sess_to_buffer(struct session *s, struct buffer *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); @@ -1127,16 +1132,19 @@ void stats_dump_sess_to_buffer(struct session *s, struct buffer *rep) /* 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, @@ -1194,7 +1202,9 @@ void stats_dump_sess_to_buffer(struct session *s, struct buffer *rep) : "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; } diff --git a/src/proto_uxst.c b/src/proto_uxst.c index f07fa158b..997cf496e 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -360,7 +360,6 @@ int uxst_event_accept(int fd) { struct listener *l = fdtab[fd].owner; struct session *s; struct task *t; - struct bref *bref, *back; int cfd; int max_accept; @@ -553,11 +552,6 @@ int uxst_event_accept(int fd) { 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: diff --git a/src/session.c b/src/session.c index d1bc052aa..8ced9b8bf 100644 --- a/src/session.c +++ b/src/session.c @@ -98,8 +98,13 @@ void session_free(struct session *s) 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);