OPTIM: server: switch the actconn list to an mt-list

The remaining contention on the server lock solely comes from
sess_change_server() which takes the lock to add and remove a
stream from the server's actconn list. This is both expensive
and pointless since we have mt-lists, and this list is only
used by the CLI's "shutdown server sessions" command!

Let's migrate to an mt-list and remove the need for this costly
lock. By doing so, the request rate increased by ~1.8%.

(cherry picked from commit 751153e0f119bec90455cda95166f1b29d8b0326)
[wt: the contention is extreme on high threads counts, thus this
     actconn series is backported; ctx adjustments]
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h
index d2e0fd0..4b26e43 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -222,7 +222,7 @@
 	struct be_counters counters;		/* statistics counters */
 
 	struct eb_root pendconns;		/* pending connections */
-	struct list actconns;			/* active connections */
+	struct mt_list actconns;		/* active connections (used by "shutdown server sessions") */
 	struct mt_list *idle_conns;		/* shareable idle connections*/
 	struct mt_list *safe_conns;		/* safe idle connections */
 	struct list *available_conns;           /* Connection in used, but with still new streams available */
diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h
index b2c8378..3bdab72 100644
--- a/include/haproxy/stream-t.h
+++ b/include/haproxy/stream-t.h
@@ -140,7 +140,7 @@
 	int32_t priority_offset;        /* priority offset of the stream for the pending queue */
 
 	struct list list;               /* position in global streams list */
-	struct list by_srv;             /* position in server stream list */
+	struct mt_list by_srv;          /* position in server stream list */
 	struct list back_refs;          /* list of users tracking this stream */
 	struct buffer_wait buffer_wait; /* position in the list of objects waiting for a buffer */
 
diff --git a/include/haproxy/stream.h b/include/haproxy/stream.h
index e50fbc8..8500fb6 100644
--- a/include/haproxy/stream.h
+++ b/include/haproxy/stream.h
@@ -341,17 +341,10 @@
 	}
 }
 
-static inline void __stream_add_srv_conn(struct stream *sess, struct server *srv)
-{
-	sess->srv_conn = srv;
-	LIST_ADD(&srv->actconns, &sess->by_srv);
-}
-
 static inline void stream_add_srv_conn(struct stream *sess, struct server *srv)
 {
-	HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
-	__stream_add_srv_conn(sess, srv);
-	HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
+	MT_LIST_ADD(&srv->actconns, &sess->by_srv);
+	HA_ATOMIC_STORE(&sess->srv_conn, srv);
 }
 
 static inline void stream_del_srv_conn(struct stream *sess)
@@ -361,16 +354,14 @@
 	if (!srv)
 		return;
 
-	HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
-	sess->srv_conn = NULL;
-	LIST_DEL(&sess->by_srv);
-	HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
+	MT_LIST_DEL(&sess->by_srv);
+	HA_ATOMIC_STORE(&sess->srv_conn, NULL);
 }
 
 static inline void stream_init_srv_conn(struct stream *sess)
 {
 	sess->srv_conn = NULL;
-	LIST_INIT(&sess->by_srv);
+	MT_LIST_INIT(&sess->by_srv);
 }
 
 static inline void stream_choose_redispatch(struct stream *s)
diff --git a/src/hlua.c b/src/hlua.c
index 550b592..8dd2f31 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -8750,7 +8750,7 @@
 	socket_tcp.next = NULL;
 	socket_tcp.proxy = &socket_proxy;
 	socket_tcp.obj_type = OBJ_TYPE_SERVER;
-	LIST_INIT(&socket_tcp.actconns);
+	MT_LIST_INIT(&socket_tcp.actconns);
 	socket_tcp.pendconns = EB_ROOT;
 	socket_tcp.idle_conns = NULL;
 	socket_tcp.safe_conns = NULL;
@@ -8795,7 +8795,7 @@
 	socket_ssl.next = NULL;
 	socket_ssl.proxy = &socket_proxy;
 	socket_ssl.obj_type = OBJ_TYPE_SERVER;
-	LIST_INIT(&socket_ssl.actconns);
+	MT_LIST_INIT(&socket_ssl.actconns);
 	socket_ssl.pendconns = EB_ROOT;
 	socket_ssl.idle_conns = NULL;
 	socket_ssl.safe_conns = NULL;
diff --git a/src/queue.c b/src/queue.c
index 19b99a5..ea99761 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -328,7 +328,7 @@
 	__ha_barrier_atomic_store();
 	if (px->lbprm.server_take_conn)
 		px->lbprm.server_take_conn(srv);
-	__stream_add_srv_conn(p->strm, srv);
+	stream_add_srv_conn(p->strm, srv);
 
 	task_wakeup(p->strm->task, TASK_WOKEN_RES);
 
diff --git a/src/server.c b/src/server.c
index d741f16..13eb676 100644
--- a/src/server.c
+++ b/src/server.c
@@ -863,9 +863,10 @@
  */
 void srv_shutdown_streams(struct server *srv, int why)
 {
-	struct stream *stream, *stream_bck;
+	struct stream *stream;
+	struct mt_list *elt1, elt2;
 
-	list_for_each_entry_safe(stream, stream_bck, &srv->actconns, by_srv)
+	mt_list_for_each_entry_safe(stream, &srv->actconns, by_srv, elt1, elt2)
 		if (stream->srv_conn == srv)
 			stream_shutdown(stream, why);
 }
@@ -1724,7 +1725,7 @@
 
 	srv->obj_type = OBJ_TYPE_SERVER;
 	srv->proxy = proxy;
-	LIST_INIT(&srv->actconns);
+	MT_LIST_INIT(&srv->actconns);
 	srv->pendconns = EB_ROOT;
 
 	srv->next_state = SRV_ST_RUNNING; /* early server setup */
diff --git a/src/stream.c b/src/stream.c
index a2feea1..7b58e2a 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -2496,17 +2496,19 @@
  */
 void sess_change_server(struct stream *sess, struct server *newsrv)
 {
-	if (sess->srv_conn == newsrv)
+	struct server *oldsrv = sess->srv_conn;
+
+	if (oldsrv == newsrv)
 		return;
 
-	if (sess->srv_conn) {
-		_HA_ATOMIC_SUB(&sess->srv_conn->served, 1);
-		_HA_ATOMIC_SUB(&sess->srv_conn->proxy->served, 1);
+	if (oldsrv) {
+		_HA_ATOMIC_SUB(&oldsrv->served, 1);
+		_HA_ATOMIC_SUB(&oldsrv->proxy->served, 1);
 		__ha_barrier_atomic_store();
-		if (sess->srv_conn->proxy->lbprm.server_drop_conn) {
-			HA_SPIN_LOCK(SERVER_LOCK, &sess->srv_conn->lock);
-			sess->srv_conn->proxy->lbprm.server_drop_conn(sess->srv_conn);
-			HA_SPIN_UNLOCK(SERVER_LOCK, &sess->srv_conn->lock);
+		if (oldsrv->proxy->lbprm.server_drop_conn) {
+			HA_SPIN_LOCK(SERVER_LOCK, &oldsrv->lock);
+			oldsrv->proxy->lbprm.server_drop_conn(oldsrv);
+			HA_SPIN_UNLOCK(SERVER_LOCK, &oldsrv->lock);
 		}
 		stream_del_srv_conn(sess);
 	}