Refactored EventNotifier RAII class
This commit is contained in:
@@ -8,6 +8,7 @@ target_sources(
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/Logger/Logger.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Logger/Logger.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Helpers/Paths.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Helpers/Paths.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Helpers/EpollInstance.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Helpers/EpollInstance.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/Helpers/EventNotifier.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/VersionNumber.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/VersionNumber.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Generated/resources.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/Generated/resources.cpp
|
||||||
|
|
||||||
|
|||||||
55
src/Helpers/EventNotifier.cpp
Normal file
55
src/Helpers/EventNotifier.cpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#include "EventNotifier.hpp"
|
||||||
|
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
|
||||||
|
namespace Bloom
|
||||||
|
{
|
||||||
|
using Exceptions::Exception;
|
||||||
|
|
||||||
|
EventNotifier::EventNotifier() {
|
||||||
|
this->fileDescriptor = ::eventfd(0, EFD_NONBLOCK);
|
||||||
|
|
||||||
|
if (this->fileDescriptor < 0) {
|
||||||
|
throw Exception(
|
||||||
|
"Failed to create eventfd object - error number " + std::to_string(errno)
|
||||||
|
+ " returned."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EventNotifier::EventNotifier(EventNotifier&& other) noexcept
|
||||||
|
: fileDescriptor(other.fileDescriptor)
|
||||||
|
{
|
||||||
|
other.fileDescriptor = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventNotifier::~EventNotifier() noexcept {
|
||||||
|
this->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventNotifier::notify() {
|
||||||
|
if (::eventfd_write(this->fileDescriptor.value(), 1) < 0) {
|
||||||
|
throw Exceptions::Exception("Failed to increment eventfd counter - error number: "
|
||||||
|
+ std::to_string(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventNotifier::clear() {
|
||||||
|
eventfd_t counter = {};
|
||||||
|
if (::eventfd_read(this->fileDescriptor.value(), &counter) < 0 && errno != EAGAIN) {
|
||||||
|
throw Exceptions::Exception("Failed to clear EventNotifier object - eventfd_read failed - "
|
||||||
|
"error number: " + std::to_string(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventNotifier::close() {
|
||||||
|
if (this->fileDescriptor.value_or(-1) >= 0) {
|
||||||
|
::close(this->fileDescriptor.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,82 +1,45 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/eventfd.h>
|
#include <optional>
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include "src/Exceptions/Exception.hpp"
|
|
||||||
|
|
||||||
namespace Bloom
|
namespace Bloom
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The EventNotifier class provides a means to interrupt a thread that is blocked by an IO call.
|
* The EventNotifier class is an RAII wrapper for a Linux eventfd object.
|
||||||
*
|
|
||||||
* It's implementation is rather simple: It uses a Linux event file descriptor (sys/eventfd.h), which should be used
|
|
||||||
* along side epoll() to interrupt a blocking call that is waiting on the epoll file descriptor.
|
|
||||||
*
|
*
|
||||||
* The EventListener can hold an instance to EventNotifier, where it will invoke EventNotifier::notify() everytime
|
* The EventListener can hold an instance to EventNotifier, where it will invoke EventNotifier::notify() everytime
|
||||||
* a new event is registered on the listener.
|
* a new event is registered on the listener.
|
||||||
*
|
|
||||||
* @TODO: This could do with some cleaning. It's a bit hacky. Also, maybe add the ability to register the event
|
|
||||||
* file descriptor to an epoll instance within a public method (instead of relying on the caller to do this
|
|
||||||
* themselves via EventNotifier::getFileDescriptor()).
|
|
||||||
*/
|
*/
|
||||||
class EventNotifier
|
class EventNotifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EventNotifier() {
|
EventNotifier();
|
||||||
this->init();
|
|
||||||
};
|
|
||||||
|
|
||||||
~EventNotifier() {
|
/*
|
||||||
if (this->initialised) {
|
* EpollInstance objects should not be copied.
|
||||||
this->close();
|
*/
|
||||||
}
|
EventNotifier(EventNotifier& other) = delete;
|
||||||
|
EventNotifier& operator = (EventNotifier& other) = delete;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Implement this. For now, use the move constructor.
|
||||||
|
*/
|
||||||
|
EventNotifier& operator = (EventNotifier&& other) = delete;
|
||||||
|
|
||||||
|
EventNotifier(EventNotifier&& other) noexcept;
|
||||||
|
~EventNotifier() noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] int getFileDescriptor() const {
|
||||||
|
return this->fileDescriptor.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getFileDescriptor() const {
|
void notify();
|
||||||
return this->fileDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInitialised() {
|
void clear();
|
||||||
return this->initialised;
|
|
||||||
}
|
|
||||||
|
|
||||||
void notify() {
|
|
||||||
if (::eventfd_write(this->fileDescriptor, 1) < 0) {
|
|
||||||
throw Exceptions::Exception("Failed to increment eventfd counter - error number: "
|
|
||||||
+ std::to_string(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
eventfd_t counter;
|
|
||||||
if (::eventfd_read(this->fileDescriptor, &counter) < 0 && errno != EAGAIN) {
|
|
||||||
throw Exceptions::Exception("Failed to clear EventNotifier object - eventfd_read failed - "
|
|
||||||
"error number: " + std::to_string(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fileDescriptor = -1;
|
std::optional<int> fileDescriptor;
|
||||||
std::atomic<bool> initialised = false;
|
|
||||||
|
|
||||||
void init() {
|
void close();
|
||||||
this->fileDescriptor = ::eventfd(0, EFD_NONBLOCK);
|
|
||||||
|
|
||||||
if (this->fileDescriptor < -1) {
|
|
||||||
throw Exceptions::Exception("Failed to create new eventfd object - error number: "
|
|
||||||
+ std::to_string(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
this->initialised = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void close() {
|
|
||||||
::close(this->fileDescriptor);
|
|
||||||
this->initialised = false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user