From 6172f76ccd212fad43872fdeb9283186c9eb6a5a Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sun, 27 Dec 2015 11:56:21 +0000 Subject: [PATCH] Add an event listener interface to services. --- service-listener.h | 24 ++++++++++++++++++++++++ service.cc | 11 ++++++----- service.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 service-listener.h diff --git a/service-listener.h b/service-listener.h new file mode 100644 index 0000000..b443602 --- /dev/null +++ b/service-listener.h @@ -0,0 +1,24 @@ +#ifndef SERVICE_LISTENER_H +#define SERVICE_LISTENER_H + +class ServiceRecord; + +enum class ServiceEvent { + STARTED, // Service was started (reached STARTED state) + STOPPED, // Service was stopped (reached STOPPED state) + FAILEDSTART, // Service failed to start (possibly due to dependency failing) + STARTCANCELLED, // Service was set to be started but a stop was requested + STOPCANCELLED // Service was set to be stopped but a start was requested +}; + +// Interface for listening to services +class ServiceListener +{ + public: + + // An event occurred on the service being observed. + // Listeners must not be added or removed during event notification. + virtual void serviceEvent(ServiceRecord * service, ServiceEvent event) noexcept = 0; +}; + +#endif diff --git a/service.cc b/service.cc index dcda52d..5f0b3b4 100644 --- a/service.cc +++ b/service.cc @@ -62,8 +62,8 @@ void ServiceRecord::stopped() noexcept } service_set->service_inactive(this); + notifyListeners(ServiceEvent::STOPPED); - // TODO inform listeners. if (desired_state == ServiceState::STARTED) { // Desired state is "started". start(); @@ -126,8 +126,7 @@ void ServiceRecord::start(bool unpinned) noexcept && desired_state == ServiceState::STOPPED) { // This service was starting, or started, but was set to be stopped. // Cancel the stop (and continue starting/running). - // TODO any listeners waiting for stop should be notified of - // its cancellation + notifyListeners(ServiceEvent::STOPCANCELLED); } if (desired_state == ServiceState::STARTED && !unpinned) return; @@ -236,7 +235,7 @@ void ServiceRecord::started() { logServiceStarted(service_name); service_state = ServiceState::STARTED; - // TODO - inform listeners + notifyListeners(ServiceEvent::STARTED); if (onstart_flags.release_console) { log_to_console = false; @@ -271,6 +270,8 @@ void ServiceRecord::failed_to_start() service_state = ServiceState::STOPPED; desired_state = ServiceState::STOPPED; service_set->service_inactive(this); + notifyListeners(ServiceEvent::FAILEDSTART); + // failure to start // Cancel start of dependents: for (sr_iter i = dependents.begin(); i != dependents.end(); i++) { @@ -453,7 +454,7 @@ void ServiceRecord::stop(bool unpinned) noexcept && desired_state == ServiceState::STARTED) { // The service *was* stopped/stopping, but it was going to restart. // Now, we'll cancel the restart. - // TODO inform listeners waiting for start of cancellation + notifyListeners(ServiceEvent::STARTCANCELLED); } if (desired_state == ServiceState::STOPPED && !unpinned) return; diff --git a/service.h b/service.h index 1c8963f..202f01a 100644 --- a/service.h +++ b/service.h @@ -1,9 +1,14 @@ +#ifndef SERVICE_H +#define SERVICE_H + #include #include #include #include +#include #include "ev.h" #include "control.h" +#include "service-listener.h" /* * Possible service states @@ -157,6 +162,7 @@ static const char ** separate_args(std::string &s, std::list listeners; int term_signal = -1; // signal to use for process termination @@ -254,6 +262,14 @@ class ServiceRecord void forceStop() noexcept; // force-stop this service and all dependents + void notifyListeners(ServiceEvent event) + { + for (auto l : listeners) { + l->serviceEvent(this, event); + } + } + + public: ServiceRecord(ServiceSet *set, string name) @@ -331,6 +347,20 @@ class ServiceRecord { return service_type == ServiceType::DUMMY; } + + // Add a listener. A listener must only be added once. May throw std::bad_alloc. + void addListener(ServiceListener * listener) + { + listeners.insert(listener); + } + + // Remove a listener. + void removeListener(ServiceListener * listener) noexcept + { + listeners.erase(listener); + } + + // TODO notify listeners when service events occur }; @@ -430,3 +460,5 @@ class ServiceSet } } }; + +#endif -- 2.25.1