MINOR: xprt: add new xprt_set_idle and xprt_set_used methods
authorWilly Tarreau <w@1wt.eu>
Tue, 2 Mar 2021 16:27:58 +0000 (17:27 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 5 Mar 2021 07:30:08 +0000 (08:30 +0100)
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
include/haproxy/connection.h
src/mux_fcgi.c
src/mux_h1.c
src/mux_h2.c

index 033f761..9c2af7b 100644 (file)
@@ -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 <es> to events, such as "being able to send" */
        int (*unsubscribe)(struct connection *conn, void *xprt_ctx, int event_type, struct wait_event *es); /* Unsubscribe <es> from events */
index d8aff5c..e00e6f8 100644 (file)
@@ -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)
index be063cf..b7d8e94 100644 (file)
@@ -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);
index 7d1bed4..c8dc71c 100644 (file)
@@ -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);
index 2ac61f7..9a4660e 100644 (file)
@@ -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);