Refactored EventNotifier RAII class

This commit is contained in:
Nav
2022-04-05 22:37:26 +01:00
parent 7b5ce83b50
commit bd73051003
3 changed files with 79 additions and 60 deletions

View File

@@ -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

View 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());
}
}
}

View File

@@ -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;
}
}; };
} }