diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba0c564c..f42be744 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/Logger/Logger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Helpers/Paths.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}/Generated/resources.cpp diff --git a/src/Helpers/EventNotifier.cpp b/src/Helpers/EventNotifier.cpp new file mode 100644 index 00000000..aebd67f1 --- /dev/null +++ b/src/Helpers/EventNotifier.cpp @@ -0,0 +1,55 @@ +#include "EventNotifier.hpp" + +#include +#include +#include +#include + +#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()); + } + } +} diff --git a/src/Helpers/EventNotifier.hpp b/src/Helpers/EventNotifier.hpp index 66d98ab3..d908b6b9 100644 --- a/src/Helpers/EventNotifier.hpp +++ b/src/Helpers/EventNotifier.hpp @@ -1,82 +1,45 @@ #pragma once -#include -#include -#include -#include -#include - -#include "src/Exceptions/Exception.hpp" +#include namespace Bloom { /** - * The EventNotifier class provides a means to interrupt a thread that is blocked by an IO call. - * - * 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 EventNotifier class is an RAII wrapper for a Linux eventfd object. * * The EventListener can hold an instance to EventNotifier, where it will invoke EventNotifier::notify() everytime * 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 { public: - EventNotifier() { - this->init(); - }; + EventNotifier(); - ~EventNotifier() { - if (this->initialised) { - this->close(); - } + /* + * EpollInstance objects should not be copied. + */ + 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 { - return this->fileDescriptor; - } + void notify(); - bool isInitialised() { - 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)); - } - } + void clear(); private: - int fileDescriptor = -1; - std::atomic initialised = false; + std::optional fileDescriptor; - void init() { - 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; - } + void close(); }; }