Use writev
This commit is contained in:
60
src/main.cpp
60
src/main.cpp
@@ -10,11 +10,13 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <iostream>
|
||||
#include <limits.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
@@ -147,18 +149,13 @@ struct Connection {
|
||||
}
|
||||
}
|
||||
|
||||
struct Message {
|
||||
// Owned by Connection::arena
|
||||
std::string_view s;
|
||||
int written = 0;
|
||||
};
|
||||
std::deque<Message, ArenaStlAllocator<Message>> messages{
|
||||
ArenaStlAllocator<Message>{&arena}};
|
||||
std::deque<std::string_view, ArenaStlAllocator<std::string_view>> messages{
|
||||
ArenaStlAllocator<std::string_view>{&arena}};
|
||||
// Copies s into arena, and appends to messages
|
||||
void appendMessage(std::string_view s) {
|
||||
char *arena_str = arena.allocate<char>(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<void *>(static_cast<const void *>(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())) {
|
||||
|
||||
assert(w > 0);
|
||||
|
||||
// Handle partial writes by updating string_view data/size
|
||||
size_t bytes_written = static_cast<size_t>(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());
|
||||
|
||||
Reference in New Issue
Block a user