mirror of
https://github.com/zeek/zeek.git
synced 2025-10-04 07:38:19 +00:00
Redo NotfifierRegistry to no longer rely on StateAccess.
We simplify the API to a simple Modified() operation.
This commit is contained in:
parent
c0c5dccd06
commit
02214dafc4
3 changed files with 80 additions and 70 deletions
|
@ -149,7 +149,7 @@ void StateAccess::Replay()
|
||||||
|
|
||||||
Val* v = target.id->ID_Val();
|
Val* v = target.id->ID_Val();
|
||||||
TypeTag t = v ? v->Type()->Tag() : TYPE_VOID;
|
TypeTag t = v ? v->Type()->Tag() : TYPE_VOID;
|
||||||
|
|
||||||
if ( opcode != OP_ASSIGN && ! v )
|
if ( opcode != OP_ASSIGN && ! v )
|
||||||
{
|
{
|
||||||
// FIXME: I think this warrants an internal error,
|
// FIXME: I think this warrants an internal error,
|
||||||
|
@ -514,22 +514,17 @@ void StateAccess::Describe(ODesc* d) const
|
||||||
|
|
||||||
void StateAccess::Log(StateAccess* access)
|
void StateAccess::Log(StateAccess* access)
|
||||||
{
|
{
|
||||||
bool tracked = false;
|
|
||||||
|
|
||||||
if ( access->target_type == TYPE_ID )
|
if ( access->target_type == TYPE_ID )
|
||||||
{
|
{
|
||||||
if ( access->target.id->FindAttr(ATTR_TRACKED) )
|
if ( access->target.id->FindAttr(ATTR_TRACKED) )
|
||||||
tracked = true;
|
notifiers.Modified(access->target.id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( access->target.val->GetProperties() & MutableVal::TRACKED )
|
if ( access->target.val->GetProperties() & MutableVal::TRACKED )
|
||||||
tracked = true;
|
notifiers.Modified(access->target.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( tracked )
|
|
||||||
notifiers.AccessPerformed(*access);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
ODesc desc;
|
ODesc desc;
|
||||||
access->Describe(&desc);
|
access->Describe(&desc);
|
||||||
|
@ -543,6 +538,15 @@ void StateAccess::Log(StateAccess* access)
|
||||||
|
|
||||||
NotifierRegistry notifiers;
|
NotifierRegistry notifiers;
|
||||||
|
|
||||||
|
NotifierRegistry::~NotifierRegistry()
|
||||||
|
{
|
||||||
|
for ( auto i : ids )
|
||||||
|
Unref(i.first);
|
||||||
|
|
||||||
|
for ( auto i : vals )
|
||||||
|
Unref(i.first);
|
||||||
|
}
|
||||||
|
|
||||||
void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier)
|
void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier)
|
||||||
{
|
{
|
||||||
DBG_LOG(DBG_NOTIFIERS, "registering ID %s for notifier %s",
|
DBG_LOG(DBG_NOTIFIERS, "registering ID %s for notifier %s",
|
||||||
|
@ -563,24 +567,20 @@ void NotifierRegistry::Register(ID* id, NotifierRegistry::Notifier* notifier)
|
||||||
|
|
||||||
Unref(attr);
|
Unref(attr);
|
||||||
|
|
||||||
NotifierMap::iterator i = ids.find(id->Name());
|
ids.insert({id, notifier});
|
||||||
|
|
||||||
if ( i != ids.end() )
|
|
||||||
i->second->insert(notifier);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NotifierSet* s = new NotifierSet;
|
|
||||||
s->insert(notifier);
|
|
||||||
ids.insert(NotifierMap::value_type(id->Name(), s));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref(id);
|
Ref(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifierRegistry::Register(Val* val, NotifierRegistry::Notifier* notifier)
|
void NotifierRegistry::Register(Val* val, NotifierRegistry::Notifier* notifier)
|
||||||
{
|
{
|
||||||
if ( val->IsMutableVal() )
|
if ( ! val->IsMutableVal() )
|
||||||
Register(val->AsMutableVal()->UniqueID(), notifier);
|
return;
|
||||||
|
|
||||||
|
DBG_LOG(DBG_NOTIFIERS, "registering value %p for notifier %s",
|
||||||
|
val, notifier->Name());
|
||||||
|
|
||||||
|
vals.insert({val, notifier});
|
||||||
|
Ref(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifierRegistry::Unregister(ID* id, NotifierRegistry::Notifier* notifier)
|
void NotifierRegistry::Unregister(ID* id, NotifierRegistry::Notifier* notifier)
|
||||||
|
@ -588,52 +588,55 @@ void NotifierRegistry::Unregister(ID* id, NotifierRegistry::Notifier* notifier)
|
||||||
DBG_LOG(DBG_NOTIFIERS, "unregistering ID %s for notifier %s",
|
DBG_LOG(DBG_NOTIFIERS, "unregistering ID %s for notifier %s",
|
||||||
id->Name(), notifier->Name());
|
id->Name(), notifier->Name());
|
||||||
|
|
||||||
NotifierMap::iterator i = ids.find(id->Name());
|
auto x = ids.equal_range(id);
|
||||||
|
for ( auto i = x.first; i != x.second; i++ )
|
||||||
if ( i == ids.end() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Attr* attr = id->Attrs()->FindAttr(ATTR_TRACKED);
|
|
||||||
id->Attrs()->RemoveAttr(ATTR_TRACKED);
|
|
||||||
Unref(attr);
|
|
||||||
|
|
||||||
NotifierSet* s = i->second;
|
|
||||||
s->erase(notifier);
|
|
||||||
|
|
||||||
if ( s->size() == 0 )
|
|
||||||
{
|
{
|
||||||
delete s;
|
if ( i->second == notifier )
|
||||||
ids.erase(i);
|
{
|
||||||
|
ids.erase(i);
|
||||||
|
Unref(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unref(id);
|
if ( ids.find(id) == ids.end() )
|
||||||
|
// Last registered notifier for this ID
|
||||||
|
id->Attrs()->RemoveAttr(ATTR_TRACKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifierRegistry::Unregister(Val* val, NotifierRegistry::Notifier* notifier)
|
void NotifierRegistry::Unregister(Val* val, NotifierRegistry::Notifier* notifier)
|
||||||
{
|
{
|
||||||
if ( val->IsMutableVal() )
|
DBG_LOG(DBG_NOTIFIERS, "unregistering Val %p for notifier %s",
|
||||||
Unregister(val->AsMutableVal()->UniqueID(), notifier);
|
val, notifier->Name());
|
||||||
|
|
||||||
|
auto x = vals.equal_range(val);
|
||||||
|
for ( auto i = x.first; i != x.second; i++ )
|
||||||
|
{
|
||||||
|
if ( i->second == notifier )
|
||||||
|
{
|
||||||
|
vals.erase(i);
|
||||||
|
Unref(val);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifierRegistry::AccessPerformed(const StateAccess& sa)
|
void NotifierRegistry::Modified(Val *val)
|
||||||
{
|
{
|
||||||
ID* id = sa.Target();
|
DBG_LOG(DBG_NOTIFIERS, "modification to tracked value %p", val);
|
||||||
|
|
||||||
NotifierMap::iterator i = ids.find(id->Name());
|
auto x = vals.equal_range(val);
|
||||||
|
for ( auto i = x.first; i != x.second; i++ )
|
||||||
if ( i == ids.end() )
|
i->second->Modified(val);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
void NotifierRegistry::Modified(ID *id)
|
||||||
|
{
|
||||||
DBG_LOG(DBG_NOTIFIERS, "modification to tracked ID %s", id->Name());
|
DBG_LOG(DBG_NOTIFIERS, "modification to tracked ID %s", id->Name());
|
||||||
|
|
||||||
NotifierSet* s = i->second;
|
auto x = ids.equal_range(id);
|
||||||
|
for ( auto i = x.first; i != x.second; i++ )
|
||||||
if ( id->IsInternalGlobal() )
|
i->second->Modified(id);
|
||||||
for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
|
|
||||||
(*j)->Access(id->ID_Val(), sa);
|
|
||||||
else
|
|
||||||
for ( NotifierSet::iterator j = s->begin(); j != s->end(); j++ )
|
|
||||||
(*j)->Access(id, sa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* NotifierRegistry::Notifier::Name() const
|
const char* NotifierRegistry::Notifier::Name() const
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#define STATEACESSS_H
|
#define STATEACESSS_H
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Val;
|
class Val;
|
||||||
|
@ -105,32 +105,39 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual ~Notifier() { }
|
virtual ~Notifier() { }
|
||||||
|
|
||||||
// Called when a change is being performed. Note that when these
|
// Called when a change is being performed. Note that when
|
||||||
// methods are called, it is undefined whether the change has
|
// these methods are called, it is undefined whether the
|
||||||
// already been done or is just going to be performed soon.
|
// change has already been done or is just going to be
|
||||||
virtual void Access(ID* id, const StateAccess& sa) = 0;
|
// performed soon.
|
||||||
virtual void Access(Val* val, const StateAccess& sa) = 0;
|
virtual void Modified(ID* id) = 0;
|
||||||
|
virtual void Modified(Val* val) = 0;
|
||||||
virtual const char* Name() const; // for debugging
|
virtual const char* Name() const; // for debugging
|
||||||
};
|
};
|
||||||
|
|
||||||
NotifierRegistry() { }
|
NotifierRegistry() { }
|
||||||
~NotifierRegistry() { }
|
~NotifierRegistry();
|
||||||
|
|
||||||
// Inform the given notifier if ID/Val changes.
|
// Register a new notifier to be informed when ID/Val changes. Note
|
||||||
|
// that the registry will store a reference to the target, keeping
|
||||||
|
// the instance alive for as long as it's registered.
|
||||||
void Register(ID* id, Notifier* notifier);
|
void Register(ID* id, Notifier* notifier);
|
||||||
void Register(Val* val, Notifier* notifier);
|
void Register(Val* val, Notifier* notifier);
|
||||||
|
|
||||||
// Cancel notification for this ID/Val.
|
// Cancel a notifier's tracking for this ID/Val, also releasing the
|
||||||
|
// referencee being held.
|
||||||
void Unregister(ID* id, Notifier* notifier);
|
void Unregister(ID* id, Notifier* notifier);
|
||||||
void Unregister(Val* val, Notifier* notifier);
|
void Unregister(Val* val, Notifier* notifier);
|
||||||
|
|
||||||
private:
|
// Inform all registered notifiiers of a modification to a value/ID.
|
||||||
friend class StateAccess;
|
void Modified(ID *id);
|
||||||
void AccessPerformed(const StateAccess& sa);
|
void Modified(Val *val);
|
||||||
|
|
||||||
typedef std::set<Notifier*> NotifierSet;
|
private:
|
||||||
typedef std::map<std::string, NotifierSet*> NotifierMap;
|
typedef std::unordered_multimap<Val*, Notifier*> ValMap;
|
||||||
NotifierMap ids;
|
typedef std::unordered_multimap<ID*, Notifier*> IDMap;
|
||||||
|
|
||||||
|
ValMap vals;
|
||||||
|
IDMap ids;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NotifierRegistry notifiers;
|
extern NotifierRegistry notifiers;
|
||||||
|
|
|
@ -61,9 +61,9 @@ public:
|
||||||
{ d->Add("<trigger>"); }
|
{ d->Add("<trigger>"); }
|
||||||
// Overidden from Notifier. We queue the trigger and evaluate it
|
// Overidden from Notifier. We queue the trigger and evaluate it
|
||||||
// later to avoid race conditions.
|
// later to avoid race conditions.
|
||||||
void Access(ID* id, const StateAccess& sa) override
|
void Modified(ID* id) override
|
||||||
{ QueueTrigger(this); }
|
{ QueueTrigger(this); }
|
||||||
void Access(Val* val, const StateAccess& sa) override
|
void Modified(Val* val) override
|
||||||
{ QueueTrigger(this); }
|
{ QueueTrigger(this); }
|
||||||
|
|
||||||
const char* Name() const override;
|
const char* Name() const override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue