sessiond: agent: enable events matching event notifiers
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Tue, 11 Feb 2020 20:59:02 +0000 (15:59 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 4 Feb 2021 21:02:51 +0000 (16:02 -0500)
Per event notifier domain agents
--------------------------------

A `struct agent` instance encapsulates the agent events of an agent
domain for a given session. In the context of event notifiers, there is
no session involved to scope the agent instance.

Hence, per-domain instances are maintained to control event-notifiers
enabled by triggers.

Agent event enable count
------------------------

Agents act as a pre-filter on user space tracer events. In order to
honor triggers use event notifiers (on-event-hit conditions), the
register/unregister trigger commands are modified to ensure 'agent'
domain events are created and enabled/disabled suitably for the user
space tracer to be invoked.

Note that since agent events are a "filter" before event enablers, an
event-rule targetting a ring buffer and an identical event-rule
targetting an event notifier can be enabled. The action to take when the
event is hit is completely opaque to the agents. In such cases, the same
agent event instance needs to be enabled and the current implementation
doesn't allow duplicate agent events.

Hence, `struct agent_event`'s enabled state is now a counter which
accounts for all enabled event-rules that require this agent event to be
enabled. The agent event is enabled when one or more event rules
matching it are enabled and it is disabled when that count reached zero.

To ensure no code checks for the agent_event's enabled state by
comparing to '1', a new `AGENT_EVENT_IS_ENABLED` macro is introduced.
The existing code using the `enabled` attribute directly is modified to
use it.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I363db1e4bd7d7d73c75b8576c6323ee41e31aa00
Depends-on: lttng-ust: I5a800fc92e588c2a6a0e26282b0ad5f31c044479

16 files changed:
include/lttng/event-rule/event-rule-internal.h
src/bin/lttng-sessiond/agent-thread.c
src/bin/lttng-sessiond/agent.c
src/bin/lttng-sessiond/agent.h
src/bin/lttng-sessiond/client.c
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/event.c
src/bin/lttng-sessiond/event.h
src/bin/lttng-sessiond/globals.c
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/save.c
src/bin/lttng-sessiond/ust-app.c
src/bin/lttng-sessiond/utils.c
src/bin/lttng-sessiond/utils.h
src/common/event-rule/event-rule.c
src/common/event-rule/tracepoint.c

index 31465c7694dc13b701bf3cdf45e3e3d170e0b629..a8ad34fe897728731fd9bb4b0d468bbb90a4292e 100644 (file)
@@ -12,6 +12,7 @@
 #include <common/credentials.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <lttng/domain.h>
+#include <lttng/event.h>
 #include <lttng/event-rule/event-rule.h>
 #include <lttng/lttng-error.h>
 #include <stdbool.h>
@@ -54,6 +55,8 @@ typedef enum lttng_event_rule_generate_exclusions_status (
                struct lttng_event_exclusion **exclusions);
 typedef unsigned long (*event_rule_hash_cb)(
                const struct lttng_event_rule *event_rule);
+typedef struct lttng_event *(*event_rule_generate_lttng_event_cb)(
+               const struct lttng_event_rule *event_rule);
 
 struct lttng_event_rule {
        struct urcu_ref ref;
@@ -67,6 +70,7 @@ struct lttng_event_rule {
        event_rule_get_filter_bytecode_cb get_filter_bytecode;
        event_rule_generate_exclusions_cb generate_exclusions;
        event_rule_hash_cb hash;
+       event_rule_generate_lttng_event_cb generate_lttng_event;
 };
 
 struct lttng_event_rule_comm {
@@ -140,4 +144,21 @@ const char *lttng_event_rule_type_str(enum lttng_event_rule_type type);
 LTTNG_HIDDEN
 unsigned long lttng_event_rule_hash(const struct lttng_event_rule *rule);
 
+/*
+ * This is a compatibility helper allowing us to generate a sessiond-side (not
+ * communication) `struct lttng_event` object from an event rule.
+ *
+ * This effectively bridges older parts of the code using those structures and
+ * new event-rule based code.
+ *
+ * The caller owns the returned object.
+ */
+LTTNG_HIDDEN
+struct lttng_event *lttng_event_rule_generate_lttng_event(
+               const struct lttng_event_rule *rule);
+
+/* Test if an event rule targets an agent domain. */
+LTTNG_HIDDEN
+bool lttng_event_rule_targets_agent_domain(const struct lttng_event_rule *rule);
+
 #endif /* LTTNG_EVENT_RULE_INTERNAL_H */
index 06ef377a3a181c1b7528df89b076340f789c0f70..2015498ff59a178bf76e26eb5d092e1e3a748e87 100644 (file)
@@ -59,6 +59,8 @@ static void update_agent_app(const struct agent_app *app)
 {
        struct ltt_session *session, *stmp;
        struct ltt_session_list *list;
+       struct agent *trigger_agent;
+       struct lttng_ht_iter iter;
 
        list = session_get_list();
        assert(list);
@@ -82,6 +84,17 @@ static void update_agent_app(const struct agent_app *app)
                session_unlock(session);
                session_put(session);
        }
+
+       rcu_read_lock();
+       /*
+        * We are protected against the addition of new events by the session
+        * list lock being held.
+        */
+       cds_lfht_for_each_entry (trigger_agents_ht_by_domain->ht, &iter.iter,
+                       trigger_agent, node.node) {
+               agent_update(trigger_agent, app);
+       }
+       rcu_read_unlock();
 }
 
 /*
index e5978be5cef3ac24ecc7b7255cff563f87b13580..84728b7829cd5adbebed1ae0788dd74eb81f3b9a 100644 (file)
 #include <urcu/uatomic.h>
 #include <urcu/rculist.h>
 
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/event-rule/tracepoint.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/domain-internal.h>
+
 #include <common/common.h>
 #include <common/sessiond-comm/agent.h>
 
@@ -101,7 +108,8 @@ no_match:
 }
 
 /*
- * Match function for the events hash table lookup by name and loglevel.
+ * Match function for the events hash table lookup by name, log level and
+ * filter expression.
  */
 static int ht_match_event(struct cds_lfht_node *node,
                const void *_key)
@@ -681,7 +689,7 @@ int agent_enable_event(struct agent_event *event,
                }
        }
 
-       event->enabled = 1;
+       event->enabled_count++;
        ret = LTTNG_OK;
 
 error:
@@ -787,7 +795,17 @@ int agent_disable_event(struct agent_event *event,
        struct lttng_ht_iter iter;
 
        assert(event);
-       if (!event->enabled) {
+       if (!AGENT_EVENT_IS_ENABLED(event)) {
+               goto end;
+       }
+
+       if (--event->enabled_count != 0) {
+               /*
+                * Agent event still enabled. Disable the agent event only when
+                * all "users" have disabled it (event notifiers, event rules,
+                * etc.).
+                */
+               ret = LTTNG_OK;
                goto end;
        }
 
@@ -806,7 +824,8 @@ int agent_disable_event(struct agent_event *event,
                }
        }
 
-       event->enabled = 0;
+       /* event->enabled_count is now 0. */
+       assert(!AGENT_EVENT_IS_ENABLED(event));
 
 error:
        rcu_read_unlock();
@@ -1206,6 +1225,67 @@ void agent_find_events_by_name(const char *name, struct agent *agt,
                        ht_match_event_by_name, &key, &iter->iter);
 }
 
+/*
+ * Find the agent event matching a trigger.
+ *
+ * RCU read side lock MUST be acquired. It must be held for as long as
+ * the returned agent_event is used.
+ *
+ * Return object if found else NULL.
+ */
+struct agent_event *agent_find_event_by_trigger(
+               const struct lttng_trigger *trigger, struct agent *agt)
+{
+       enum lttng_condition_status c_status;
+       enum lttng_event_rule_status er_status;
+       enum lttng_domain_type domain;
+       const struct lttng_condition *condition;
+       const struct lttng_event_rule *rule;
+       const char *name;
+       const char *filter_expression;
+       /* Unused when loglevel_type is 'ALL'. */
+       int loglevel_value = 0;
+       enum lttng_loglevel_type loglevel_type;
+
+       assert(agt);
+       assert(agt->events);
+
+       condition = lttng_trigger_get_const_condition(trigger);
+
+       assert(lttng_condition_get_type(condition) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+
+       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       assert(c_status == LTTNG_CONDITION_STATUS_OK);
+
+       assert(lttng_event_rule_get_type(rule) ==
+                       LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+       domain = lttng_event_rule_get_domain_type(rule);
+       assert(domain == LTTNG_DOMAIN_JUL || domain == LTTNG_DOMAIN_LOG4J ||
+                       domain == LTTNG_DOMAIN_PYTHON);
+
+       /* Get the event's pattern ('name' in the legacy terminology). */
+       er_status = lttng_event_rule_tracepoint_get_pattern(rule, &name);
+       assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       /* Get the internal filter expression. */
+       filter_expression = lttng_event_rule_get_filter(rule);
+
+       er_status = lttng_event_rule_tracepoint_get_log_level_type(
+                       rule, &loglevel_type);
+       assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+               er_status = lttng_event_rule_tracepoint_get_log_level(
+                               rule, &loglevel_value);
+               assert(er_status == LTTNG_EVENT_RULE_STATUS_OK);
+       }
+
+       return agent_find_event(name, loglevel_type, loglevel_value,
+                       filter_expression, agt);
+}
+
 /*
  * Get the next agent event duplicate by name. This should be called
  * after a call to agent_find_events_by_name() to iterate on events.
@@ -1233,8 +1313,10 @@ void agent_event_next_duplicate(const char *name,
  * Return object if found else NULL.
  */
 struct agent_event *agent_find_event(const char *name,
-               enum lttng_loglevel_type loglevel_type, int loglevel_value,
-               char *filter_expression, struct agent *agt)
+               enum lttng_loglevel_type loglevel_type,
+               int loglevel_value,
+               const char *filter_expression,
+               struct agent *agt)
 {
        struct lttng_ht_node_str *node;
        struct lttng_ht_iter iter;
@@ -1337,14 +1419,8 @@ void agent_destroy(struct agent *agt)
  */
 int agent_app_ht_alloc(void)
 {
-       int ret = 0;
-
        agent_apps_ht_by_sock = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
-       if (!agent_apps_ht_by_sock) {
-               ret = -1;
-       }
-
-       return ret;
+       return agent_apps_ht_by_sock ? 0 : -1;
 }
 
 /*
@@ -1422,7 +1498,7 @@ void agent_update(const struct agent *agt, const struct agent_app *app)
 
        cds_lfht_for_each_entry(agt->events->ht, &iter.iter, event, node.node) {
                /* Skip event if disabled. */
-               if (!event->enabled) {
+               if (!AGENT_EVENT_IS_ENABLED(event)) {
                        continue;
                }
 
@@ -1447,3 +1523,66 @@ void agent_update(const struct agent *agt, const struct agent_app *app)
 
        rcu_read_unlock();
 }
+
+/*
+ * Allocate the per-event notifier domain agent hash table. It is lazily
+ * populated as domains are used.
+ */
+int agent_by_event_notifier_domain_ht_create(void)
+{
+       trigger_agents_ht_by_domain = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
+       return trigger_agents_ht_by_domain ? 0 : -1;
+}
+
+/*
+ * Clean-up the per-event notifier domain agent hash table and destroy it.
+ */
+void agent_by_event_notifier_domain_ht_destroy(void)
+{
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+
+       if (!trigger_agents_ht_by_domain) {
+               return;
+       }
+
+       rcu_read_lock();
+       cds_lfht_for_each_entry (trigger_agents_ht_by_domain->ht, &iter.iter,
+                       node, node) {
+               struct agent *agent =
+                               caa_container_of(node, struct agent, node);
+               const int ret = lttng_ht_del(
+                               trigger_agents_ht_by_domain, &iter);
+
+               assert(ret == 0);
+               agent_destroy(agent);
+       }
+
+       rcu_read_unlock();
+       lttng_ht_destroy(trigger_agents_ht_by_domain);
+}
+
+struct agent *agent_find_by_event_notifier_domain(
+               enum lttng_domain_type domain_type)
+{
+       struct agent *agt = NULL;
+       struct lttng_ht_node_u64 *node;
+       struct lttng_ht_iter iter;
+       const uint64_t key = (uint64_t) domain_type;
+
+       assert(trigger_agents_ht_by_domain);
+
+       DBG3("Per-event notifier domain agent lookup for domain '%s'",
+                       lttng_domain_type_str(domain_type));
+
+       lttng_ht_lookup(trigger_agents_ht_by_domain, &key, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
+       if (!node) {
+               goto end;
+       }
+
+       agt = caa_container_of(node, struct agent, node);
+
+end:
+       return agt;
+}
index f8e67efdae82b7130e951d721859841991fa2e76..e82f32627937c162b26464ac1024815750b7e0f3 100644 (file)
  */
 extern struct lttng_ht *agent_apps_ht_by_sock;
 
+/*
+ * Hash table that contains the trigger agents by domain */
+extern struct lttng_ht *trigger_agents_ht_by_domain;
+
 struct agent_ht_key {
        const char *name;
        int loglevel_value;
        enum lttng_loglevel_type loglevel_type;
-       char *filter_expression;
+       const char *filter_expression;
 };
 
 /*
@@ -68,6 +72,7 @@ struct agent_app {
 
 /*
  * Agent event representation.
+ * Accesses to this structure are protected by the session list lock.
  */
 struct agent_event {
        /* Name of the event. */
@@ -76,9 +81,18 @@ struct agent_event {
        enum lttng_loglevel_type loglevel_type;
 
        /*
-        * Tells if the event is enabled or not on the agent.
+        * Tells if the event is enabled or not on the agent. While this can be
+        * implicitly tested as a boolean, it is in fact a reference count and
+        * the AGENT_EVENT_IS_ENABLED macro should be used to prevent accidental
+        * comparisons to non-zero literals (e.g. '1').
+        *
+        * Multiple triggers and events can map to the same agent event as it
+        * is merely a "filter" in front of a user space tracer enabler.
+        *
+        * This count is updated to ensure an event is only disabled when all
+        * matching enablers are disabled.
         */
-       unsigned int enabled:1;
+       unsigned int enabled_count;
 
        /* Hash table node of the agent domain object. */
        struct lttng_ht_node_str node;
@@ -89,8 +103,12 @@ struct agent_event {
        struct lttng_event_exclusion *exclusion;
 };
 
+#define AGENT_EVENT_IS_ENABLED(agent_event) (!!agent_event->enabled_count)
+
 /*
- * Agent object containing events enabled/disabled for it.
+ * Agent object containing events enabled/disabled for a given domain in a
+ * scope. The scope is typically a session, but can also be "global" in the
+ * context of event notifiers: see event_notifiers_find_agent().
  */
 struct agent {
        /*
@@ -133,8 +151,10 @@ struct agent_event *agent_create_event(const char *name,
 void agent_add_event(struct agent_event *event, struct agent *agt);
 
 struct agent_event *agent_find_event(const char *name,
-               enum lttng_loglevel_type loglevel_type, int loglevel_value,
-               char *filter_expression, struct agent *agt);
+               enum lttng_loglevel_type loglevel_type,
+               int loglevel_value,
+               const char *filter_expression,
+               struct agent *agt);
 void agent_find_events_by_name(const char *name, struct agent *agt,
                struct lttng_ht_iter* iter);
 void agent_event_next_duplicate(const char *name,
@@ -167,4 +187,13 @@ void agent_update(const struct agent *agt, const struct agent_app *app);
 int agent_list_events(struct lttng_event **events,
                enum lttng_domain_type domain);
 
+struct agent_event *agent_find_event_by_trigger(
+               const struct lttng_trigger *trigger, struct agent *agt);
+
+/* Global event notifier per-domain agents. */
+struct agent *agent_find_by_event_notifier_domain(
+               enum lttng_domain_type domain_type);
+void agent_by_event_notifier_domain_ht_destroy(void);
+int agent_by_event_notifier_domain_ht_create(void);
+
 #endif /* LTTNG_SESSIOND_AGENT_H */
index 9e4d446aec60359c0311856339ddebb349d17bd5..09e683a712d8b41914f9938d306b65b506c74635 100644 (file)
@@ -43,6 +43,7 @@
 #include "utils.h"
 #include "manage-consumer.h"
 #include "clear.h"
+#include "agent-thread.h"
 
 static bool is_root;
 
@@ -1078,6 +1079,11 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock,
        case LTTNG_DOMAIN_JUL:
        case LTTNG_DOMAIN_LOG4J:
        case LTTNG_DOMAIN_PYTHON:
+               if (!agent_tracing_is_enabled()) {
+                       ret = LTTNG_ERR_AGENT_TRACING_DISABLED;
+                       goto error;
+               }
+               /* Fallthrough */
        case LTTNG_DOMAIN_UST:
        {
                if (!ust_app_supported()) {
index 2ba825da006cae03d2bb5a8ab396d4642843f5df..d8b0637534aec9d4f99dab23a6742b2cdb1a2c93 100644 (file)
@@ -488,7 +488,7 @@ static int list_lttng_agent_events(struct agent *agt,
        cds_lfht_for_each_entry (
                        agt->events->ht, &iter.iter, agent_event, node.node) {
                struct lttng_event event = {
-                       .enabled = agent_event->enabled,
+                       .enabled = AGENT_EVENT_IS_ENABLED(agent_event),
                        .loglevel = agent_event->loglevel_value,
                        .loglevel_type = agent_event->loglevel_type,
                };
@@ -4377,7 +4377,7 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
        if (ret_code != LTTNG_OK) {
                DBG("Failed to register trigger to notification thread: trigger name = '%s', trigger owner uid = %d, error code = %d",
                                trigger_name, (int) trigger_owner, ret_code);
-               goto end_notification_thread;
+               goto end;
        }
 
        trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
@@ -4388,16 +4388,19 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
        if (ret_code != LTTNG_OK) {
                ERR("Failed to determine if event modifies event notifiers: trigger name = '%s', trigger owner uid = %d, error code = %d",
                                trigger_name, (int) trigger_owner, ret_code);
-               goto end_notification_thread;
+               goto end;
        }
 
        /*
         * Synchronize tracers if the trigger adds an event notifier.
         */
        if (must_update_event_notifier) {
-               if (lttng_trigger_get_underlying_domain_type_restriction(
-                                   trigger) == LTTNG_DOMAIN_KERNEL) {
+               const enum lttng_domain_type trigger_domain =
+                               lttng_trigger_get_underlying_domain_type_restriction(trigger);
 
+               switch (trigger_domain) {
+               case LTTNG_DOMAIN_KERNEL:
+               {
                        ret_code = kernel_register_event_notifier(
                                        trigger, cmd_creds);
                        if (ret_code != LTTNG_OK) {
@@ -4413,11 +4416,36 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
                                                        (int) trigger_owner,
                                                        ret_code);
                                }
+                       }
+                       break;
+               }
+               case LTTNG_DOMAIN_UST:
+                       ust_app_global_update_all_event_notifier_rules();
+                       break;
+               case LTTNG_DOMAIN_NONE:
+                       abort();
+               default:
+               {
+                       /* Agent domains. */
+                       struct agent *agt = agent_find_by_event_notifier_domain(
+                                       trigger_domain);
+
+                       if (!agt) {
+                               agt = agent_create(trigger_domain);
+                               if (!agt) {
+                                       ret_code = LTTNG_ERR_NOMEM;
+                                       goto end;
+                               }
+                               agent_add(agt, trigger_agents_ht_by_domain);
+                       }
 
+                       ret_code = trigger_agent_enable(trigger, agt);
+                       if (ret_code != LTTNG_OK) {
                                goto end;
                        }
-               } else {
-                       ust_app_global_update_all_event_notifier_rules();
+
+                       break;
+               }
                }
        }
 
@@ -4430,9 +4458,7 @@ enum lttng_error_code cmd_register_trigger(const struct lttng_credentials *cmd_c
         */
        lttng_trigger_get(trigger);
        *return_trigger = trigger;
-
-end_notification_thread:
-       /* Ownership of trigger was transferred. */
+       /* Ownership of trigger was transferred to caller. */
        trigger = NULL;
 end:
        return ret_code;
@@ -4491,15 +4517,49 @@ enum lttng_error_code cmd_unregister_trigger(const struct lttng_credentials *cmd
 
        /*
         * Synchronize tracers if the trigger removes an event notifier.
+        * Do this even if the trigger unregistration failed to at least stop
+        * the tracers from producing notifications associated with this
+        * event notifier.
         */
        if (must_update_event_notifier) {
-               if (lttng_trigger_get_underlying_domain_type_restriction(
-                                   trigger) == LTTNG_DOMAIN_KERNEL) {
+               const enum lttng_domain_type trigger_domain =
+                               lttng_trigger_get_underlying_domain_type_restriction(
+                                               trigger);
 
+               switch (trigger_domain) {
+               case LTTNG_DOMAIN_KERNEL:
+               {
                        ret_code = kernel_unregister_event_notifier(
                                        trigger);
-               } else {
+                       break;
+               }
+               case LTTNG_DOMAIN_UST:
                        ust_app_global_update_all_event_notifier_rules();
+                       break;
+               case LTTNG_DOMAIN_NONE:
+                       abort();
+               default:
+               {
+                       /* Agent domains. */
+                       struct agent *agt = agent_find_by_event_notifier_domain(
+                                       trigger_domain);
+
+                       if (!agt) {
+                               agt = agent_create(trigger_domain);
+                               if (!agt) {
+                                       ret_code = LTTNG_ERR_NOMEM;
+                                       goto end;
+                               }
+                               agent_add(agt, trigger_agents_ht_by_domain);
+                       }
+
+                       ret_code = trigger_agent_disable(trigger, agt);
+                       if (ret_code != LTTNG_OK) {
+                               goto end;
+                       }
+
+                       break;
+               }
                }
        }
 
index d8abc60f5eeb0008ffdfbb87ecaf275c6e06edfe..40eb2656098b7d0b3ab69a9dd1219b0d5beadf7b 100644 (file)
 
 #include <common/compat/errno.h>
 #include <lttng/lttng.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/event-rule/event-rule.h>
+#include <lttng/event-rule/event-rule-internal.h>
 #include <common/error.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 #include <common/filter.h>
@@ -27,6 +31,7 @@
 #include "trace-kernel.h"
 #include "trace-ust.h"
 #include "agent.h"
+#include "utils.h"
 
 /*
  * Add unique UST event based on the event name, filter bytecode and loglevel.
@@ -366,6 +371,20 @@ error:
        return ret;
 }
 
+static void agent_enable_all(struct agent *agt)
+{
+       struct agent_event *aevent;
+       struct lttng_ht_iter iter;
+
+       /* Flag every event as enabled. */
+       rcu_read_lock();
+       cds_lfht_for_each_entry (
+                       agt->events->ht, &iter.iter, aevent, node.node) {
+               aevent->enabled_count++;
+       }
+       rcu_read_unlock();
+}
+
 /*
  * Enable all agent event for a given UST session.
  *
@@ -376,8 +395,6 @@ int event_agent_enable_all(struct ltt_ust_session *usess,
                struct lttng_filter_bytecode *filter ,char *filter_expression)
 {
        int ret;
-       struct agent_event *aevent;
-       struct lttng_ht_iter iter;
 
        assert(usess);
 
@@ -389,13 +406,7 @@ int event_agent_enable_all(struct ltt_ust_session *usess,
                goto error;
        }
 
-       /* Flag every event that they are now enabled. */
-       rcu_read_lock();
-       cds_lfht_for_each_entry(agt->events->ht, &iter.iter, aevent,
-                       node.node) {
-               aevent->enabled = 1;
-       }
-       rcu_read_unlock();
+       agent_enable_all(agt);
 
        ret = LTTNG_OK;
 
@@ -467,28 +478,17 @@ end:
        return ret;
 }
 
-/*
- * Enable a single agent event for a given UST session.
- *
- * Return LTTNG_OK on success or else a LTTNG_ERR* code.
- */
-int event_agent_enable(struct ltt_ust_session *usess,
-               struct agent *agt, struct lttng_event *event,
+static int agent_enable(struct agent *agt,
+               struct lttng_event *event,
                struct lttng_filter_bytecode *filter,
                char *filter_expression)
 {
        int ret, created = 0;
        struct agent_event *aevent;
 
-       assert(usess);
        assert(event);
        assert(agt);
 
-       DBG("Event agent enabling %s for session %" PRIu64 " with loglevel type %d "
-                       ", loglevel %d and filter \"%s\"", event->name,
-                       usess->id, event->loglevel_type, event->loglevel,
-                       filter_expression ? filter_expression : "NULL");
-
        aevent = agent_find_event(event->name, event->loglevel_type,
                        event->loglevel, filter_expression, agt);
        if (!aevent) {
@@ -502,7 +502,7 @@ int event_agent_enable(struct ltt_ust_session *usess,
                filter = NULL;
                filter_expression = NULL;
                created = 1;
-               assert(!aevent->enabled);
+               assert(!AGENT_EVENT_IS_ENABLED(aevent));
        }
 
        if (created && aevent->filter) {
@@ -514,7 +514,7 @@ int event_agent_enable(struct ltt_ust_session *usess,
        }
 
        /* Already enabled? */
-       if (aevent->enabled) {
+       if (AGENT_EVENT_IS_ENABLED(aevent)) {
                ret = LTTNG_OK;
                goto end;
        }
@@ -542,6 +542,119 @@ end:
        return ret;
 }
 
+/*
+ * Enable a single agent event for a given UST session.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int event_agent_enable(struct ltt_ust_session *usess,
+               struct agent *agt,
+               struct lttng_event *event,
+               struct lttng_filter_bytecode *filter,
+               char *filter_expression)
+{
+       assert(usess);
+       assert(event);
+       assert(agt);
+
+       DBG("Enabling agent event: event pattern = '%s', session id = %" PRIu64 ", loglevel type = %d, loglevel = %d, filter expression = '%s'",
+                       event->name, usess->id, event->loglevel_type,
+                       event->loglevel,
+                       filter_expression ? filter_expression : "(none)");
+
+       return agent_enable(agt, event, filter, filter_expression);
+}
+
+/*
+ * Enable a single agent event for a trigger.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int trigger_agent_enable(const struct lttng_trigger *trigger, struct agent *agt)
+{
+       int ret;
+       enum lttng_condition_status c_status;
+       enum lttng_trigger_status t_status;
+       enum lttng_domain_type d_type;
+       const struct lttng_condition *condition;
+       const struct lttng_event_rule *rule;
+       const char *filter_expression;
+       char *filter_expression_copy = NULL;
+       const struct lttng_filter_bytecode *filter_bytecode;
+       struct lttng_filter_bytecode *filter_bytecode_copy = NULL;
+       struct lttng_event *event = NULL;
+       uid_t trigger_owner_uid = 0;
+       const char *trigger_name;
+
+       assert(trigger);
+       assert(agt);
+
+       t_status = lttng_trigger_get_name(trigger, &trigger_name);
+       if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+               trigger_name = "(unnamed)";
+       }
+
+       t_status = lttng_trigger_get_owner_uid(trigger, &trigger_owner_uid);
+       assert(t_status == LTTNG_TRIGGER_STATUS_OK);
+
+       condition = lttng_trigger_get_const_condition(trigger);
+
+       assert(lttng_condition_get_type(condition) ==
+                       LTTNG_CONDITION_TYPE_EVENT_RULE_HIT);
+
+       c_status = lttng_condition_event_rule_get_rule(condition, &rule);
+       assert(c_status == LTTNG_CONDITION_STATUS_OK);
+
+       assert(lttng_event_rule_get_type(rule) ==
+                       LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+       d_type = lttng_event_rule_get_domain_type(rule);
+       assert(d_type == agt->domain);
+
+       event = lttng_event_rule_generate_lttng_event(rule);
+       if (!event) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Get the internal filter expression and bytecode. */
+       filter_expression = lttng_event_rule_get_filter(rule);
+       if (filter_expression) {
+               filter_expression_copy = strdup(filter_expression);
+               if (!filter_expression_copy) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Get the filter bytecode */
+               filter_bytecode = lttng_event_rule_get_filter_bytecode(rule);
+               if (filter_bytecode) {
+                       filter_bytecode_copy =
+                                       lttng_filter_bytecode_copy(filter_bytecode);
+                       if (!filter_bytecode_copy) {
+                               ret = LTTNG_ERR_NOMEM;
+                               goto end;
+                       }
+               }
+       }
+
+       DBG("Enabling agent event from trigger: trigger name = '%s', trigger owner uid = %d, token = %" PRIu64,
+                       trigger_name, trigger_owner_uid,
+                       lttng_trigger_get_tracer_token(trigger));
+
+       ret = agent_enable(agt, event, filter_bytecode_copy,
+                       filter_expression_copy);
+       /* Ownership was passed even in case of error. */
+       filter_expression_copy = NULL;
+       filter_bytecode_copy = NULL;
+
+end:
+       free(filter_expression_copy);
+       free(filter_bytecode_copy);
+       free(event);
+       return ret;
+}
+
 /*
  * Return the default event name associated with the provided UST domain. Return
  * NULL on error.
@@ -567,6 +680,43 @@ const char *event_get_default_agent_ust_name(enum lttng_domain_type domain)
        return default_event_name;
 }
 
+static int trigger_agent_disable_one(const struct lttng_trigger *trigger,
+               struct agent *agt,
+               struct agent_event *aevent)
+
+{
+       int ret;
+
+       assert(agt);
+       assert(trigger);
+       assert(aevent);
+
+       /*
+        * Actual ust event un-registration happens on the trigger
+        * un-registration at that point.
+        */
+
+       DBG("Event agent disabling %s (loglevel type %d, loglevel value %d) for trigger %" PRIu64,
+                       aevent->name, aevent->loglevel_type,
+                       aevent->loglevel_value, lttng_trigger_get_tracer_token(trigger));
+
+       /* Already disabled? */
+       if (!AGENT_EVENT_IS_ENABLED(aevent)) {
+               goto end;
+       }
+
+       ret = agent_disable_event(aevent, agt->domain);
+       if (ret != LTTNG_OK) {
+               goto error;
+       }
+
+end:
+       return LTTNG_OK;
+
+error:
+       return ret;
+}
+
 /*
  * Disable a given agent event for a given UST session.
  *
@@ -590,7 +740,7 @@ static int event_agent_disable_one(struct ltt_ust_session *usess,
                usess->id);
 
        /* Already disabled? */
-       if (!aevent->enabled) {
+       if (!AGENT_EVENT_IS_ENABLED(aevent)) {
                goto end;
        }
 
@@ -659,6 +809,44 @@ error:
        return ret;
 }
 
+/*
+ * Disable agent event matching a given trigger.
+ *
+ * Return LTTNG_OK on success or else a LTTNG_ERR* code.
+ */
+int trigger_agent_disable(
+               const struct lttng_trigger *trigger, struct agent *agt)
+{
+       int ret = LTTNG_OK;
+       struct agent_event *aevent;
+
+       assert(trigger);
+       assert(agt);
+
+       DBG("Event agent disabling for trigger %" PRIu64,
+                       lttng_trigger_get_tracer_token(trigger));
+
+       rcu_read_lock();
+       aevent = agent_find_event_by_trigger(trigger, agt);
+
+       if (aevent == NULL) {
+               DBG2("Event agent NOT found by trigger %" PRIu64,
+                               lttng_trigger_get_tracer_token(trigger));
+               ret = LTTNG_ERR_UST_EVENT_NOT_FOUND;
+               goto end;
+       }
+
+       ret = trigger_agent_disable_one(trigger, agt, aevent);
+
+       if (ret != LTTNG_OK) {
+               goto end;
+       }
+
+end:
+       rcu_read_unlock();
+       return ret;
+}
+
 /*
  * Disable all agent events matching a given name for a given UST session.
  *
@@ -732,7 +920,7 @@ int event_agent_disable_all(struct ltt_ust_session *usess,
        rcu_read_lock();
        cds_lfht_for_each_entry(agt->events->ht, &iter.iter, aevent,
                        node.node) {
-               if (!aevent->enabled) {
+               if (!AGENT_EVENT_IS_ENABLED(aevent)) {
                        continue;
                }
 
index 1c646db37b7d4d7956d1bc50303ed1032415ac3f..c7a849c0b3d46017d4660ed217a2fcd6e348eafb 100644 (file)
@@ -42,6 +42,11 @@ int event_agent_disable(struct ltt_ust_session *usess, struct agent *agt,
                const char *event_name);
 int event_agent_disable_all(struct ltt_ust_session *usess, struct agent *agt);
 
+int trigger_agent_enable(
+               const struct lttng_trigger *trigger, struct agent *agt);
+int trigger_agent_disable(
+               const struct lttng_trigger *trigger, struct agent *agt);
+
 const char *event_get_default_agent_ust_name(enum lttng_domain_type domain);
 
 #endif /* _LTT_EVENT_H */
index 20aa790a7540d4dcfd0adbb8897a7da81ff47582..85c1eec9035be74bb0b239b782a760dd27ad580f 100644 (file)
@@ -22,6 +22,7 @@ struct health_app *health_sessiond;
 struct notification_thread_handle *notification_thread_handle;
 
 struct lttng_ht *agent_apps_ht_by_sock = NULL;
+struct lttng_ht *trigger_agents_ht_by_domain = NULL;
 
 struct lttng_kernel_tracer_version kernel_tracer_version;
 struct lttng_kernel_tracer_abi_version kernel_tracer_abi_version;
index 9f8c9a332fea3fd28879324e86922af3e8c27edc..a344cd4769dbce11493828e2c1f6bbb367f255c3 100644 (file)
@@ -314,6 +314,9 @@ static void sessiond_cleanup(void)
 
        pthread_mutex_destroy(&session_list->lock);
 
+       DBG("Cleaning up all per-event notifier domain agents");
+       agent_by_event_notifier_domain_ht_destroy();
+
        DBG("Cleaning up all agent apps");
        agent_app_ht_clean();
        DBG("Closing all UST sockets");
@@ -1596,6 +1599,11 @@ int main(int argc, char **argv)
                goto stop_threads;
        }
 
+       if (agent_by_event_notifier_domain_ht_create()) {
+               ERR("Failed to allocate per-event notifier domain agent hash table");
+               retval = -1;
+               goto stop_threads;
+       }
        /*
         * These actions must be executed as root. We do that *after* setting up
         * the sockets path because we MUST make the check for another daemon using
index 052928c89e9298f60ddc12a03a16e8cd8584fe28..6ca756365de18f8177309c52e2d93301d6db651e 100644 (file)
@@ -1190,7 +1190,7 @@ int init_ust_event_from_agent_event(struct ltt_ust_event *ust_event,
        int ret;
        enum lttng_ust_loglevel_type ust_loglevel_type;
 
-       ust_event->enabled = agent_event->enabled;
+       ust_event->enabled = AGENT_EVENT_IS_ENABLED(agent_event);
        ust_event->attr.instrumentation = LTTNG_UST_TRACEPOINT;
        if (lttng_strncpy(ust_event->attr.name, agent_event->name,
                        LTTNG_SYMBOL_NAME_LEN)) {
index 5ab55ec29d3718b83a67135e3b6a155af8c74bfb..0f8664cc3c65fd29471c1ef78786ddde8ee0fca7 100644 (file)
@@ -41,6 +41,7 @@
 #include "lttng-sessiond.h"
 #include "notification-thread-commands.h"
 #include "rotate.h"
+#include "event.h"
 
 struct lttng_ht *ust_app_ht;
 struct lttng_ht *ust_app_ht_by_sock;
@@ -1316,29 +1317,6 @@ error:
        return NULL;
 }
 
-/*
- * Allocate a filter and copy the given original filter.
- *
- * Return allocated filter or NULL on error.
- */
-static struct lttng_filter_bytecode *copy_filter_bytecode(
-               struct lttng_filter_bytecode *orig_f)
-{
-       struct lttng_filter_bytecode *filter = NULL;
-
-       /* Copy filter bytecode */
-       filter = zmalloc(sizeof(*filter) + orig_f->len);
-       if (!filter) {
-               PERROR("zmalloc alloc filter bytecode");
-               goto error;
-       }
-
-       memcpy(filter, orig_f, sizeof(*filter) + orig_f->len);
-
-error:
-       return filter;
-}
-
 /*
  * Create a liblttng-ust filter bytecode from given bytecode.
  *
@@ -1944,43 +1922,57 @@ static int init_ust_event_notifier_from_event_rule(
 
        memset(event_notifier, 0, sizeof(*event_notifier));
 
-       status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               /* At this point, this is a fatal error. */
-               abort();
-       }
+       if (lttng_event_rule_targets_agent_domain(rule)) {
+               /*
+                * Special event for agents
+                * The actual meat of the event is in the filter that will be
+                * attached later on.
+                * Set the default values for the agent event.
+                */
+               pattern = event_get_default_agent_ust_name(
+                               lttng_event_rule_get_domain_type(rule));
+               loglevel = 0;
+               ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+       } else {
+               status = lttng_event_rule_tracepoint_get_pattern(
+                               rule, &pattern);
+               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       /* At this point, this is a fatal error. */
+                       abort();
+               }
 
-       status = lttng_event_rule_tracepoint_get_log_level_type(
-                       rule, &loglevel_type);
-       if (status != LTTNG_EVENT_RULE_STATUS_OK) {
-               /* At this point, this is a fatal error. */
-               abort();
-       }
+               status = lttng_event_rule_tracepoint_get_log_level_type(
+                               rule, &loglevel_type);
+               if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       /* At this point, this is a fatal error. */
+                       abort();
+               }
 
-       switch (loglevel_type) {
-       case LTTNG_EVENT_LOGLEVEL_ALL:
-               ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
-               break;
-       case LTTNG_EVENT_LOGLEVEL_RANGE:
-               ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
-               break;
-       case LTTNG_EVENT_LOGLEVEL_SINGLE:
-               ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
-               break;
-       default:
-               /* Unknown log level specification type. */
-               abort();
-       }
+               switch (loglevel_type) {
+               case LTTNG_EVENT_LOGLEVEL_ALL:
+                       ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+                       break;
+               case LTTNG_EVENT_LOGLEVEL_RANGE:
+                       ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
+                       break;
+               case LTTNG_EVENT_LOGLEVEL_SINGLE:
+                       ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
+                       break;
+               default:
+                       /* Unknown log level specification type. */
+                       abort();
+               }
 
-       if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
-               status = lttng_event_rule_tracepoint_get_log_level(
-                               rule, &loglevel);
-               assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+               if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+                       status = lttng_event_rule_tracepoint_get_log_level(
+                                       rule, &loglevel);
+                       assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+               }
        }
 
        event_notifier->event.instrumentation = LTTNG_UST_TRACEPOINT;
        ret = lttng_strncpy(event_notifier->event.name, pattern,
-                           LTTNG_UST_SYM_NAME_LEN - 1);
+                       LTTNG_UST_SYM_NAME_LEN - 1);
        if (ret) {
                ERR("Failed to copy event rule pattern to notifier: pattern = '%s' ",
                                pattern);
@@ -2119,7 +2111,7 @@ static void shadow_copy_event(struct ust_app_event *ua_event,
 
        /* Copy filter bytecode */
        if (uevent->filter) {
-               ua_event->filter = copy_filter_bytecode(uevent->filter);
+               ua_event->filter = lttng_filter_bytecode_copy(uevent->filter);
                /* Filter might be NULL here in case of ENONEM. */
        }
 
index f84859fc621645aea1939d7c04648c7ac729682a..febf2305826a5ce31c7033e111457aae5040618c 100644 (file)
@@ -98,3 +98,26 @@ const char *consumer_output_get_base_path(const struct consumer_output *output)
                        output->dst.session_root_path :
                        output->dst.net.base_dir;
 }
+
+/*
+ * Allocate a filter and copy the given original filter.
+ *
+ * Return allocated filter or NULL on error.
+ */
+struct lttng_filter_bytecode *lttng_filter_bytecode_copy(
+               const struct lttng_filter_bytecode *orig_f)
+{
+       struct lttng_filter_bytecode *filter = NULL;
+
+       /* Copy filter bytecode */
+       filter = zmalloc(sizeof(*filter) + orig_f->len);
+       if (!filter) {
+               PERROR("zmalloc alloc filter bytecode");
+               goto error;
+       }
+
+       memcpy(filter, orig_f, sizeof(*filter) + orig_f->len);
+
+error:
+       return filter;
+}
index ff8deaec45597b64ab88a366b1c7cec39a89ec4d..2492bb0f6f646a149490282f34a442e49116cac5 100644 (file)
@@ -19,5 +19,7 @@ int loglevels_match(int a_loglevel_type, int a_loglevel_value,
        int b_loglevel_type, int b_loglevel_value, int loglevel_all_type);
 const char *session_get_base_path(const struct ltt_session *session);
 const char *consumer_output_get_base_path(const struct consumer_output *output);
+struct lttng_filter_bytecode *lttng_filter_bytecode_copy(
+               const struct lttng_filter_bytecode *orig_f);
 
 #endif /* _LTT_UTILS_H */
index a37559c70608cf174a5401854031521e0a506409..98ff37411b90f45b6be1810da4af802c00cf8986 100644 (file)
@@ -276,6 +276,36 @@ lttng_event_rule_generate_exclusions(const struct lttng_event_rule *rule,
 }
 
 LTTNG_HIDDEN
+struct lttng_event *lttng_event_rule_generate_lttng_event(
+               const struct lttng_event_rule *rule)
+{
+       assert(rule->generate_lttng_event);
+       return rule->generate_lttng_event(rule);
+}
+
+LTTNG_HIDDEN
+bool lttng_event_rule_targets_agent_domain(const struct lttng_event_rule *rule)
+{
+       bool targets_agent_domain = false;
+       enum lttng_domain_type type = lttng_event_rule_get_domain_type(rule);
+
+       switch (type) {
+       case LTTNG_DOMAIN_JUL:
+       case LTTNG_DOMAIN_LOG4J:
+       case LTTNG_DOMAIN_PYTHON:
+               targets_agent_domain = true;
+               break;
+       case LTTNG_DOMAIN_UST:
+       case LTTNG_DOMAIN_KERNEL:
+               targets_agent_domain = false;
+               break;
+       default:
+               abort();
+       };
+
+       return targets_agent_domain;
+}
+
 const char *lttng_event_rule_type_str(enum lttng_event_rule_type type)
 {
        switch (type) {
index 6bdb754bc98f5f7917dbeb93bd59f0b10f8b663b..d6f3b9fb7b0b871b2c505cdf578daa60ebaff1aa 100644 (file)
@@ -16,6 +16,7 @@
 #include <common/hashtable/utils.h>
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/tracepoint-internal.h>
+#include <lttng/event.h>
 
 #define IS_TRACEPOINT_EVENT_RULE(rule) \
        (lttng_event_rule_get_type(rule) == LTTNG_EVENT_RULE_TYPE_TRACEPOINT)
@@ -599,6 +600,41 @@ static unsigned long lttng_event_rule_tracepoint_hash(
        return hash;
 }
 
+static struct lttng_event *lttng_event_rule_tracepoint_generate_lttng_event(
+               const struct lttng_event_rule *rule)
+{
+       int ret;
+       const struct lttng_event_rule_tracepoint *tracepoint;
+       struct lttng_event *local_event = NULL;
+       struct lttng_event *event = NULL;
+
+       tracepoint = container_of(
+                       rule, const struct lttng_event_rule_tracepoint, parent);
+
+       local_event = zmalloc(sizeof(*local_event));
+       if (!local_event) {
+               goto error;
+       }
+
+       local_event->type = LTTNG_EVENT_TRACEPOINT;
+       ret = lttng_strncpy(local_event->name, tracepoint->pattern,
+                           sizeof(local_event->name));
+       if (ret) {
+               ERR("Truncation occurred when copying event rule pattern to `lttng_event` structure: pattern = '%s'",
+                               tracepoint->pattern);
+               goto error;
+       }
+
+       local_event->loglevel_type = tracepoint->loglevel.type;
+       local_event->loglevel = tracepoint->loglevel.value;
+
+       event = local_event;
+       local_event = NULL;
+error:
+       free(local_event);
+       return event;
+}
+
 struct lttng_event_rule *lttng_event_rule_tracepoint_create(
                enum lttng_domain_type domain_type)
 {
@@ -629,6 +665,8 @@ struct lttng_event_rule *lttng_event_rule_tracepoint_create(
        tp_rule->parent.generate_exclusions =
                        lttng_event_rule_tracepoint_generate_exclusions;
        tp_rule->parent.hash = lttng_event_rule_tracepoint_hash;
+       tp_rule->parent.generate_lttng_event =
+                       lttng_event_rule_tracepoint_generate_lttng_event;
 
        tp_rule->domain = domain_type;
        tp_rule->loglevel.type = LTTNG_EVENT_LOGLEVEL_ALL;
This page took 0.066744 seconds and 4 git commands to generate.