The branch, master has been updated
       via  481b961be99 async_sock: try recvmsg(MSG_DONTWAIT) without fd event 
handler first
       via  d4b5784cb59 async_sock: split out read_packet_do() from 
read_packet_handler()
       via  5d1ab4b02f1 async_sock: make use of recvmsg() in 
read_packet_handler()
       via  75ca6f5aa08 async_sock: let writev_do() try sendmsg() first
      from  cdb9fa71db3 source3/wscript: Remove extra config 
WITH_PROMETHEUS_EXPORTER

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 481b961be9971b999f9ef73a26dbad6dfdbc5ae4
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Apr 28 17:56:37 2025 +0200

    async_sock: try recvmsg(MSG_DONTWAIT) without fd event handler first
    
    Also callers typically read a header to get the length and then
    the remaining data, for that we typically don't need an additional
    hop via [e]poll.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>
    
    Autobuild-User(master): Stefan Metzmacher <[email protected]>
    Autobuild-Date(master): Mon May 12 11:28:47 UTC 2025 on atb-devel-224

commit d4b5784cb599b9ee8cb4cf94feccb880ad94f1d3
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Apr 28 17:54:31 2025 +0200

    async_sock: split out read_packet_do() from read_packet_handler()
    
    We'll call read_packet_do() in other places too in future.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>

commit 5d1ab4b02f113b9a0d87013748475d6668caa72a
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Apr 28 17:46:44 2025 +0200

    async_sock: make use of recvmsg() in read_packet_handler()
    
    This typically has a better call stack in the kernel.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>

commit 75ca6f5aa08251885b1ba414ed72afc272f20f93
Author: Stefan Metzmacher <[email protected]>
Date:   Mon Apr 28 17:38:15 2025 +0200

    async_sock: let writev_do() try sendmsg() first
    
    This is typically more efficient on the kernel call stack.
    As far as I can see writev_send/recv is only used with sockets
    so far, but in any case we fallback on ENOTSOCK.
    
    Signed-off-by: Stefan Metzmacher <[email protected]>
    Reviewed-by: Volker Lendecke <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 lib/async_req/async_sock.c | 108 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 97 insertions(+), 11 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/async_req/async_sock.c b/lib/async_req/async_sock.c
