From 9e494452f10f3931ea3bc41df0fbdf445314945d Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 30 Dec 2019 14:04:19 -0800 Subject: [PATCH] Clean up triggers awaiting global state modification at shutdown Otherwise they can be reported as memory leaks since no more global state modifications will take place to notify the trigger to clean itself up. --- src/Notifier.cc | 11 +++++++++++ src/Notifier.h | 12 ++++++++++++ src/Trigger.cc | 21 +++++++++++++++++++++ src/Trigger.h | 4 ++++ src/main.cc | 1 + 5 files changed, 49 insertions(+) diff --git a/src/Notifier.cc b/src/Notifier.cc index 511eb33beb..265c574b2a 100644 --- a/src/Notifier.cc +++ b/src/Notifier.cc @@ -65,6 +65,17 @@ void notifier::Registry::Modified(Modifiable* m) i->second->Modified(m); } +void notifier::Registry::Terminate() + { + std::set receivers; + + for ( auto& r : registrations ) + receivers.emplace(r.second); + + for ( auto& r : receivers ) + r->Terminate(); + } + notifier::Modifiable::~Modifiable() { if ( num_receivers ) diff --git a/src/Notifier.h b/src/Notifier.h index 01ab3e3dc1..e85345fa81 100644 --- a/src/Notifier.h +++ b/src/Notifier.h @@ -30,6 +30,12 @@ public: * @param m object that was modified */ virtual void Modified(Modifiable* m) = 0; + + /** + * Callback executed when notification registry is terminating and + * no further modifications can possibly occur. + */ + virtual void Terminate() { } }; /** Singleton class tracking all notification requests globally. */ @@ -69,6 +75,12 @@ public: */ void Unregister(Modifiable* m); + /** + * Notifies all receivers that no further modifications will occur + * as the registry is shutting down. + */ + void Terminate(); + private: friend class Modifiable; diff --git a/src/Trigger.cc b/src/Trigger.cc index 5caffaa74d..3df2e9e43e 100644 --- a/src/Trigger.cc +++ b/src/Trigger.cc @@ -171,6 +171,27 @@ Trigger::Trigger(Expr* arg_cond, Stmt* arg_body, Stmt* arg_timeout_stmts, Unref(this); } +void Trigger::Terminate() + { + if ( is_return ) + { + auto parent = frame->GetTrigger(); + + if ( ! parent->Disabled() ) + { + // If the trigger was already disabled due to interpreter + // exception, an Unref already happened at that point. + parent->Disable(); + Unref(parent); + } + + frame->ClearTrigger(); + } + + Disable(); + Unref(this); + } + Trigger::~Trigger() { DBG_LOG(DBG_NOTIFIERS, "%s: deleting", Name()); diff --git a/src/Trigger.h b/src/Trigger.h index 59ba30b300..e9fcc087a2 100644 --- a/src/Trigger.h +++ b/src/Trigger.h @@ -62,6 +62,10 @@ public: // later to avoid race conditions. void Modified(notifier::Modifiable* m) override { QueueTrigger(this); } + // Overridden from notifer::Receiver. If we're still waiting + // on an ID/Val to be modified at termination time, we can't hope + // for any further progress to be made, so just Unref ourselves. + void Terminate() override; const char* Name() const; diff --git a/src/main.cc b/src/main.cc index 8a698f29e1..a3e7f37e9d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -343,6 +343,7 @@ void terminate_bro() mgr.Drain(); + notifier::registry.Terminate(); log_mgr->Terminate(); input_mgr->Terminate(); thread_mgr->Terminate();