]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: connection: add flag CO_FL_WILL_UPDATE to indicate when updates are granted
authorWilly Tarreau <w@1wt.eu>
Wed, 25 Oct 2017 07:22:43 +0000 (09:22 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 25 Oct 2017 13:52:41 +0000 (15:52 +0200)
In transport-layer functions (snd_buf/rcv_buf), it's very problematic
never to know if polling changes made to the connection will be propagated
or not. This has led to some conn_cond_update_polling() calls being placed
at a few places to cover both the cases where the function is called from
the upper layer and when it's called from the lower layer. With the arrival
of the MUX, this becomes even more complicated, as the upper layer will not
have to manipulate anything from the connection layer directly and will not
have to push such updates directly either. But the snd_buf functions will
need to see their updates committed when called from upper layers.

The solution here is to introduce a connection flag set by the connection
handler (and possibly any other similar place) indicating that the caller
is committed to applying such changes on return. This way, the called
functions will be able to apply such changes by themselves before leaving
when the flag is not set, and the upper layer will not have to care about
that anymore.

include/proto/connection.h
include/types/connection.h
src/connection.c

index 1cc216929fc1ed912b1dba023a1bc8a30f0131f9..c472c9a0fdb076674b526b697978b0e447280f92 100644 (file)
@@ -167,11 +167,13 @@ void conn_update_sock_polling(struct connection *c);
 void conn_update_xprt_polling(struct connection *c);
 
 /* Refresh the connection's polling flags from its file descriptor status.
- * This should be called at the beginning of a connection handler.
+ * This should be called at the beginning of a connection handler. It does
+ * nothing if CO_FL_WILL_UPDATE is present, indicating that an upper caller
+ * has already done it.
  */
 static inline void conn_refresh_polling_flags(struct connection *conn)
 {
-       if (conn_ctrl_ready(conn)) {
+       if (conn_ctrl_ready(conn) && !(conn->flags & CO_FL_WILL_UPDATE)) {
                unsigned int flags = conn->flags;
 
                flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA | CO_FL_WAIT_ROOM);
@@ -230,32 +232,38 @@ static inline unsigned int conn_sock_polling_changes(const struct connection *c)
 }
 
 /* Automatically updates polling on connection <c> depending on the XPRT flags
- * if no handshake is in progress.
+ * if no handshake is in progress. It does nothing if CO_FL_WILL_UPDATE is
+ * present, indicating that an upper caller is going to do it again later.
  */
 static inline void conn_cond_update_xprt_polling(struct connection *c)
 {
-       if (!(c->flags & CO_FL_POLL_SOCK) && conn_xprt_polling_changes(c))
-               conn_update_xprt_polling(c);
+       if (!(c->flags & CO_FL_WILL_UPDATE))
+               if (!(c->flags & CO_FL_POLL_SOCK) && conn_xprt_polling_changes(c))
+                       conn_update_xprt_polling(c);
 }
 
 /* Automatically updates polling on connection <c> depending on the SOCK flags
- * if a handshake is in progress.
+ * if a handshake is in progress. It does nothing if CO_FL_WILL_UPDATE is
+ * present, indicating that an upper caller is going to do it again later.
  */
 static inline void conn_cond_update_sock_polling(struct connection *c)
 {
-       if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
-               conn_update_sock_polling(c);
+       if (!(c->flags & CO_FL_WILL_UPDATE))
+               if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
+                       conn_update_sock_polling(c);
 }
 
 /* Stop all polling on the fd. This might be used when an error is encountered
- * for example.
+ * for example. It does not propage the change to the fd layer if
+ * CO_FL_WILL_UPDATE is present, indicating that an upper caller is going to do
+ * it later.
  */
 static inline void conn_stop_polling(struct connection *c)
 {
        c->flags &= ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA |
                      CO_FL_SOCK_RD_ENA | CO_FL_SOCK_WR_ENA |
                      CO_FL_XPRT_RD_ENA | CO_FL_XPRT_WR_ENA);
-       if (conn_ctrl_ready(c))
+       if (!(c->flags & CO_FL_WILL_UPDATE) && conn_ctrl_ready(c))
                fd_stop_both(c->handle.fd);
 }
 
@@ -263,15 +271,19 @@ static inline void conn_stop_polling(struct connection *c)
  * SOCK flags, and on whether a handshake is in progress or not. This may be
  * called at any moment when there is a doubt about the effectiveness of the
  * polling state, for instance when entering or leaving the handshake state.
+ * It does nothing if CO_FL_WILL_UPDATE is present, indicating that an upper
+ * caller is going to do it again later.
  */
 static inline void conn_cond_update_polling(struct connection *c)
 {
        if (unlikely(c->flags & CO_FL_ERROR))
                conn_stop_polling(c);
-       else if (!(c->flags & CO_FL_POLL_SOCK) && conn_xprt_polling_changes(c))
-               conn_update_xprt_polling(c);
-       else if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
-               conn_update_sock_polling(c);
+       else if (!(c->flags & CO_FL_WILL_UPDATE)) {
+               if (!(c->flags & CO_FL_POLL_SOCK) && conn_xprt_polling_changes(c))
+                       conn_update_xprt_polling(c);
+               else if ((c->flags & CO_FL_POLL_SOCK) && conn_sock_polling_changes(c))
+                       conn_update_sock_polling(c);
+       }
 }
 
 /***** Event manipulation primitives for use by DATA I/O callbacks *****/
index d6f9322f77f7334ad963958f54c76002805efaae..c1560cb6d0920311cca6f4b480913c35435bba54 100644 (file)
@@ -83,7 +83,7 @@ enum {
        CO_FL_CTRL_READY    = 0x00000100, /* FD was registered, fd_delete() needed */
        CO_FL_XPRT_READY    = 0x00000200, /* xprt_init() done, xprt_close() needed */
 
-       /* unused : 0x00000400 */
+       CO_FL_WILL_UPDATE   = 0x00000400, /* the conn handler will take care of updating the polling */
 
        /* This flag is used by data layers to indicate they had to stop
         * receiving data because a buffer was full. The connection handler
index b3183b7898871ce0bd9a46ceb4a1315a3e3f64a6..48f0ec33158784a87d2dd4e0127ad2e0f76baaff 100644 (file)
@@ -49,6 +49,8 @@ void conn_fd_handler(int fd)
                return;
 
        conn_refresh_polling_flags(conn);
+       conn->flags |= CO_FL_WILL_UPDATE;
+
        flags = conn->flags & ~CO_FL_ERROR; /* ensure to call the wake handler upon error */
 
  process_handshake:
@@ -174,6 +176,7 @@ void conn_fd_handler(int fd)
        fdtab[fd].ev &= FD_POLL_STICKY;
 
        /* commit polling changes */
+       conn->flags &= ~CO_FL_WILL_UPDATE;
        conn_cond_update_polling(conn);
        return;
 }