From 4f8cd4397f07389129dd23b07e94018404340731 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 2 Mar 2021 17:27:58 +0100 Subject: [PATCH] MINOR: xprt: add new xprt_set_idle and xprt_set_used methods These functions are used on the mux layer to indicate that the connection is becoming idle and that the xprt ought to be careful before checking the context or that it's not idle anymore and that the context is safe. The purpose is to allow a mux which is going to release a connection to tell the xprt to be careful when touching it. At the moment, the xprt are always careful and that's costly so we want to have the ability to relax this a bit. No xprt layer uses this yet. --- include/haproxy/connection-t.h | 2 ++ include/haproxy/connection.h | 19 +++++++++++++++++++ src/mux_fcgi.c | 3 +++ src/mux_h1.c | 3 +++ src/mux_h2.c | 3 +++ 5 files changed, 30 insertions(+) diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 033f761..9c2af7b 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -380,6 +380,8 @@ struct xprt_ops { void (*destroy_srv)(struct server *srv); /* destroy a server context */ int (*get_alpn)(const struct connection *conn, void *xprt_ctx, const char **str, int *len); /* get application layer name */ int (*takeover)(struct connection *conn, void *xprt_ctx, int orig_tid); /* Let the xprt know the fd have been taken over */ + void (*set_idle)(struct connection *conn, void *xprt_ctx); /* notify the xprt that the connection becomes idle. implies set_used. */ + void (*set_used)(struct connection *conn, void *xprt_ctx); /* notify the xprt that the connection leaves idle. implies set_idle. */ char name[8]; /* transport layer name, zero-terminated */ int (*subscribe)(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es); /* Subscribe to events, such as "being able to send" */ int (*unsubscribe)(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es); /* Unsubscribe from events */ diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index d8aff5c..e00e6f8 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -868,6 +868,25 @@ static inline int xprt_add_hs(struct connection *conn) return 0; } +/* notify the next xprt that the connection is about to become idle and that it + * may be stolen at any time after the function returns and that any tasklet in + * the chain must be careful before dereferencing its context. + */ +static inline void xprt_set_idle(struct connection *conn, const struct xprt_ops *xprt, void *xprt_ctx) +{ + if (xprt->set_idle) + xprt->set_idle(conn, conn->xprt_ctx); +} + +/* notify the next xprt that the connection is not idle anymore and that it may + * not be stolen before the next xprt_set_idle(). + */ +static inline void xprt_set_used(struct connection *conn, const struct xprt_ops *xprt, void *xprt_ctx) +{ + if (xprt->set_used) + xprt->set_used(conn, conn->xprt_ctx); +} + static inline int conn_get_alpn(const struct connection *conn, const char **str, int *len) { if (!conn_xprt_ready(conn) || !conn->xprt->get_alpn) diff --git a/src/mux_fcgi.c b/src/mux_fcgi.c index be063cf..b7d8e94 100644 --- a/src/mux_fcgi.c +++ b/src/mux_fcgi.c @@ -3489,6 +3489,7 @@ static struct conn_stream *fcgi_attach(struct connection *conn, struct session * /* the connection is not idle anymore, let's mark this */ HA_ATOMIC_AND(&fconn->wait_event.tasklet->state, ~TASK_F_USR1); + xprt_set_used(conn, conn->xprt, conn->xprt_ctx); TRACE_LEAVE(FCGI_EV_FSTRM_NEW, conn, fstrm); return cs; @@ -3620,6 +3621,8 @@ static void fcgi_detach(struct conn_stream *cs) * that the handler needs to check it under the idle conns lock. */ HA_ATOMIC_OR(&fconn->wait_event.tasklet->state, TASK_F_USR1); + xprt_set_idle(fconn->conn, fconn->conn->xprt, fconn->conn->xprt_ctx); + if (!srv_add_to_idle_list(objt_server(fconn->conn->target), fconn->conn, 1)) { /* The server doesn't want it, let's kill the connection right away */ fconn->conn->mux->destroy(fconn); diff --git a/src/mux_h1.c b/src/mux_h1.c index 7d1bed4..c8dc71c 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -3007,6 +3007,7 @@ static struct conn_stream *h1_attach(struct connection *conn, struct session *se /* the connection is not idle anymore, let's mark this */ HA_ATOMIC_AND(&h1c->wait_event.tasklet->state, ~TASK_F_USR1); + xprt_set_used(conn, conn->xprt, conn->xprt_ctx); TRACE_LEAVE(H1_EV_STRM_NEW, conn, h1s); return cs; @@ -3106,6 +3107,8 @@ static void h1_detach(struct conn_stream *cs) */ HA_ATOMIC_OR(&h1c->wait_event.tasklet->state, TASK_F_USR1); h1c->conn->xprt->subscribe(h1c->conn, h1c->conn->xprt_ctx, SUB_RETRY_RECV, &h1c->wait_event); + xprt_set_idle(h1c->conn, h1c->conn->xprt, h1c->conn->xprt_ctx); + if (!srv_add_to_idle_list(objt_server(h1c->conn->target), h1c->conn, is_not_first)) { /* The server doesn't want it, let's kill the connection right away */ h1c->conn->mux->destroy(h1c); diff --git a/src/mux_h2.c b/src/mux_h2.c index 2ac61f7..9a4660e 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -4106,6 +4106,7 @@ static struct conn_stream *h2_attach(struct connection *conn, struct session *se /* the connection is not idle anymore, let's mark this */ HA_ATOMIC_AND(&h2c->wait_event.tasklet->state, ~TASK_F_USR1); + xprt_set_used(h2c->conn, h2c->conn->xprt, h2c->conn->xprt_ctx); TRACE_LEAVE(H2_EV_H2S_NEW, conn, h2s); return cs; @@ -4254,6 +4255,8 @@ static void h2_detach(struct conn_stream *cs) * that the handler needs to check it under the idle conns lock. */ HA_ATOMIC_OR(&h2c->wait_event.tasklet->state, TASK_F_USR1); + xprt_set_idle(h2c->conn, h2c->conn->xprt, h2c->conn->xprt_ctx); + if (!srv_add_to_idle_list(objt_server(h2c->conn->target), h2c->conn, 1)) { /* The server doesn't want it, let's kill the connection right away */ h2c->conn->mux->destroy(h2c); -- 1.7.10.4