trigger: lttng_trigger_get_underlying_domain_type_restriction
[lttng-tools.git] / src / common / trigger.c
index 785fce3fcf0271e66a3d11a2777905dba3bd04fc..132fda138912ef8ac264f6452f274614c1b19eca 100644 (file)
@@ -7,10 +7,14 @@
 
 #include <lttng/trigger/trigger-internal.h>
 #include <lttng/condition/condition-internal.h>
+#include <lttng/condition/event-rule.h>
+#include <lttng/condition/buffer-usage.h>
+#include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/action/action-internal.h>
 #include <common/credentials.h>
 #include <common/payload.h>
 #include <common/payload-view.h>
+#include <lttng/domain.h>
 #include <common/error.h>
 #include <common/dynamic-array.h>
 #include <common/optional.h>
@@ -55,6 +59,9 @@ struct lttng_trigger *lttng_trigger_create(
 
        urcu_ref_init(&trigger->ref);
 
+       trigger->firing_policy.type = LTTNG_TRIGGER_FIRING_POLICY_EVERY_N;
+       trigger->firing_policy.threshold = 1;
+
        lttng_condition_get(condition);
        trigger->condition = condition;
 
@@ -126,25 +133,45 @@ void lttng_trigger_destroy(struct lttng_trigger *trigger)
        lttng_trigger_put(trigger);
 }
 
+static bool is_firing_policy_valid(enum lttng_trigger_firing_policy policy)
+{
+       bool valid = false;
+
+       switch (policy) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               valid = true;
+               break;
+       default:
+               valid = false;
+               break;
+       }
+
+       return valid;
+}
+
 LTTNG_HIDDEN
 ssize_t lttng_trigger_create_from_payload(
                struct lttng_payload_view *src_view,
-               struct lttng_trigger **trigger)
+               struct lttng_trigger **_trigger)
 {
        ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
        struct lttng_condition *condition = NULL;
        struct lttng_action *action = NULL;
        const struct lttng_trigger_comm *trigger_comm;
        const char *name = NULL;
+       uint64_t firing_policy_threshold;
+       enum lttng_trigger_firing_policy firing_policy;
        struct lttng_credentials creds = {
                .uid = LTTNG_OPTIONAL_INIT_UNSET,
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
        };
+       struct lttng_trigger *trigger = NULL;
        const struct lttng_payload_view trigger_comm_view =
                        lttng_payload_view_from_view(
                                        src_view, 0, sizeof(*trigger_comm));
 
-       if (!src_view || !trigger) {
+       if (!src_view || !_trigger) {
                ret = -1;
                goto end;
        }
@@ -169,6 +196,13 @@ ssize_t lttng_trigger_create_from_payload(
 
        offset += sizeof(*trigger_comm);
 
+       firing_policy = trigger_comm->firing_policy_type;
+       if (!is_firing_policy_valid(firing_policy)) {
+               ret =-1;
+               goto end;
+       }
+
+       firing_policy_threshold = trigger_comm->firing_policy_threshold;
        if (trigger_comm->name_length != 0) {
                /* Name. */
                const struct lttng_payload_view name_view =
@@ -229,13 +263,13 @@ ssize_t lttng_trigger_create_from_payload(
                goto error;
        }
 
-       *trigger = lttng_trigger_create(condition, action);
-       if (!*trigger) {
+       trigger = lttng_trigger_create(condition, action);
+       if (!trigger) {
                ret = -1;
                goto error;
        }
 
-       lttng_trigger_set_credentials(*trigger, &creds);
+       lttng_trigger_set_credentials(trigger, &creds);
 
        /*
         * The trigger object owns references to the action and condition
@@ -249,7 +283,20 @@ ssize_t lttng_trigger_create_from_payload(
 
        if (name) {
                const enum lttng_trigger_status status =
-                               lttng_trigger_set_name(*trigger, name);
+                               lttng_trigger_set_name(trigger, name);
+
+               if (status != LTTNG_TRIGGER_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+       /* Set the policy. */
+       {
+               const enum lttng_trigger_status status =
+                               lttng_trigger_set_firing_policy(trigger,
+                                               firing_policy,
+                                               firing_policy_threshold);
 
                if (status != LTTNG_TRIGGER_STATUS_OK) {
                        ret = -1;
@@ -260,9 +307,15 @@ ssize_t lttng_trigger_create_from_payload(
        ret = offset;
 
 error:
-       lttng_condition_destroy(condition);
-       lttng_action_destroy(action);
+       lttng_condition_put(condition);
+       lttng_action_put(action);
 end:
+       if (ret >= 0) {
+               *_trigger = trigger;
+       } else {
+               lttng_trigger_put(trigger);
+       }
+
        return ret;
 }
 
@@ -292,6 +345,8 @@ int lttng_trigger_serialize(const struct lttng_trigger *trigger,
        }
 
        trigger_comm.name_length = size_name;
+       trigger_comm.firing_policy_type = (uint8_t) trigger->firing_policy.type;
+       trigger_comm.firing_policy_threshold = (uint64_t) trigger->firing_policy.threshold;
 
        header_offset = payload->buffer.size;
        ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
@@ -330,6 +385,14 @@ LTTNG_HIDDEN
 bool lttng_trigger_is_equal(
                const struct lttng_trigger *a, const struct lttng_trigger *b)
 {
+       if (a->firing_policy.type != b->firing_policy.type) {
+               return false;
+       }
+
+       if (a->firing_policy.threshold != b->firing_policy.threshold) {
+               return false;
+       }
+
        /*
         * Name is not taken into account since it is cosmetic only.
         */
@@ -731,3 +794,137 @@ enum lttng_trigger_status lttng_trigger_get_owner_uid(
 end:
        return ret;
 }
+
+enum lttng_trigger_status lttng_trigger_set_firing_policy(
+               struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy policy_type,
+               uint64_t threshold)
+{
+       enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
+       assert(trigger);
+
+       if (threshold < 1) {
+               ret = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       trigger->firing_policy.type = policy_type;
+       trigger->firing_policy.threshold = threshold;
+
+end:
+       return ret;
+}
+
+enum lttng_trigger_status lttng_trigger_get_firing_policy(
+               const struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy *policy_type,
+               uint64_t *threshold)
+{
+       enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
+
+       if (!trigger || !policy_type || !threshold) {
+               status = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       *policy_type = trigger->firing_policy.type;
+       *threshold = trigger->firing_policy.threshold;
+
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+bool lttng_trigger_should_fire(const struct lttng_trigger *trigger)
+{
+       bool ready_to_fire = false;
+
+       assert(trigger);
+
+       switch (trigger->firing_policy.type) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+               if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
+                       ready_to_fire = true;
+               }
+               break;
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
+                       ready_to_fire = true;
+               }
+               break;
+       default:
+               abort();
+       };
+
+       return ready_to_fire;
+}
+
+LTTNG_HIDDEN
+void lttng_trigger_fire(struct lttng_trigger *trigger)
+{
+       assert(trigger);
+
+       trigger->firing_policy.current_count++;
+
+       switch (trigger->firing_policy.type) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+               if (trigger->firing_policy.current_count == trigger->firing_policy.threshold) {
+                       trigger->firing_policy.current_count = 0;
+               }
+
+               break;
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               /*
+                * TODO:
+                * As an optimisation, deactivate the trigger condition and
+                * remove any checks in the traced application or kernel since
+                * the trigger will never fire again.
+                */
+               break;
+       default:
+               abort();
+       };
+}
+
+LTTNG_HIDDEN
+enum lttng_domain_type lttng_trigger_get_underlying_domain_type_restriction(
+               const struct lttng_trigger *trigger)
+{
+       enum lttng_domain_type type = LTTNG_DOMAIN_NONE;
+       const struct lttng_event_rule *event_rule;
+       enum lttng_condition_status c_status;
+       enum lttng_condition_type c_type;
+
+       assert(trigger);
+       assert(trigger->condition);
+
+       c_type = lttng_condition_get_type(trigger->condition);
+       assert (c_type != LTTNG_CONDITION_TYPE_UNKNOWN);
+
+       switch (c_type) {
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               /* Apply to any domain. */
+               type = LTTNG_DOMAIN_NONE;
+               break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
+               /* Return the domain of the event rule. */
+               c_status = lttng_condition_event_rule_get_rule(
+                               trigger->condition, &event_rule);
+               assert(c_status == LTTNG_CONDITION_STATUS_OK);
+               type = lttng_event_rule_get_domain_type(event_rule);
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+               /* Return the domain of the channel being monitored. */
+               c_status = lttng_condition_buffer_usage_get_domain_type(
+                               trigger->condition, &type);
+               assert(c_status == LTTNG_CONDITION_STATUS_OK);
+               break;
+       default:
+               abort();
+       }
+
+       return type;
+}
This page took 0.026432 seconds and 4 git commands to generate.