New RAII wrapper for Linux epoll instances

This commit is contained in:
Nav
2022-03-28 01:02:52 +01:00
parent 3bd09bdc84
commit 2b55f8f5ea
3 changed files with 148 additions and 0 deletions

View File

@@ -66,6 +66,7 @@ add_executable(Bloom
# Helpers & other # Helpers & other
src/Logger/Logger.cpp src/Logger/Logger.cpp
src/Helpers/Paths.cpp src/Helpers/Paths.cpp
src/Helpers/EpollInstance.cpp
src/VersionNumber.cpp src/VersionNumber.cpp
src/Generated/resources.cpp src/Generated/resources.cpp

View File

@@ -0,0 +1,77 @@
#include "EpollInstance.hpp"
#include <string>
#include <cerrno>
#include <unistd.h>
#include <array>
#include "src/Exceptions/Exception.hpp"
namespace Bloom
{
using Exceptions::Exception;
EpollInstance::EpollInstance() {
this->fileDescriptor = ::epoll_create(1);
if (this->fileDescriptor < 0) {
throw Exception(
"Failed to create epoll instance - error number " + std::to_string(errno)
+ " returned."
);
}
}
void EpollInstance::addEntry(int fileDescriptor, std::uint16_t eventMask) {
struct epoll_event event = {
.events = eventMask,
.data = {
.fd = fileDescriptor
}
};
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_ADD, fileDescriptor, &event) != 0) {
throw Exception(
"Failed to add entry to epoll instance - error number " + std::to_string(errno) + " returned."
);
}
}
void EpollInstance::removeEntry(int fileDescriptor) {
if (::epoll_ctl(this->fileDescriptor.value(), EPOLL_CTL_DEL, fileDescriptor, NULL) != 0) {
throw Exception(
"Failed to remove entry from epoll instance - error number " + std::to_string(errno)
+ " returned."
);
}
}
std::optional<int> EpollInstance::waitForEvent(std::optional<std::chrono::milliseconds> timeout) {
std::array<struct epoll_event, 1> events = {};
const auto eventCount = ::epoll_wait(
this->fileDescriptor.value(),
events.data(),
1,
timeout.has_value() ? static_cast<int>(timeout->count()) : -1
);
if (eventCount < 1) {
return std::nullopt;
}
return static_cast<int>(events.at(0).data.fd);
}
EpollInstance::EpollInstance(EpollInstance&& other) noexcept
: fileDescriptor(other.fileDescriptor)
{
other.fileDescriptor = std::nullopt;
}
EpollInstance::~EpollInstance() noexcept {
if (this->fileDescriptor.value_or(-1) >= 0) {
::close(this->fileDescriptor.value());
}
}
}

View File

@@ -0,0 +1,70 @@
#pragma once
#include <sys/epoll.h>
#include <cstdint>
#include <optional>
#include <chrono>
namespace Bloom
{
enum class EpollEvent: std::uint16_t
{
READ_READY = EPOLL_EVENTS::EPOLLIN,
WRITE_READY = EPOLL_EVENTS::EPOLLOUT,
};
/**
* The EpollInstance class is an RAII wrapper for a single Linux epoll instance.
*
* See https://man7.org/linux/man-pages/man7/epoll.7.html for more on the Linux epoll API.
*/
class EpollInstance
{
public:
EpollInstance();
/**
* Adds an entry to the epoll instance.
*
* @param fileDescriptor
* @param eventMask
*/
void addEntry(int fileDescriptor, std::uint16_t eventMask);
/**
* Removes an entry from the epoll instance.
*
* @param fileDescriptor
*/
void removeEntry(int fileDescriptor);
/**
* Waits on the epoll instance until an event occurs for any of the registered files.
*
* @param timeout
* Millisecond timeout. If not provided, no timeout will be applied and this function will block until an
* event occurs.
*
* @return
* The file descriptor of the file for which the event occurred, or std::nullopt if a timeout was reached.
*/
std::optional<int> waitForEvent(std::optional<std::chrono::milliseconds> timeout = std::nullopt);
/*
* EpollInstance objects should not be copied.
*/
EpollInstance(EpollInstance& other) = delete;
EpollInstance& operator = (EpollInstance& other) = delete;
/*
* TODO: Implement this. For now, use the move constructor.
*/
EpollInstance& operator = (EpollInstance&& other) = delete;
EpollInstance(EpollInstance&& other) noexcept;
~EpollInstance() noexcept;
private:
std::optional<int> fileDescriptor;
};
}