diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 033f76143..9c2af7b8f 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 d8aff5c7b..e00e6f820 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 be063cf40..b7d8e94de 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 7d1bed48d..c8dc71c72 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 2ac61f7ac..9a4660e2f 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);