From: Willy Tarreau Date: Tue, 2 Mar 2021 16:27:58 +0000 (+0100) Subject: MINOR: xprt: add new xprt_set_idle and xprt_set_used methods X-Git-Tag: v2.4-dev11~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4f8cd4397f07389129dd23b07e94018404340731;p=thirdparty%2Fhaproxy.git 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. --- diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 033f76143b..9c2af7b8f9 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 d8aff5c7bc..e00e6f820a 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 be063cf403..b7d8e94de7 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 7d1bed48dd..c8dc71c72a 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 2ac61f7ac4..9a4660e2f9 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);