mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
184 lines
4.5 KiB
C++
184 lines
4.5 KiB
C++
#pragma once
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include "zeek/ID.h"
|
|
#include "zeek/IntrusivePtr.h"
|
|
#include "zeek/Notifier.h"
|
|
#include "zeek/Obj.h"
|
|
#include "zeek/iosource/IOSource.h"
|
|
#include "zeek/util.h"
|
|
|
|
namespace zeek
|
|
{
|
|
|
|
class ODesc;
|
|
class Val;
|
|
|
|
using ValPtr = IntrusivePtr<Val>;
|
|
|
|
namespace detail
|
|
{
|
|
|
|
class Frame;
|
|
class Stmt;
|
|
class Expr;
|
|
class CallExpr;
|
|
class ID;
|
|
class WhenInfo;
|
|
|
|
using StmtPtr = IntrusivePtr<Stmt>;
|
|
|
|
namespace trigger
|
|
{
|
|
|
|
// Triggers are the heart of "when" statements: expressions that when
|
|
// they become true execute a body of statements.
|
|
|
|
class TriggerTimer;
|
|
class TriggerTraversalCallback;
|
|
|
|
class Trigger final : public Obj, public notifier::detail::Receiver
|
|
{
|
|
public:
|
|
// Don't access Trigger objects; they take care of themselves after
|
|
// instantiation. Note that if the condition is already true, the
|
|
// statements are executed immediately and the object is deleted
|
|
// right away.
|
|
|
|
Trigger(WhenInfo* wi, double timeout, const IDSet& globals, std::vector<ValPtr> local_aggrs,
|
|
Frame* f, const Location* loc);
|
|
|
|
~Trigger() override;
|
|
|
|
// Evaluates the condition. If true, executes the body and deletes
|
|
// the object deleted.
|
|
//
|
|
// Returns the state of condition.
|
|
bool Eval();
|
|
|
|
// Executes timeout code and deletes the object.
|
|
void Timeout();
|
|
|
|
// Return the timeout interval (negative if none was specified).
|
|
double TimeoutValue() const { return timeout_value; }
|
|
|
|
// Called if another entity needs to complete its operations first
|
|
// in any case before this trigger can proceed.
|
|
void Hold() { delayed = true; }
|
|
|
|
// Complement of Hold().
|
|
void Release() { delayed = false; }
|
|
|
|
// If we evaluate to true, our return value will be passed on
|
|
// to the given trigger. Note, automatically calls Hold().
|
|
void Attach(Trigger* trigger);
|
|
|
|
// Cache for return values of delayed function calls. Returns whether
|
|
// the trigger is queued for later evaluation -- it may not be queued
|
|
// if the Val is null or it's disabled. The cache is managed using
|
|
// void*'s so that the value can be associated with either a CallExpr
|
|
// (for interpreted execution) or a C++ function (for compiled-to-C++).
|
|
bool Cache(const void* obj, Val* val);
|
|
Val* Lookup(const void* obj);
|
|
|
|
// Disable this trigger completely. Needed because Unref'ing the trigger
|
|
// may not immediately delete it as other references may still exist.
|
|
void Disable();
|
|
|
|
bool Disabled() const { return disabled; }
|
|
|
|
void Describe(ODesc* d) const override;
|
|
|
|
// Overidden from Notifier. We queue the trigger and evaluate it
|
|
// later to avoid race conditions.
|
|
void Modified(zeek::notifier::detail::Modifiable* m) override;
|
|
|
|
// Overridden from notifier::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 { return name.c_str(); }
|
|
void SetName(const char* new_name) { name = new_name; }
|
|
|
|
private:
|
|
friend class TriggerTimer;
|
|
|
|
void ReInit(std::vector<ValPtr> index_expr_results);
|
|
|
|
void Register(const ID* id);
|
|
void Register(Val* val);
|
|
void UnregisterAll();
|
|
|
|
ExprPtr cond;
|
|
StmtPtr body;
|
|
StmtPtr timeout_stmts;
|
|
ExprPtr timeout;
|
|
double timeout_value;
|
|
Frame* frame;
|
|
bool is_return;
|
|
|
|
std::string name;
|
|
|
|
TriggerTimer* timer;
|
|
Trigger* attached;
|
|
|
|
bool delayed; // true if a function call is currently being delayed
|
|
bool disabled;
|
|
|
|
// Globals and locals present in the when expression.
|
|
IDSet globals;
|
|
IDSet locals; // not needed, present only for matching deprecated logic
|
|
|
|
// Tracks whether we've found the globals/locals, as the work only
|
|
// has to be done once.
|
|
bool have_trigger_elems = false;
|
|
|
|
// Aggregate values seen in locals used in the trigger condition,
|
|
// so we can detect changes in them that affect whether the condition
|
|
// holds.
|
|
std::vector<ValPtr> local_aggrs;
|
|
|
|
std::vector<std::pair<Obj*, notifier::detail::Modifiable*>> objs;
|
|
|
|
using ValCache = std::map<const void*, Val*>;
|
|
ValCache cache;
|
|
};
|
|
|
|
class Manager final : public iosource::IOSource
|
|
{
|
|
public:
|
|
Manager();
|
|
~Manager();
|
|
|
|
void InitPostScript();
|
|
|
|
double GetNextTimeout() override;
|
|
void Process() override;
|
|
const char* Tag() override { return "TriggerMgr"; }
|
|
|
|
void Queue(Trigger* trigger);
|
|
|
|
struct Stats
|
|
{
|
|
unsigned long total;
|
|
unsigned long pending;
|
|
};
|
|
|
|
void GetStats(Stats* stats);
|
|
|
|
private:
|
|
using TriggerList = std::list<Trigger*>;
|
|
TriggerList* pending;
|
|
unsigned long total_triggers = 0;
|
|
};
|
|
|
|
} // namespace trigger
|
|
|
|
extern trigger::Manager* trigger_mgr;
|
|
|
|
} // namespace detail
|
|
} // namespace zeek
|