New RAII wrapper for Linux epoll instances
This commit is contained in:
@@ -66,6 +66,7 @@ add_executable(Bloom
|
||||
# Helpers & other
|
||||
src/Logger/Logger.cpp
|
||||
src/Helpers/Paths.cpp
|
||||
src/Helpers/EpollInstance.cpp
|
||||
src/VersionNumber.cpp
|
||||
src/Generated/resources.cpp
|
||||
|
||||
|
||||
77
src/Helpers/EpollInstance.cpp
Normal file
77
src/Helpers/EpollInstance.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/Helpers/EpollInstance.hpp
Normal file
70
src/Helpers/EpollInstance.hpp
Normal 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;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user