From 2b458747f8f997202aaa4392237348a954e35120 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Tue, 19 Aug 2025 12:04:13 -0400 Subject: [PATCH] Use writev --- src/main.cpp | 62 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3c195ee..687cb1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -147,18 +149,13 @@ struct Connection { } } - struct Message { - // Owned by Connection::arena - std::string_view s; - int written = 0; - }; - std::deque> messages{ - ArenaStlAllocator{&arena}}; + std::deque> messages{ + ArenaStlAllocator{&arena}}; // Copies s into arena, and appends to messages void appendMessage(std::string_view s) { char *arena_str = arena.allocate(s.size()); std::memcpy(arena_str, s.data(), s.size()); - messages.emplace_back(std::string_view(arena_str, s.size()), 0); + messages.emplace_back(arena_str, s.size()); } // Whether or not to close the connection after completing writing the // response @@ -192,11 +189,28 @@ struct Connection { bool writeBytes() { while (!messages.empty()) { - auto &front = messages.front(); - int w; + // Build iovec array up to IOV_MAX limit + struct iovec iov[IOV_MAX]; + int iov_count = 0; + + for (auto it = messages.begin(); + it != messages.end() && iov_count < IOV_MAX; ++it) { + const auto &msg = *it; + if (msg.size() > 0) { + iov[iov_count] = { + const_cast(static_cast(msg.data())), + msg.size()}; + iov_count++; + } + } + + if (iov_count == 0) { + break; + } + + ssize_t w; for (;;) { - w = write(fd, front.s.data() + front.written, - front.s.size() - front.written); + w = writev(fd, iov, iov_count); if (w == -1) { if (errno == EINTR) { continue; // Standard practice: retry on signal interruption @@ -204,15 +218,29 @@ struct Connection { if (errno == EAGAIN) { return false; } - perror("write"); + perror("writev"); return true; } break; } - assert(w != 0); - front.written += w; - if (front.written == int(front.s.size())) { - messages.pop_front(); + + assert(w > 0); + + // Handle partial writes by updating string_view data/size + size_t bytes_written = static_cast(w); + while (bytes_written > 0 && !messages.empty()) { + auto &front = messages.front(); + + if (bytes_written >= front.size()) { + // This message is completely written + bytes_written -= front.size(); + messages.pop_front(); + } else { + // Partial write of this message - update string_view + front = std::string_view(front.data() + bytes_written, + front.size() - bytes_written); + bytes_written = 0; + } } } assert(messages.empty());