From ec060a469b32c7fb58f8e0b44690a83b00ec755e Mon Sep 17 00:00:00 2001 From: Nav Date: Fri, 15 Apr 2022 22:05:50 +0100 Subject: [PATCH] Renamed EventNotifer to EventFdNotifier and employed new NotifierInterface --- src/CMakeLists.txt | 2 +- src/DebugServer/DebugServerComponent.cpp | 3 +- src/DebugServer/DebugServerComponent.hpp | 6 +-- src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp | 5 +- src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp | 3 +- src/DebugServer/Gdb/Connection.cpp | 2 +- src/DebugServer/Gdb/Connection.hpp | 12 ++--- src/DebugServer/Gdb/GdbRspDebugServer.cpp | 17 ++++--- src/DebugServer/Gdb/GdbRspDebugServer.hpp | 12 +++-- src/DebugServer/README.md | 17 +++---- src/EventManager/EventListener.hpp | 8 ++-- ...{EventNotifier.cpp => EventFdNotifier.cpp} | 16 +++---- src/Helpers/EventFdNotifier.hpp | 46 +++++++++++++++++++ src/Helpers/EventNotifier.hpp | 45 ------------------ 14 files changed, 100 insertions(+), 94 deletions(-) rename src/Helpers/{EventNotifier.cpp => EventFdNotifier.cpp} (73%) create mode 100644 src/Helpers/EventFdNotifier.hpp delete mode 100644 src/Helpers/EventNotifier.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f42be744..52def3d1 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +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}/Helpers/EventFdNotifier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/VersionNumber.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Generated/resources.cpp diff --git a/src/DebugServer/DebugServerComponent.cpp b/src/DebugServer/DebugServerComponent.cpp index ee1bd148..7c7c6177 100644 --- a/src/DebugServer/DebugServerComponent.cpp +++ b/src/DebugServer/DebugServerComponent.cpp @@ -44,7 +44,8 @@ namespace Bloom::DebugServer [this] () -> std::unique_ptr { return std::make_unique( this->debugServerConfig, - *(this->eventListener.get()) + *(this->eventListener.get()), + this->interruptEventNotifier ); } }, diff --git a/src/DebugServer/DebugServerComponent.hpp b/src/DebugServer/DebugServerComponent.hpp index 009a0180..9cb4bf5a 100644 --- a/src/DebugServer/DebugServerComponent.hpp +++ b/src/DebugServer/DebugServerComponent.hpp @@ -7,7 +7,7 @@ #include "src/Helpers/Thread.hpp" #include "src/ProjectConfig.hpp" -#include "src/Helpers/EventNotifier.hpp" +#include "src/Helpers/EventFdNotifier.hpp" #include "src/EventManager/EventListener.hpp" #include "src/EventManager/Events/Events.hpp" @@ -48,11 +48,11 @@ namespace Bloom::DebugServer DebugServerConfig debugServerConfig; /** - * This EventNotifier is injected into this->eventListener. It can be used by server implementations to + * This EventFdNotifier is injected into this->eventListener. It can be used by server implementations to * interrupt blocking I/O calls upon an event being triggered. For more, see the "Servicing events" section in * the DebugServer documentation (src/DebugServer/README.md). */ - EventNotifier interruptEventNotifier = EventNotifier(); + EventFdNotifier interruptEventNotifier = EventFdNotifier(); /** * An instance to the selected server implementation. See DebugServerComponent::startup() for more. diff --git a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp index c6c2cf1d..360d7168 100644 --- a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp +++ b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.cpp @@ -13,9 +13,10 @@ namespace Bloom::DebugServer::Gdb::AvrGdb AvrGdbRsp::AvrGdbRsp( const DebugServerConfig& debugServerConfig, - EventListener& eventListener + EventListener& eventListener, + EventFdNotifier& eventNotifier ) - : GdbRspDebugServer(debugServerConfig, eventListener) + : GdbRspDebugServer(debugServerConfig, eventListener, eventNotifier) {} void AvrGdbRsp::init() { diff --git a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp index 3481de47..90b57120 100644 --- a/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp +++ b/src/DebugServer/Gdb/AvrGdb/AvrGdbRsp.hpp @@ -28,7 +28,8 @@ namespace Bloom::DebugServer::Gdb::AvrGdb public: AvrGdbRsp( const DebugServerConfig& debugServerConfig, - EventListener& eventListener + EventListener& eventListener, + EventFdNotifier& eventNotifier ); std::string getName() const override { diff --git a/src/DebugServer/Gdb/Connection.cpp b/src/DebugServer/Gdb/Connection.cpp index 97eeee5e..48bbba71 100644 --- a/src/DebugServer/Gdb/Connection.cpp +++ b/src/DebugServer/Gdb/Connection.cpp @@ -19,7 +19,7 @@ namespace Bloom::DebugServer::Gdb using ResponsePackets::ResponsePacket; - Connection::Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier) + Connection::Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier) : interruptEventNotifier(interruptEventNotifier) { this->accept(serverSocketFileDescriptor); diff --git a/src/DebugServer/Gdb/Connection.hpp b/src/DebugServer/Gdb/Connection.hpp index b986bcb0..b5a82535 100644 --- a/src/DebugServer/Gdb/Connection.hpp +++ b/src/DebugServer/Gdb/Connection.hpp @@ -9,7 +9,7 @@ #include #include -#include "src/Helpers/EventNotifier.hpp" +#include "src/Helpers/EventFdNotifier.hpp" #include "src/Helpers/EpollInstance.hpp" #include "src/DebugServer/Gdb/Packet.hpp" @@ -23,7 +23,7 @@ namespace Bloom::DebugServer::Gdb class Connection { public: - explicit Connection(int serverSocketFileDescriptor, EventNotifier& interruptEventNotifier); + explicit Connection(int serverSocketFileDescriptor, EventFdNotifier& interruptEventNotifier); Connection() = delete; Connection(const Connection&) = delete; @@ -77,8 +77,8 @@ namespace Bloom::DebugServer::Gdb int maxPacketSize = 1024; /** - * The interruptEventNotifier (instance of EventNotifier) allows us to interrupt blocking I/O calls on this - * connection's socket. Under the hood, the EventNotifier class is just an RAII wrapper for a Linux eventfd + * The interruptEventNotifier (instance of EventFdNotifier) allows us to interrupt blocking I/O calls on this + * connection's socket. Under the hood, the EventFdNotifier class is just an RAII wrapper for a Linux eventfd * object. * * The file descriptors of the eventfd object and the socket are both added to an EpollInstance (which is just @@ -86,9 +86,9 @@ namespace Bloom::DebugServer::Gdb * either of the two file descriptors. See any of the Connection I/O functions (e.g Connection::read()) for * more on this. * - * See the EventNotifier and EpollInstance classes for more. + * See the EventFdNotifier and EpollInstance classes for more. */ - EventNotifier& interruptEventNotifier; + EventFdNotifier& interruptEventNotifier; EpollInstance epollInstance = EpollInstance(); bool readInterruptEnabled = false; diff --git a/src/DebugServer/Gdb/GdbRspDebugServer.cpp b/src/DebugServer/Gdb/GdbRspDebugServer.cpp index 5f7ca91d..a82263d8 100644 --- a/src/DebugServer/Gdb/GdbRspDebugServer.cpp +++ b/src/DebugServer/Gdb/GdbRspDebugServer.cpp @@ -39,14 +39,13 @@ namespace Bloom::DebugServer::Gdb GdbRspDebugServer::GdbRspDebugServer( const DebugServerConfig& debugServerConfig, - EventListener& eventListener + EventListener& eventListener, + EventFdNotifier& eventNotifier ) : debugServerConfig(GdbDebugServerConfig(debugServerConfig)) , eventListener(eventListener) - , interruptEventNotifier(eventListener.getInterruptEventNotifier()) - { - assert(this->interruptEventNotifier != nullptr); - } + , interruptEventNotifier(eventNotifier) + {} void GdbRspDebugServer::init() { this->socketAddress.sin_family = AF_INET; @@ -102,7 +101,7 @@ namespace Bloom::DebugServer::Gdb ); this->epollInstance.addEntry( - this->interruptEventNotifier->getFileDescriptor(), + this->interruptEventNotifier.getFileDescriptor(), static_cast(EpollEvent::READ_READY) ); @@ -203,15 +202,15 @@ namespace Bloom::DebugServer::Gdb if ( !eventFileDescriptor.has_value() - || eventFileDescriptor.value() == this->interruptEventNotifier->getFileDescriptor() + || eventFileDescriptor.value() == this->interruptEventNotifier.getFileDescriptor() ) { - this->interruptEventNotifier->clear(); + this->interruptEventNotifier.clear(); return std::nullopt; } return std::make_optional( this->serverSocketFileDescriptor.value(), - *(this->interruptEventNotifier) + this->interruptEventNotifier ); } diff --git a/src/DebugServer/Gdb/GdbRspDebugServer.hpp b/src/DebugServer/Gdb/GdbRspDebugServer.hpp index f3a8d53d..70702ad8 100644 --- a/src/DebugServer/Gdb/GdbRspDebugServer.hpp +++ b/src/DebugServer/Gdb/GdbRspDebugServer.hpp @@ -12,6 +12,7 @@ #include "GdbDebugServerConfig.hpp" #include "src/EventManager/EventListener.hpp" #include "src/Helpers/EpollInstance.hpp" +#include "src/Helpers/EventFdNotifier.hpp" #include "src/TargetController/TargetControllerConsole.hpp" #include "Connection.hpp" @@ -41,7 +42,8 @@ namespace Bloom::DebugServer::Gdb public: explicit GdbRspDebugServer( const DebugServerConfig& debugServerConfig, - EventListener& eventListener + EventListener& eventListener, + EventFdNotifier& eventNotifier ); GdbRspDebugServer() = delete; @@ -86,24 +88,24 @@ namespace Bloom::DebugServer::Gdb EventListener& eventListener; /** - * EventNotifier object for interrupting blocking I/O operations. + * EventFdNotifier object for interrupting blocking I/O operations. * * Extracted from this->eventListener. * * See documentation in src/DebugServer/README.md for more. */ - EventNotifier* interruptEventNotifier = nullptr; + EventFdNotifier& interruptEventNotifier; /** * When waiting for a connection, we don't listen on the this->serverSocketFileDescriptor directly. Instead, * we use an EpollInstance to monitor both this->serverSocketFileDescriptor and this->interruptEventNotifier. - * This allows us to interrupt any blocking socket IO calls when EventNotifier::notify() is called on + * This allows us to interrupt any blocking socket IO calls when EventFdNotifier::notify() is called on * this->interruptEventNotifier. * * See GdbRspDebugServer::init() * See DebugServer::interruptEventNotifier * See EpollInstance - * See EventNotifier + * See EventFdNotifier */ EpollInstance epollInstance = EpollInstance(); diff --git a/src/DebugServer/README.md b/src/DebugServer/README.md index b9bb704d..9fc35d30 100644 --- a/src/DebugServer/README.md +++ b/src/DebugServer/README.md @@ -35,22 +35,23 @@ method to ensure that events are processed ASAP. See the relevant documentation --- Any blocking I/O employed by a server implementation can support event interrupts using an -[`EventNotifier`](../Helpers/EventNotifier.hpp) and [`EpollInstance`](../Helpers/EpollInstance.hpp). +[`EventFdNotifier`](../Helpers/EventFdNotifier.hpp) and [`EpollInstance`](../Helpers/EpollInstance.hpp). Key points: -- The `EventNotifier` class is an RAII wrapper for a Linux - [eventfd object](https://man7.org/linux/man-pages/man2/eventfd.2.html). An event can be recorded against the eventfd - object via a call to `EventNotifier::notify()`. -- The [`EventListener`](../EventManager/EventListener.hpp) class can accept an `EventNotifier` object via - `EventListener::setInterruptEventNotifier()`. If an `EventNotifier` has been set on an `EventListener`, the - `EventListener` will call `EventNotifer::notify()` everytime an event is registered for that listener. +- The `EventFdNotifier` class is an RAII wrapper for a Linux + [eventfd object](https://man7.org/linux/man-pages/man2/eventfd.2.html). It implements the + [`NotifierInterface`](../Helpers/NotifierInterface.hpp). An event can be recorded against the eventfd + object via a call to `EventFdNotifier::notify()`. +- The [`EventListener`](../EventManager/EventListener.hpp) class can accept an `NotifierInterface` object via + `EventListener::setInterruptEventNotifier()`. If a `NotifierInterface` has been set on an `EventListener`, the + `EventListener` will call `NotifierInterface::notify()` everytime an event is registered for that listener. - The `EpollInstance` class is an RAII wrapper for a Linux [epoll instance](https://man7.org/linux/man-pages/man7/epoll.7.html). It allows us to wait for any activity on a set of file descriptors. File descriptors can be added and removed from the epoll instance via `EpollInstance::addEntry()` and `EpollInstance::removeEntry()`. Calling `EpollInstance::waitForEvent()` will block until there is activity on at least one of the file descriptors, or a timeout has been reached. -With an `EventNotifer` and `EpollInstance`, one can perform a blocking I/O operation which can be interrupted by an +With an `EventFdNotifier` and `EpollInstance`, one can perform a blocking I/O operation which can be interrupted by an event. For an example of this, see the AVR GDB server implementation - it employs the method described above to allow the interruption of blocking I/O operations when an event is triggered. Specifically, [`GdbRspDebugServer::waitForConnection()`](./Gdb/GdbRspDebugServer.hpp) or diff --git a/src/EventManager/EventListener.hpp b/src/EventManager/EventListener.hpp index 94b1adb1..08ad74ae 100644 --- a/src/EventManager/EventListener.hpp +++ b/src/EventManager/EventListener.hpp @@ -15,7 +15,7 @@ #include "src/EventManager/Events/Events.hpp" #include "src/Helpers/SyncSafe.hpp" -#include "src/Helpers/EventNotifier.hpp" +#include "src/Helpers/NotifierInterface.hpp" namespace Bloom { @@ -92,11 +92,11 @@ namespace Bloom */ void registerEvent(Events::SharedGenericEventPointer event); - void setInterruptEventNotifier(EventNotifier* interruptEventNotifier) { + void setInterruptEventNotifier(NotifierInterface* interruptEventNotifier) { this->interruptEventNotifier = interruptEventNotifier; } - [[nodiscard]] EventNotifier* getInterruptEventNotifier() { + [[nodiscard]] NotifierInterface* getInterruptEventNotifier() { return this->interruptEventNotifier; } @@ -370,7 +370,7 @@ namespace Bloom SyncSafe>>> eventTypeToCallbacksMapping; SyncSafe> registeredEventTypes; - EventNotifier* interruptEventNotifier = nullptr; + NotifierInterface* interruptEventNotifier = nullptr; std::vector getEvents(); }; diff --git a/src/Helpers/EventNotifier.cpp b/src/Helpers/EventFdNotifier.cpp similarity index 73% rename from src/Helpers/EventNotifier.cpp rename to src/Helpers/EventFdNotifier.cpp index aebd67f1..2759302b 100644 --- a/src/Helpers/EventNotifier.cpp +++ b/src/Helpers/EventFdNotifier.cpp @@ -1,4 +1,4 @@ -#include "EventNotifier.hpp" +#include "EventFdNotifier.hpp" #include #include @@ -11,7 +11,7 @@ namespace Bloom { using Exceptions::Exception; - EventNotifier::EventNotifier() { + EventFdNotifier::EventFdNotifier() { this->fileDescriptor = ::eventfd(0, EFD_NONBLOCK); if (this->fileDescriptor < 0) { @@ -22,32 +22,32 @@ namespace Bloom } } - EventNotifier::EventNotifier(EventNotifier&& other) noexcept + EventFdNotifier::EventFdNotifier(EventFdNotifier&& other) noexcept : fileDescriptor(other.fileDescriptor) { other.fileDescriptor = std::nullopt; } - EventNotifier::~EventNotifier() noexcept { + EventFdNotifier::~EventFdNotifier() noexcept { this->close(); } - void EventNotifier::notify() { + void EventFdNotifier::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() { + void EventFdNotifier::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 - " + throw Exceptions::Exception("Failed to clear EventFdNotifier object - eventfd_read failed - " "error number: " + std::to_string(errno)); } } - void EventNotifier::close() { + void EventFdNotifier::close() { if (this->fileDescriptor.value_or(-1) >= 0) { ::close(this->fileDescriptor.value()); } diff --git a/src/Helpers/EventFdNotifier.hpp b/src/Helpers/EventFdNotifier.hpp new file mode 100644 index 00000000..684a76d7 --- /dev/null +++ b/src/Helpers/EventFdNotifier.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include "NotifierInterface.hpp" + +namespace Bloom +{ + /** + * The EventFdNotifier class is an RAII wrapper for a Linux eventfd object. + * + * It uses an eventfd object to implement the NotifierInterface. + */ + class EventFdNotifier: public NotifierInterface + { + public: + EventFdNotifier(); + + /* + * EventNotifier objects should not be copied. + */ + EventFdNotifier(EventFdNotifier& other) = delete; + EventFdNotifier& operator = (EventFdNotifier& other) = delete; + + /* + * TODO: Implement this. For now, use the move constructor. + */ + EventFdNotifier& operator = (EventFdNotifier&& other) = delete; + + EventFdNotifier(EventFdNotifier&& other) noexcept; + ~EventFdNotifier() noexcept override; + + [[nodiscard]] int getFileDescriptor() const { + return this->fileDescriptor.value(); + } + + void notify() override; + + void clear(); + + private: + std::optional fileDescriptor; + + void close(); + }; +} diff --git a/src/Helpers/EventNotifier.hpp b/src/Helpers/EventNotifier.hpp deleted file mode 100644 index d908b6b9..00000000 --- a/src/Helpers/EventNotifier.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include - -namespace Bloom -{ - /** - * 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. - */ - class EventNotifier - { - public: - EventNotifier(); - - /* - * 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(); - } - - void notify(); - - void clear(); - - private: - std::optional fileDescriptor; - - void close(); - }; -}