Compare commits

...
2 Commits
Author SHA1 Message Date
andrew 3b7cc2a70f Don't count_down past 0
CI / pre-commit (push) Successful in 59s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64) (push) Successful in 2m22s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64) (push) Successful in 2m57s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64) (push) Successful in 2m44s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64) (push) Successful in 3m10s
2026-07-17 21:15:23 -04:00
andrew a427278cc0 Read until EAGAIN
To prepare for EPOLLET
2026-07-17 15:39:56 -04:00
4 changed files with 44 additions and 21 deletions
+1 -1
View File
@@ -153,7 +153,7 @@ void Connection::send_response(ProtocolHandle handle,
}
}
int Connection::readBytes(char *buf, size_t buffer_size) {
int Connection::read_bytes(char *buf, size_t buffer_size) {
int r;
for (;;) {
r = read(fd_, buf, buffer_size);
+1 -1
View File
@@ -279,7 +279,7 @@ private:
friend Ref<T> make_ref(Args &&...args);
// Networking interface - only accessible by Server
int readBytes(char *buf, size_t buffer_size);
int read_bytes(char *buf, size_t buffer_size);
enum WriteBytesResult {
Error = 1 << 0,
Progress = 1 << 1,
+22 -13
View File
@@ -409,21 +409,30 @@ void Server::process_connection_reads(Ref<Connection> &conn, int events) {
auto buf_size = config_.server.read_buffer_size;
g_read_buffer.resize(buf_size);
char *buf = g_read_buffer.data();
int r = conn->readBytes(buf, buf_size);
if (r < 0) {
// Error or EOF - connection should be closed
close_connection(conn);
return;
// Once we do EPOLLET we must drain the socket until read returns EAGAIN.
for (;;) {
int r = conn->read_bytes(buf, buf_size);
if (r < 0) {
// Error or EOF - connection should be closed
close_connection(conn);
return;
}
if (r == 0) {
// No data available (EAGAIN) - read side drained
return;
}
// Call handler with connection reference - server retains ownership.
handler_.on_data_arrived(std::string_view{buf, size_t(r)}, *conn);
// The connection may have been closed by the handler; stop reading.
if (!conn) {
return;
}
}
if (r == 0) {
// No data available (EAGAIN) - skip read processing but continue
return;
}
// Call handler with connection reference - server retains ownership
handler_.on_data_arrived(std::string_view{buf, size_t(r)}, *conn);
}
}
+20 -6
View File
@@ -3,22 +3,36 @@
#include "connection_handler.hpp"
#include "server.hpp"
#include <atomic>
#include <doctest/doctest.h>
#include <latch>
#include <string_view>
#include <thread>
struct Event {
void wait() { done_.wait(); }
void set() {
if (!set_.exchange(true, std::memory_order_relaxed)) {
done_.count_down();
}
}
private:
std::latch done_{1};
std::atomic<bool> set_;
};
struct EchoHandler : ConnectionHandler {
Arena arena;
std::span<std::string_view> reply;
WeakRef<MessageSender> wconn;
std::latch done{1};
Event done;
void on_data_arrived(std::string_view data, Connection &conn) override {
reply = arena.allocate_span<std::string_view>(1);
reply[0] = arena.copy_string(data);
wconn = conn.get_weak_ref();
CHECK(wconn.lock());
done.count_down();
done.set();
}
};
@@ -60,8 +74,8 @@ struct ShutdownTestHandler : ConnectionHandler {
Arena arena;
std::span<std::string_view> reply;
WeakRef<MessageSender> wconn;
std::latch received_data{1};
std::latch connection_closed_latch{1};
Event received_data;
Event connection_closed_latch;
ConnectionShutdown shutdown_mode = ConnectionShutdown::None;
std::atomic<bool> connection_closed{false};
@@ -69,12 +83,12 @@ struct ShutdownTestHandler : ConnectionHandler {
reply = arena.allocate_span<std::string_view>(1);
reply[0] = arena.copy_string(data);
wconn = conn.get_weak_ref();
received_data.count_down();
received_data.set();
}
void on_connection_closed(Connection &) override {
connection_closed = true;
connection_closed_latch.count_down();
connection_closed_latch.set();
}
};