index 795a2c63dba..06ffb942967 100644
--- a/lib/async_req/async_sock.c
+++ b/lib/async_req/async_sock.c
@@ -235,6 +235,7 @@ struct writev_state {
        struct tevent_context *ev;
        struct tevent_queue_entry *queue_entry;
        int fd;
+       bool is_sock;
        struct tevent_fd *fde;
        struct iovec *iov;
        int count;
@@ -264,6 +265,7 @@ struct tevent_req *writev_send(TALLOC_CTX *mem_ctx, struct 
tevent_context *ev,
        }
        state->ev = ev;
        state->fd = fd;
+       state->is_sock = true;
        state->total_size = 0;
        state->count = count;
        state->iov = (struct iovec *)talloc_memdup(
@@ -341,7 +343,20 @@ static void writev_do(struct tevent_req *req, struct 
writev_state *state)
        ssize_t written;
        bool ok;
 
-       written = writev(state->fd, state->iov, state->count);
+       if (state->is_sock) {
+               struct msghdr msg = {
+                       .msg_iov = state->iov,
+                       .msg_iovlen = state->count,
+               };
+
+               written = sendmsg(state->fd, &msg, 0);
+               if ((written == -1) && (errno == ENOTSOCK)) {
+                       state->is_sock = false;
+               }
+       }
+       if (!state->is_sock) {
+               written = writev(state->fd, state->iov, state->count);
+       }
        if ((written == -1) &&
            ((errno == EINTR) ||
             (errno == EAGAIN) ||
@@ -434,6 +449,7 @@ ssize_t writev_recv(struct tevent_req *req, int *perrno)
 
 struct read_packet_state {
        int fd;
+       bool is_sock;
        struct tevent_fd *fde;
        uint8_t *buf;
        size_t nread;
@@ -443,6 +459,8 @@ struct read_packet_state {
 
 static void read_packet_cleanup(struct tevent_req *req,
                                 enum tevent_req_state req_state);
+static void read_packet_do(struct tevent_req *req,
+                          uint16_t ready_flags);
 static void read_packet_handler(struct tevent_context *ev,
                                struct tevent_fd *fde,
                                uint16_t flags, void *private_data);
@@ -463,6 +481,7 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
                return NULL;
        }
        state->fd = fd;
+       state->is_sock = true;
        state->nread = 0;
        state->more = more;
        state->private_data = private_data;
@@ -474,6 +493,17 @@ struct tevent_req *read_packet_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       /*
+        * Call read_packet_do()
+        * with ready_flags = 0,
+        * so only recvmsg(MSG_DONTWAIT)
+        * will be tried.
+        */
+       read_packet_do(req, 0);
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, ev);
+       }
+
        state->fde = tevent_add_fd(ev, state, fd,
                                   TEVENT_FD_READ, read_packet_handler,
                                   req);
@@ -492,26 +522,54 @@ static void read_packet_cleanup(struct tevent_req *req,
        TALLOC_FREE(state->fde);
 }
 
-static void read_packet_handler(struct tevent_context *ev,
-                               struct tevent_fd *fde,
-                               uint16_t flags, void *private_data)
+static void read_packet_do(struct tevent_req *req,
+                          uint16_t ready_flags)
 {
-       struct tevent_req *req = talloc_get_type_abort(
-               private_data, struct tevent_req);
        struct read_packet_state *state =
                tevent_req_data(req, struct read_packet_state);
-       size_t total = talloc_get_size(state->buf);
+       size_t total;
        ssize_t nread, more;
        uint8_t *tmp;
 
-       nread = recv(state->fd, state->buf+state->nread, total-state->nread,
-                    0);
-       if ((nread == -1) && (errno == ENOTSOCK)) {
+retry:
+       total = talloc_get_size(state->buf);
+       if (state->is_sock) {
+               struct iovec iov = {
+                       .iov_base = state->buf+state->nread,
+                       .iov_len = total-state->nread,
+               };
+               struct msghdr msg = {
+                       .msg_iov = &iov,
+                       .msg_iovlen = 1,
+               };
+
+               nread = recvmsg(state->fd, &msg, MSG_DONTWAIT);
+               if ((nread == -1) && (errno == ENOTSOCK)) {
+                       state->is_sock = false;
+               }
+       }
+       if (!state->is_sock) {
+               if (!(ready_flags & TEVENT_FD_READ)) {
+                       /*
+                        * With out TEVENT_FD_READ read() may block,
+                        * so we just return here and retry via
+                        * fd event handler
+                        */
+                       return;
+               }
                nread = read(state->fd, state->buf+state->nread,
                             total-state->nread);
        }
        if ((nread == -1) && (errno == EINTR)) {
-               /* retry */
+               /* retry directly */
+               goto retry;
+       }
+       if ((nread == -1) && (errno == EAGAIN)) {
+               /* retry later via fd event handler */
+               return;
+       }
+       if ((nread == -1) && (errno == EWOULDBLOCK)) {
+               /* retry later via fd event handler */
                return;
        }
        if (nread == -1) {
@@ -523,6 +581,13 @@ static void read_packet_handler(struct tevent_context *ev,
                return;
        }
 
+       /*
+        * We have pulled some data out of the fd!
+        * A possible retry can't rely
+        * on TEVENT_FD_READ semantics anymore.
+        */
+       ready_flags &= ~TEVENT_FD_READ;
+
        state->nread += nread;
        if (state->nread < total) {
                /* Come back later */
@@ -560,6 +625,27 @@ static void read_packet_handler(struct tevent_context *ev,
                return;
        }
        state->buf = tmp;
+
+       /*
+        * We already cleared TEVENT_FD_READ,
+        * we do a retry without it.
+        *
+        * We either do recvmsg(MSG_DONTWAIT)
+        * or return without any further read
+        * because TEVENT_FD_READ was already
+        * cleared.
+        */
+       goto retry;
+}
+
+static void read_packet_handler(struct tevent_context *ev,
+                               struct tevent_fd *fde,
+                               uint16_t flags, void *private_data)
+{
+       struct tevent_req *req = talloc_get_type_abort(
+               private_data, struct tevent_req);
+
+       read_packet_do(req, flags);
 }
 
 ssize_t read_packet_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,


-- 
Samba Shared Repository

Reply via email to