Skip to content

Commit

Permalink
epoll and kqueue stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
braindigitalis committed Apr 4, 2024
1 parent eb5d05b commit 9566009
Show file tree
Hide file tree
Showing 9 changed files with 310 additions and 12 deletions.
17 changes: 17 additions & 0 deletions cmake/epoll.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
macro(CHECK_EPOLL VARIABLE)
if(UNIX)
if("${VARIABLE}" MATCHES "^${VARIABLE}$")
message(STATUS "Check if the system supports epoll")
include(CheckSymbolExists)
check_symbol_exists(epoll_create "sys/epoll.h" EPOLL_PROTOTYPE_EXISTS)

if(EPOLL_PROTOTYPE_EXISTS)
message(STATUS "Check if the system supports epoll - yes")
set(${VARIABLE} 1 CACHE INTERNAL "Result of CHECK_EPOLL" FORCE)
else(EPOLL_PROTOTYPE_EXISTS)
message(STATUS "Check if the system supports epoll - no")
set(${VARIABLE} "" CACHE INTERNAL "Result of CHECK_EPOLL" FORCE)
endif(EPOLL_PROTOTYPE_EXISTS)
endif("${VARIABLE}" MATCHES "^${VARIABLE}$")
endif(UNIX)
endmacro(CHECK_EPOLL)
17 changes: 17 additions & 0 deletions cmake/kqueue.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
macro(CHECK_KQUEUE VARIABLE)
if(UNIX)
if("${VARIABLE}" MATCHES "^${VARIABLE}$")
message(STATUS "Check if the system supports kqueue")
include(CheckSymbolExists)
check_symbol_exists(kqueue "sys/event.h" KQUEUE_PROTOTYPE_EXISTS)

if(KQUEUE_PROTOTYPE_EXISTS)
message(STATUS "Check if the system supports kqueue - yes")
set(${VARIABLE} 1 CACHE INTERNAL "Result of CHECK_KQUEUE" FORCE)
else(KQUEUE_PROTOTYPE_EXISTS)
message(STATUS "Check if the system supports kqueue - no")
set(${VARIABLE} "" CACHE INTERNAL "Result of CHECK_KQUEUE" FORCE)
endif(KQUEUE_PROTOTYPE_EXISTS)
endif("${VARIABLE}" MATCHES "^${VARIABLE}$")
endif(UNIX)
endmacro(CHECK_KQUEUE)
13 changes: 9 additions & 4 deletions include/dpp/socketengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ enum socket_event_flags : uint8_t {
WANT_ERROR = 4,
};

using socket_read_event = auto (*)(const struct socket_event&) -> void;
using socket_write_event = auto (*)(const struct socket_event&) -> void;
using socket_error_event = auto (*)(const struct socket_event&, int error_code) -> void;
using socket_read_event = auto (*)(dpp::socket fd, const struct socket_events&) -> void;
using socket_write_event = auto (*)(dpp::socket fd, const struct socket_events&) -> void;
using socket_error_event = auto (*)(dpp::socket fd, const struct socket_events&, int error_code) -> void;

