struct wait_event *subs; /* Task to wake when awaited events are ready */
union {
struct list idle_list; /* list element for idle connection in server idle list */
- struct mt_list toremove_list; /* list element when idle connection is ready to be purged */
+ struct mt_list purge_el; /* list element when idle connection is ready to be purged */
};
union {
struct list sess_el; /* used by private backend conns, list elem into session */
* accessible from foreign threads.
*/
struct idle_conns {
- struct mt_list toremove_conns;
- struct task *cleanup_task;
- __decl_thread(HA_SPINLOCK_T idle_conns_lock);
-} THREAD_ALIGNED(64);
+ struct mt_list purged_list;
+ struct task *task_free_purged;
+ __decl_thread(HA_SPINLOCK_T lock);
+} THREAD_ALIGNED(64);
/* Termination events logs:
* Each event is stored on 8 bits: 4 bits bor the event location and
* thread, and generally at the same time.
*/
THREAD_ALIGN(64);
- struct eb32_node idle_node; /* When to next do cleanup in the idle connections */
+ struct eb32_node purge_node; /* When to next do cleanup in the idle connections */
unsigned int curr_idle_conns; /* Current number of orphan idling connections, both the idle and the safe lists */
unsigned int curr_idle_nb; /* Current number of connections in the idle list */
unsigned int curr_safe_nb; /* Current number of connections in the safe list */
#include <haproxy/tools.h>
-__decl_thread(extern HA_SPINLOCK_T idle_conn_srv_lock);
-extern struct idle_conns idle_conns[MAX_THREADS];
-extern struct task *idle_conn_task;
+__decl_thread(extern HA_SPINLOCK_T purge_conns_lock);
+extern struct task *task_purge_servers;
+
extern struct mt_list servers_list;
extern struct dict server_key_dict;
void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe);
int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_safe);
void srv_add_to_avail_list(struct server *srv, struct connection *conn);
-struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsigned int state);
int srv_apply_track(struct server *srv, struct proxy *curproxy);
* to end up with two threads using the same connection.
*/
i = tid;
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn = srv_lookup_conn(is_safe ? &srv->per_thr[tid].safe_conns : &srv->per_thr[tid].idle_conns, hash);
if (conn)
conn_delete_from_tree(conn);
is_safe = 1;
}
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* If we found a connection in our own list, and we don't have to
* steal one from another thread, then we're done.
if (!srv->curr_idle_thr[i] || i == tid)
continue;
- if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0)
+ if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock) != 0)
continue;
conn = srv_lookup_conn(is_safe ? &srv->per_thr[i].safe_conns : &srv->per_thr[i].idle_conns, hash);
while (conn) {
conn = srv_lookup_conn_next(conn);
}
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
} while (!found && (i = (i + 1 == curtg->base + curtg->count) ? curtg->base : i + 1) != stop);
if (!found && (global.tune.tg_takeover == FULL_THREADGROUP_TAKEOVER ||
for (i = 0; i < global.nbthread; i++) {
curtid = (i + tid) % global.nbthread;
- if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock) != 0)
+ if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].lock) != 0)
continue;
conn = takeover_random_idle_conn(&srv->per_thr[curtid].idle_conns, curtid);
if (!conn)
conn = takeover_random_idle_conn(&srv->per_thr[curtid].safe_conns, curtid);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[curtid].lock);
if (conn)
break;
}
if (avail <= 1) {
/* no more streams available, remove it from the list */
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(srv_conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
if (avail >= 1) {
/* We have more FDs than deemed acceptable, attempt to kill an idling connection. */
struct connection *tokill_conn = NULL;
/* First, try from our own idle list */
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (!LIST_ISEMPTY(&srv->per_thr[tid].idle_conn_list)) {
tokill_conn = LIST_ELEM(srv->per_thr[tid].idle_conn_list.n, struct connection *, idle_list);
conn_delete_from_tree(tokill_conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Release the idle lock before calling mux->destroy.
* It will in turn call srv_release_conn through
tokill_conn->mux->destroy(tokill_conn->ctx);
}
else {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
/* If not, iterate over other thread's idling pool, and try to grab one */
// see it possibly larger.
ALREADY_CHECKED(i);
- if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock) != 0)
+ if (HA_SPIN_TRYLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock) != 0)
continue;
if (!LIST_ISEMPTY(&srv->per_thr[i].idle_conn_list)) {
tokill_conn = LIST_ELEM(srv->per_thr[i].idle_conn_list.n, struct connection *, idle_list);
conn_delete_from_tree(tokill_conn);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
if (tokill_conn) {
/* We got one, put it into the concerned thread's to kill list, and wake it's kill task */
-
- MT_LIST_APPEND(&idle_conns[i].toremove_conns,
- &tokill_conn->toremove_list);
- task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+ MT_LIST_APPEND(&idle_conns[i].purged_list,
+ &tokill_conn->purge_el);
+ task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
break;
}
/* At this point, target names have already been resolved. */
/***********************************************************/
- idle_conn_task = task_new_anywhere();
- if (!idle_conn_task) {
- ha_alert("parsing : failed to allocate global idle connection task.\n");
- cfgerr++;
- }
- else {
- idle_conn_task->process = srv_cleanup_idle_conns;
- idle_conn_task->context = NULL;
-
- for (i = 0; i < global.nbthread; i++) {
- idle_conns[i].cleanup_task = task_new_on(i);
- if (!idle_conns[i].cleanup_task) {
- ha_alert("parsing : failed to allocate idle connection tasks for thread '%d'.\n", i);
- cfgerr++;
- break;
- }
-
- idle_conns[i].cleanup_task->process = srv_cleanup_toremove_conns;
- idle_conns[i].cleanup_task->context = NULL;
- HA_SPIN_INIT(&idle_conns[i].idle_conns_lock);
- MT_LIST_INIT(&idle_conns[i].toremove_conns);
- }
- }
-
/* perform the final checks before creating tasks */
/* starting to initialize the main proxies list */
/* Remove <conn> idle connection from its attached tree (idle, safe or avail).
* If also present in the secondary server idle list, conn is removed from it.
*
- * Must be called with idle_conns_lock held.
+ * Must be called with lock held.
*/
void conn_delete_from_tree(struct connection *conn)
{
struct server *srv = objt_server(conn->target);
if (conn_in_list) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
ret = conn->mux->wake(conn);
}
}
else {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
}
conn->target = target;
conn->destroy_cb = NULL;
conn->proxy_netns = NULL;
- MT_LIST_INIT(&conn->toremove_list);
+ MT_LIST_INIT(&conn->purge_el);
if (conn_is_back(conn))
LIST_INIT(&conn->sess_el);
else
if (conn_is_back(conn))
conn_backend_deinit(conn);
- /* Remove the conn from toremove_list.
+ /* Remove the conn from purge list.
*
* This is needed to prevent a double-free in case the connection was
* already scheduled from cleaning but is freed before via another
* call.
*/
- MT_LIST_DELETE(&conn->toremove_list);
+ MT_LIST_DELETE(&conn->purge_el);
sockaddr_free(&conn->src);
sockaddr_free(&conn->dst);
return 0;
}
+/* Handler for task_free_purged of idle_conns. Free all connections registered
+ * in the purge list of the current thread.
+ */
+static struct task *free_purged_conns(struct task *task, void *context, unsigned int state)
+{
+ struct connection *conn;
+
+ while ((conn = MT_LIST_POP(&idle_conns[tid].purged_list,
+ struct connection *, purge_el)) != NULL) {
+ conn->mux->destroy(conn->ctx);
+ }
+
+ return task;
+}
+
/* Handler of the task of mux_stopping_data.
* Called on soft-stop.
*/
}
REGISTER_PER_THREAD_FREE(deallocate_mux_cleanup);
-static void deinit_idle_conns(void)
+static int allocate_idle_conns(void)
+{
+ idle_conns[tid].task_free_purged = task_new_on(tid);
+ if (!idle_conns[tid].task_free_purged) {
+ ha_alert("Failed to allocate idle connection tasks for thread '%d'.\n", tid);
+ return 0;
+ }
+
+ idle_conns[tid].task_free_purged->process = free_purged_conns;
+ idle_conns[tid].task_free_purged->context = NULL;
+ HA_SPIN_INIT(&idle_conns[tid].lock);
+ MT_LIST_INIT(&idle_conns[tid].purged_list);
+
+ return 1;
+}
+REGISTER_PER_THREAD_ALLOC(allocate_idle_conns);
+
+static void deinit_gc_purged_conns(void)
{
int i;
- for (i = 0; i < global.nbthread; i++) {
- task_destroy(idle_conns[i].cleanup_task);
- }
+ for (i = 0; i < global.nbthread; i++)
+ task_destroy(idle_conns[i].task_free_purged);
}
-REGISTER_POST_DEINIT(deinit_idle_conns);
+REGISTER_POST_DEINIT(deinit_gc_purged_conns);
ha_free(&global.server_state_base);
ha_free(&global.server_state_file);
ha_free(&global.stats_file);
- task_destroy(idle_conn_task);
- idle_conn_task = NULL;
+ task_destroy(task_purge_servers);
+ task_purge_servers = NULL;
list_for_each_entry_safe(log, logb, &global.loggers, list) {
LIST_DEL_INIT(&log->list);
/* the tasklet was idling on an idle connection, it might have
* been stolen, let's be careful!
*/
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (tl->context == NULL) {
/* The connection has been taken over by another thread,
* we're no longer responsible for it, so just free the
* tasklet, and do nothing.
*/
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
tasklet_free(tl);
return NULL;
}
conn_delete_from_tree(conn);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
} else {
/* we're certain the connection was not in an idle list */
conn = fconn->conn;
}
}
else {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
else {
TRACE_ENTER(FCGI_EV_FCONN_WAKE, (fconn ? fconn->conn : NULL));
if (fconn) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Somebody already stole the connection from us, so we should not
* free it, we just have to free the task.
*/
if (!t->context) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
fconn = NULL;
goto do_leave;
}
if (!expired) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
TRACE_DEVEL("leaving (not expired)", FCGI_EV_FCONN_WAKE, fconn->conn);
return t;
}
else if (fconn->conn->flags & CO_FL_SESS_IDLE)
conn_delete_from_sess(fconn->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
fcgi_conn_report_term_evt(fconn, muxc_tevt_type_tout);
}
/* the tasklet was idling on an idle connection, it might have
* been stolen, let's be careful!
*/
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (tl->context == NULL) {
/* The connection has been taken over by another thread,
* we're no longer responsible for it, so just free the
* tasklet, and do nothing.
*/
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
tasklet_free(tl);
return NULL;
}
conn_delete_from_tree(conn);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
} else {
/* we're certain the connection was not in an idle list */
conn = h1c->conn;
}
}
else {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
else {
if (h1c) {
/* Make sure nobody stole the connection from us */
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Somebody already stole the connection from us, so we should not
* free it, we just have to free the task.
*/
if (!t->context) {
h1c = NULL;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
goto do_leave;
}
if (!expired) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
TRACE_DEVEL("leaving (not expired)", H1_EV_H1C_WAKE, h1c->conn, h1c->h1s);
return t;
}
* stream's timeout
*/
if (h1c->state == H1_CS_RUNNING) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
t->expire = TICK_ETERNITY;
TRACE_DEVEL("leaving (SC still attached)", H1_EV_H1C_WAKE, h1c->conn, h1c->h1s);
return t;
h1_send(h1c);
if (b_data(&h1c->obuf) || (h1c->flags & H1C_F_ABRT_PENDING)) {
h1_refresh_timeout(h1c);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return t;
}
}
se_fl_set(h1c->h1s->sd, SE_FL_EOS | SE_FL_ERROR);
h1_alert(h1c->h1s);
h1_refresh_timeout(h1c);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
TRACE_DEVEL("waiting to release the SC before releasing the connection", H1_EV_H1C_WAKE);
return t;
}
if (h1c->conn->flags & CO_FL_LIST_MASK)
conn_delete_from_tree(h1c->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
h1c_report_term_evt(h1c, muxc_tevt_type_tout);
}
/* the tasklet was idling on an idle connection, it might have
* been stolen, let's be careful!
*/
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (t->context == NULL) {
/* The connection has been taken over by another thread,
* we're no longer responsible for it, so just free the
* tasklet, and do nothing.
*/
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
tasklet_free(tl);
t = NULL;
goto leave;
conn_delete_from_tree(conn);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
} else {
/* we're certain the connection was not in an idle list */
conn = h2c->conn;
}
}
else {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
else {
/* connections in error must be removed from the idle lists */
if (conn->flags & CO_FL_LIST_MASK) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
else if (h2c->st0 == H2_CS_ERROR) {
/* connections in error must be removed from the idle lists */
if (conn->flags & CO_FL_LIST_MASK) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
if (h2c) {
/* Make sure nobody stole the connection from us */
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Somebody already stole the connection from us, so we should not
* free it, we just have to free the task.
*/
if (!t->context) {
h2c = NULL;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
goto do_leave;
}
if (!expired) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
TRACE_DEVEL("leaving (not expired)", H2_EV_H2C_WAKE, h2c->conn);
return t;
}
/* we do still have streams but all of them are idle, waiting
* for the data layer, so we must not enforce the timeout here.
*/
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
t->expire = TICK_ETERNITY;
return t;
}
tasklet_wakeup(h2c->wait_event.tasklet);
TRACE_DEVEL("leaving (idle ping)", H2_EV_H2C_WAKE, h2c->conn);
t->expire = conn_idle_ping(h2c->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return t;
}
else if (h2c->conn->flags & CO_FL_SESS_IDLE)
session_unown_conn(h2c->conn->owner, h2c->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (h2c->flags & H2_CF_IDL_PING_SENT) {
TRACE_STATE("expired on idle ping", H2_EV_H2C_WAKE, h2c->conn);
/* in any case this connection must not be considered idle anymore */
if (h2c->conn->flags & CO_FL_LIST_MASK) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(h2c->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
/* either we can release everything now or it will be done later once
/* the tasklet was idling on an idle connection, it might have
* been stolen, let's be careful!
*/
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (tl->context == NULL) {
/* The connection has been taken over by another thread,
* we're no longer responsible for it, so just free the
* tasklet, and do nothing.
*/
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
tasklet_free(tl);
return NULL;
}
conn_delete_from_tree(conn);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
} else {
/* we're certain the connection was not in an idle list */
conn = spop_conn->conn;
}
}
else {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
else {
/* connections in error must be removed from the idle lists */
if (conn->flags & CO_FL_LIST_MASK) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
TRACE_ENTER(SPOP_EV_SPOP_CONN_WAKE, (spop_conn ? spop_conn->conn : NULL));
if (spop_conn) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Somebody already stole the connection from us, so we should not
* free it, we just have to free the task.
*/
if (!t->context) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
spop_conn = NULL;
goto do_leave;
}
if (!expired) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
TRACE_DEVEL("leaving (not expired)", SPOP_EV_SPOP_CONN_WAKE, spop_conn->conn);
return t;
}
else if (spop_conn->conn->flags & CO_FL_SESS_IDLE)
conn_delete_from_sess(spop_conn->conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
spop_conn_report_term_evt(spop_conn, muxc_tevt_type_tout);
}
static void srv_update_status(struct server *s, int type, int cause);
static int srv_apply_lastaddr(struct server *srv, int *err_code);
-static void srv_cleanup_connections(struct server *srv);
+static void srv_purge_all_idle_conns(struct server *srv);
/* extra keywords used as value for other arguments. They are used as
* suggestions for mistyped words.
.list = LIST_HEAD_INIT(srv_keywords.list)
};
-__decl_thread(HA_SPINLOCK_T idle_conn_srv_lock);
-struct eb_root idle_conn_srv = EB_ROOT;
-struct task *idle_conn_task __read_mostly = NULL;
+/* Periodic idle conns purge elements. */
+__decl_thread(HA_SPINLOCK_T purge_conns_lock);
+struct eb_root servers_purge_tree = EB_ROOT;
+struct task *task_purge_servers __read_mostly = NULL;
+
struct mt_list servers_list = MT_LIST_HEAD_INIT(servers_list);
static struct task *server_atomic_sync_task = NULL;
static event_hdl_async_equeue server_atomic_sync_queue;
send_log(srv->proxy, LOG_NOTICE, "%s.\n", trash.area);
}
}
- srv_cleanup_connections(srv);
+ srv_purge_all_idle_conns(srv);
srv_set_dyncookie(srv);
srv_set_addr_desc(srv, 1);
}
cli_err(appctx, "'set server <srv> ssl' expects 'on' or 'off'.\n");
goto out;
}
- srv_cleanup_connections(sv);
+ srv_purge_all_idle_conns(sv);
HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
cli_msg(appctx, LOG_NOTICE, "server ssl setting updated.\n");
#else
ebpt_delete(&srv->conf.name);
ebpt_delete(&srv->addr_node);
- /* remove srv from idle_node tree for idle conn cleanup */
- eb32_delete(&srv->idle_node);
+ /* remove srv from purge tree for idle conn cleanup */
+ eb32_delete(&srv->purge_node);
/* flag the server as deleted
* (despite the server being removed from primary server list,
srv_shutdown_streams(s, SF_ERR_DOWN);
/* force connection cleanup on the given server */
- srv_cleanup_connections(s);
+ srv_purge_all_idle_conns(s);
/* we might have streams queued on this server and waiting for
* a connection. Those which are redispatchable will be queued
* to another server or to the proxy itself.
}
}
-struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsigned int state)
-{
- struct connection *conn;
-
- while ((conn = MT_LIST_POP(&idle_conns[tid].toremove_conns,
- struct connection *, toremove_list)) != NULL) {
- conn->mux->destroy(conn->ctx);
- }
-
- return task;
-}
-
-/* Move <toremove_nb> count connections from <list> storage to <toremove_list>
- * list storage. -1 means moving all of them.
+/* Move <count> connections attached on a server from <conns> list into the
+ * purgeable list of <t> thread. If <count> is negative, <conns> is emptied.
*
- * Returns the number of connections moved.
+ * Must be called with IDLE_CONNS_LOCK held.
*
- * Must be called with idle_conns_lock held.
+ * Returns the number of connections moved.
*/
-static int srv_migrate_conns_to_remove(struct list *list, struct mt_list *toremove_list, int toremove_nb)
+static int srv_purge_conns(struct list *conns, int t, int count)
{
struct connection *conn;
int i = 0;
- while (!LIST_ISEMPTY(list)) {
- if (toremove_nb != -1 && i >= toremove_nb)
+ while (!LIST_ISEMPTY(conns)) {
+ if (count >= 0 && i >= count)
break;
- conn = LIST_ELEM(list->n, struct connection *, idle_list);
+ conn = LIST_ELEM(conns->n, struct connection *, idle_list);
conn_delete_from_tree(conn);
- MT_LIST_APPEND(toremove_list, &conn->toremove_list);
+ MT_LIST_APPEND(&idle_conns[t].purged_list, &conn->purge_el);
i++;
}
return i;
}
-/* cleanup connections for a given server
- * might be useful when going on forced maintenance or live changing ip/port
+
+/* Mark as purgeable all idle backend connections on <srv> server. Purge task
+ * is immediately scheduled on necessary threads to remove them.
+ *
+ * This operation is useful when the server is going on forced maintenance or
+ * some of its network configuration such as IP/port are updated during
+ * runtime.
*/
-static void srv_cleanup_connections(struct server *srv)
+static void srv_purge_all_idle_conns(struct server *srv)
{
struct sess_priv_conns *sess_conns;
int did_remove;
/* check all threads starting with ours */
for (i = tid;;) {
did_remove = 0;
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
/* idle connections */
- if (srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conn_list, &idle_conns[i].toremove_conns, -1) > 0)
+ if (srv_purge_conns(&srv->per_thr[i].idle_conn_list, i, -1) > 0)
did_remove = 1;
/* session attached connections */
}
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
if (did_remove)
- task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+ task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
break;
/* Remove the connection from any tree (safe, idle or available) */
if (conn->hash_node) {
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
conn->flags &= ~CO_FL_LIST_MASK;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
}
* on it before reinserting it with this function. In other context, prefer to
* use the full feature srv_add_to_idle_list().
*
- * Must be called with idle_conns_lock.
+ * Must be called with IDLE_CONNS_LOCK.
*/
void _srv_add_idle(struct server *srv, struct connection *conn, int is_safe)
{
}
_HA_ATOMIC_DEC(&srv->curr_used_conns);
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
conn_delete_from_tree(conn);
if (is_safe) {
_srv_add_idle(srv, conn, 0);
_HA_ATOMIC_INC(&srv->curr_idle_nb);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_HA_ATOMIC_INC(&srv->curr_idle_thr[tid]);
__ha_barrier_full();
- if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
- HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
- if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
- srv->idle_node.key = tick_add(srv->pool_purge_delay,
- now_ms);
- eb32_insert(&idle_conn_srv, &srv->idle_node);
- if (!task_in_wq(idle_conn_task) && !
- task_in_rq(idle_conn_task)) {
- task_schedule(idle_conn_task,
- srv->idle_node.key);
+
+ /* Register server for purge if not already the case. */
+ if ((volatile void *)srv->purge_node.node.leaf_p == NULL) {
+ HA_SPIN_LOCK(OTHER_LOCK, &purge_conns_lock);
+ if ((volatile void *)srv->purge_node.node.leaf_p == NULL) {
+ srv->purge_node.key = tick_add(srv->pool_purge_delay,
+ now_ms);
+ eb32_insert(&servers_purge_tree, &srv->purge_node);
+
+ /* Schedule task_purge_servers if needed. */
+ if (!task_in_wq(task_purge_servers) &&
+ !task_in_rq(task_purge_servers)) {
+ task_schedule(task_purge_servers,
+ srv->purge_node.key);
}
}
- HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
+ HA_SPIN_UNLOCK(OTHER_LOCK, &purge_conns_lock);
}
return 1;
}
eb64_insert(&srv->per_thr[tid].avail_conns, &conn->hash_node->node);
}
-struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned int state)
+/* Handler for <task_purge_servers>. Loop over registered servers and purge it
+ * if expired : detach some idle conns to reach current estimated needed level.
+ */
+struct task *do_servers_purge(struct task *task, void *context, unsigned int state)
{
struct server *srv;
struct eb32_node *eb;
unsigned int next_wakeup;
next_wakeup = TICK_ETERNITY;
- HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
+ HA_SPIN_LOCK(OTHER_LOCK, &purge_conns_lock);
while (1) {
int exceed_conns;
int to_kill;
int curr_idle;
- eb = eb32_lookup_ge(&idle_conn_srv, now_ms - TIMER_LOOK_BACK);
+ eb = eb32_lookup_ge(&servers_purge_tree, now_ms - TIMER_LOOK_BACK);
if (!eb) {
/* we might have reached the end of the tree, typically because
* <now_ms> is in the first half and we're first scanning the last
* half. Let's loop back to the beginning of the tree now.
*/
- eb = eb32_first(&idle_conn_srv);
+ eb = eb32_first(&servers_purge_tree);
if (likely(!eb))
break;
}
next_wakeup = eb->key;
break;
}
- srv = eb32_entry(eb, struct server, idle_node);
+ srv = eb32_entry(eb, struct server, purge_node);
/* Calculate how many idle connections we want to kill :
* we want to remove half the difference between the total
max_conn = (exceed_conns * srv->curr_idle_thr[i]) /
curr_idle + 1;
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
- j = srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conn_list, &idle_conns[i].toremove_conns, max_conn);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
+ j = srv_purge_conns(&srv->per_thr[i].idle_conn_list, i, max_conn);
if (j > 0)
did_remove = 1;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].lock);
if (did_remove)
- task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
+ task_wakeup(idle_conns[i].task_free_purged, TASK_WOKEN_OTHER);
if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
break;
}
remove:
- eb32_delete(&srv->idle_node);
+ eb32_delete(&srv->purge_node);
if (srv->curr_idle_conns) {
/* There are still more idle connections, add the
* server back in the tree.
*/
- srv->idle_node.key = tick_add(srv->pool_purge_delay, now_ms);
- eb32_insert(&idle_conn_srv, &srv->idle_node);
- next_wakeup = tick_first(next_wakeup, srv->idle_node.key);
+ srv->purge_node.key = tick_add(srv->pool_purge_delay, now_ms);
+ eb32_insert(&servers_purge_tree, &srv->purge_node);
+ next_wakeup = tick_first(next_wakeup, srv->purge_node.key);
}
}
- HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
+ HA_SPIN_UNLOCK(OTHER_LOCK, &purge_conns_lock);
task->expire = next_wakeup;
return task;
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+int alloc_servers_purge_task(void)
+{
+ task_purge_servers = task_new_anywhere();
+ if (!task_purge_servers) {
+ ha_alert("Failed to allocate purge servers global task.\n");
+ return ERR_FATAL|ERR_ABORT;
+ }
+
+ task_purge_servers->process = do_servers_purge;
+ task_purge_servers->context = NULL;
+ return ERR_NONE;
+}
+REGISTER_POST_CHECK(alloc_servers_purge_task);
+
/*
* Local variables:
* c-indent-level: 8
if (conn != NULL && conn->mux)
conn->mux->destroy(conn->ctx);
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
list_for_each_entry_safe(pconns, pconns_back, &sess->priv_conns, sess_el) {
list_for_each_entry_safe(conn, conn_back, &pconns->conn_list, sess_el) {
LIST_DEL_INIT(&conn->sess_el);
MT_LIST_DELETE(&pconns->srv_el);
pool_free(pool_head_sess_priv_conns, pconns);
}
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Release connections outside of idle lock. */
while (!LIST_ISEMPTY(&conn_tmp_list)) {
*/
BUG_ON(conn->owner && conn->owner != sess);
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* Already attach to the session */
if (!LIST_ISEMPTY(&conn->sess_el))
conn->owner = sess;
out:
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return 1;
err:
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return 0;
}
{
struct sess_priv_conns *pconns;
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
pconns = sess_get_sess_conns(sess, conn->target);
if (!pconns)
LIST_APPEND(&pconns->conn_list, &conn->sess_el);
++sess->idle_conns;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return 1;
err:
/* Idle conn cannot be reinserted, hence session counter must be adjusted. */
--sess->idle_conns;
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return 0;
}
struct sess_priv_conns *pconns;
struct server *srv;
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
list_for_each_entry(pconns, &sess->priv_conns, sess_el) {
if (pconns->target == target) {
}
end:
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
return srv_conn;
}
BUG_ON(objt_listener(conn->target));
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
/* WT: this currently is a workaround for an inconsistency between
* the link status of the connection in the session list and the
}
out:
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
int session_purge_conns(struct sess_priv_conns *sess_conns)
--((struct session *)conn->owner)->idle_conns;
LIST_DEL_INIT(&conn->sess_el);
- MT_LIST_APPEND(&idle_conns[conn_tid].toremove_conns,
- &conn->toremove_list);
+ MT_LIST_APPEND(&idle_conns[conn_tid].purged_list,
+ &conn->purge_el);
i++;
}
/* the tasklet was idling on an idle connection, it might have
* been stolen, let's be careful!
*/
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
if (tl->context == NULL) {
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
tasklet_free(tl);
return NULL;
}
conn_in_list = conn->flags & CO_FL_LIST_MASK;
if (conn_in_list)
conn_delete_from_tree(conn);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
} else {
ctx = context;
conn = ctx->conn;
struct server *srv = objt_server(conn->target);
TRACE_DEVEL("adding conn back to idle list", SSL_EV_CONN_IO_CB, conn);
- HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
_srv_add_idle(srv, conn, conn_in_list == CO_FL_SAFE_LIST);
- HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
+ HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].lock);
}
TRACE_LEAVE(SSL_EV_CONN_IO_CB, conn);
return t;