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