struct socket_events {
uint8_t flags{0};
Expand All @@ -48,9 +48,14 @@ struct socket_engine_base {
socket_container fds;

socket_engine_base();
socket_engine_base(const socket_engine_base&) = default;
socket_engine_base(socket_engine_base&&) = default;
socket_engine_base& operator=(const socket_engine_base&) = default;
socket_engine_base& operator=(socket_engine_base&&) = default;

virtual ~socket_engine_base() = default;

virtual void run() = 0;
virtual void process_events() = 0;
virtual bool register_socket(dpp::socket fd, const socket_events& e);
virtual bool update_socket(dpp::socket fd, const socket_events& e);
virtual bool remove_socket(dpp::socket fd);
Expand Down
16 changes: 16 additions & 0 deletions library-vcpkg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ else()
find_package(Threads REQUIRED)
endif()

include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/epoll.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/kqueue.cmake")
check_epoll(HAS_EPOLL)
check_kqueue(HAS_KQUEUE)
if (HAS_EPOLL)
message("-- Building with ${Green}epoll socket engine${ColourReset} -- good!")
target_sources("${LIB_NAME}" PRIVATE "${DPP_ROOT_PATH}/src/dpp/socketengines/epoll.cpp")
elseif (HAS_KQUEUE)
message("-- Building with ${Green}kqueue socket engine${ColourReset} -- good!")
target_sources("${LIB_NAME}" PRIVATE "${DPP_ROOT_PATH}/src/dpp/socketengines/kqueue.cpp")
else()
message("-- Building with ${Green}poll socket engine${ColourReset} -- meh!")
target_sources("${LIB_NAME}" PRIVATE "${DPP_ROOT_PATH}/src/dpp/socketengines/poll.cpp")
endif()


add_library("${PROJECT_NAME}::${LIB_NAME}" ALIAS "${LIB_NAME}")

if(${AVX_TYPE} STREQUAL "OFF")
Expand Down
15 changes: 15 additions & 0 deletions library/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,21 @@ foreach (fullmodname ${subdirlist})
endif()
endforeach()

include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/epoll.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/kqueue.cmake")
check_epoll(HAS_EPOLL)
check_kqueue(HAS_KQUEUE)
if (HAS_EPOLL)
message("-- Building with ${Green}epoll socket engine${ColourReset} -- good!")
target_sources("dpp" PRIVATE "${modules_dir}/dpp/socketengines/epoll.cpp")
elseif (HAS_KQUEUE)
message("-- Building with ${Green}kqueue socket engine${ColourReset} -- good!")
target_sources("dpp" PRIVATE "${modules_dir}/dpp/socketengines/kqueue.cpp")
else()
message("-- Building with ${Green}poll socket engine${ColourReset} -- meh!")
target_sources("dpp" PRIVATE "${modules_dir}/dpp/socketengines/poll.cpp")
endif()

target_compile_features(dpp PUBLIC cxx_std_17)
target_compile_features(dpp PRIVATE cxx_constexpr)
target_compile_features(dpp PRIVATE cxx_auto_type)
Expand Down
3 changes: 1 addition & 2 deletions src/dpp/socketengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@

bool socket_engine_base::register_socket(dpp::socket fd, const socket_events &e) {
if (fd > INVALID_SOCKET && fds.find(fd) == fds.end()) {
auto se = std::make_unique<socket_events>();
*se = e;
fds.emplace(fd, std::make_unique<socket_events>(e));
return true;
}
return false;
Expand Down
72 changes: 67 additions & 5 deletions src/dpp/socketengines/epoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,80 @@
#include <dpp/exception.h>
#include <memory>
#include <sys/epoll.h>
#include <socket.h>
#include <sys/socket.h>
#include <vector>

struct socket_engine_epoll : public socket_engine_base {

int epoll_handle{INVALID_SOCKET};
const int epoll_hint = 128;
static const int epoll_hint = 128;
std::vector<struct epoll_event> events;

socket_engine_epoll() : epoll_handle(epoll_create(epoll_hint)) {
socket_engine_epoll(const socket_engine_epoll&) = default;
socket_engine_epoll(socket_engine_epoll&&) = default;
socket_engine_epoll& operator=(const socket_engine_epoll&) = default;
socket_engine_epoll& operator=(socket_engine_epoll&&) = default;

socket_engine_epoll() : epoll_handle(epoll_create(socket_engine_epoll::epoll_hint)) {
events.resize(16);
if (epoll_handle == -1) {
throw dpp::connection_exception("Failed to initialise epoll()");
}
}

~socket_engine_epoll() {
~socket_engine_epoll() override {
if (epoll_handle != INVALID_SOCKET) {
close(epoll_handle);
}
}

void run() override {
// TODO: event routing loop for epoll() goes here
void process_events() final {
const int sleep_length = 1000;
int i = epoll_wait(epoll_handle, events.data(), static_cast<int>(events.size()), sleep_length);

for (int j = 0; j < i; j++) {
epoll_event ev = events[j];

auto* const eh = static_cast<socket_events*>(ev.data.ptr);
const int fd = ev.data.fd;
if (fd == INVALID_SOCKET) {
continue;
}

if ((ev.events & EPOLLHUP) != 0U) {
eh->on_error(fd, *eh, 0);
continue;
}

if ((ev.events & EPOLLERR) != 0U) {
/* Get error number */
socklen_t codesize = sizeof(int);
int errcode{};
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) {
errcode = errno;
}
eh->on_error(fd, *eh, errcode);
continue;
}

if ((ev.events & EPOLLOUT) != 0U) {
int new_events = eh->flags & ~WANT_WRITE;
if (new_events != eh->flags) {
ev.events = new_events;
ev.data.ptr = static_cast<void *>(eh);
epoll_ctl(epoll_handle, EPOLL_CTL_MOD, fd, &ev);
}
eh->flags = new_events;
}
if (ev.events & EPOLLIN) {
eh->on_read(fd, *eh);
}
if (ev.events & EPOLLOUT) {
eh->on_write(fd, *eh);
}
}

}

bool register_socket(dpp::socket fd, const socket_events& e) final {
Expand All @@ -56,11 +109,17 @@ struct socket_engine_epoll : public socket_engine_base {
if ((e.flags & WANT_WRITE) != 0) {
ev.events |= EPOLLOUT;
}
if ((e.flags & WANT_ERROR) != 0) {
ev.events |= EPOLLERR;
}
ev.data.ptr = fds.find(fd)->second.get();
int i = epoll_ctl(epoll_handle, EPOLL_CTL_ADD, fd, &ev);
if (i < 0) {
throw dpp::connection_exception("Failed to register socket to epoll_ctl()");
}
if (fds.size() * 2 > events.size()) {
events.resize(fds.size() * 2);
}
}
return r;
}
Expand All @@ -75,6 +134,9 @@ struct socket_engine_epoll : public socket_engine_base {
if ((e.flags & WANT_WRITE) != 0) {
ev.events |= EPOLLOUT;
}
if ((e.flags & WANT_ERROR) != 0) {
ev.events |= EPOLLERR;
}
ev.data.ptr = fds.find(fd)->second.get();
int i = epoll_ctl(epoll_handle, EPOLL_CTL_MOD, fd, &ev);
if (i < 0) {
Expand Down
Loading

0 comments on commit 9566009

Please sign in to comment.