2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/condition/event-rule.h>
11 #include <lttng/condition/buffer-usage.h>
12 #include <lttng/event-rule/event-rule-internal.h>
13 #include <lttng/action/action-internal.h>
14 #include <lttng/domain.h>
15 #include <common/error.h>
16 #include <common/dynamic-array.h>
20 static void lttng_trigger_set_internal_object_ownership(
21 struct lttng_trigger
*trigger
)
24 * This is necessary to faciliate the object destroy phase. A trigger
25 * created by a client does not OWN the internal objects (condition and
26 * action) but when a trigger object is created on the sessiond side or
27 * for listing triggers (mostly via create_from_buffer) the object is
28 * the owner of the internal objects. Hence, we set the ownership bool
29 * to true, in such case, to facilitate object lifetime management and
32 * TODO: I'm open to any other solution
35 trigger
->owns_internal_objects
= true;
39 bool lttng_trigger_validate(const struct lttng_trigger
*trigger
)
48 valid
= lttng_condition_validate(trigger
->condition
) &&
49 lttng_action_validate(trigger
->action
);
54 struct lttng_trigger
*lttng_trigger_create(
55 struct lttng_condition
*condition
,
56 struct lttng_action
*action
)
58 struct lttng_trigger
*trigger
= NULL
;
60 if (!condition
|| !action
) {
64 trigger
= zmalloc(sizeof(struct lttng_trigger
));
69 urcu_ref_init(&trigger
->ref
);
70 trigger
->owns_internal_objects
= false;
71 trigger
->firing_policy
.type
= LTTNG_TRIGGER_FIRE_EVERY_N
;
72 trigger
->firing_policy
.threshold
= 1;
73 trigger
->condition
= condition
;
74 trigger
->action
= action
;
76 trigger
->creds
.set
= false;
82 struct lttng_condition
*lttng_trigger_get_condition(
83 struct lttng_trigger
*trigger
)
85 return trigger
? trigger
->condition
: NULL
;
88 const struct lttng_condition
*lttng_trigger_get_const_condition(
89 const struct lttng_trigger
*trigger
)
91 return trigger
? trigger
->condition
: NULL
;
94 struct lttng_action
*lttng_trigger_get_action(
95 struct lttng_trigger
*trigger
)
97 return trigger
? trigger
->action
: NULL
;
100 const struct lttng_action
*lttng_trigger_get_const_action(
101 const struct lttng_trigger
*trigger
)
103 return trigger
? trigger
->action
: NULL
;
106 static void trigger_destroy_ref(struct urcu_ref
*ref
)
108 struct lttng_trigger
*trigger
=
109 container_of(ref
, struct lttng_trigger
, ref
);
111 if (trigger
->owns_internal_objects
) {
112 struct lttng_action
*action
= lttng_trigger_get_action(trigger
);
113 struct lttng_condition
*condition
=
114 lttng_trigger_get_condition(trigger
);
118 lttng_action_destroy(action
);
119 lttng_condition_destroy(condition
);
126 void lttng_trigger_destroy(struct lttng_trigger
*trigger
)
128 lttng_trigger_put(trigger
);
132 ssize_t
lttng_trigger_create_from_buffer(
133 const struct lttng_buffer_view
*src_view
,
134 struct lttng_trigger
**trigger
)
136 ssize_t ret
, offset
= 0, condition_size
, action_size
, name_size
= 0;
137 enum lttng_trigger_status status
;
138 struct lttng_condition
*condition
= NULL
;
139 struct lttng_action
*action
= NULL
;
140 const struct lttng_trigger_comm
*trigger_comm
;
141 struct lttng_buffer_view condition_view
;
142 struct lttng_buffer_view action_view
;
143 struct lttng_buffer_view name_view
;
144 const char *name
= NULL
;
145 unsigned long long firing_threshold
;
146 enum lttng_trigger_firing_policy_type firing_policy
;
148 if (!src_view
|| !trigger
) {
153 /* lttng_trigger_comm header */
154 trigger_comm
= (const struct lttng_trigger_comm
*) src_view
->data
;
155 offset
+= sizeof(*trigger_comm
);
157 firing_policy
= trigger_comm
->policy_type
;
158 firing_threshold
= trigger_comm
->policy_threshold
;
159 if (trigger_comm
->name_length
!= 0) {
160 name_view
= lttng_buffer_view_from_view(
161 src_view
, offset
, trigger_comm
->name_length
);
162 name
= name_view
.data
;
163 if (trigger_comm
->name_length
== 1 ||
164 name
[trigger_comm
->name_length
- 1] != '\0' ||
165 strlen(name
) != trigger_comm
->name_length
- 1) {
169 offset
+= trigger_comm
->name_length
;
170 name_size
= trigger_comm
->name_length
;
173 condition_view
= lttng_buffer_view_from_view(src_view
, offset
, -1);
175 /* struct lttng_condition */
176 condition_size
= lttng_condition_create_from_buffer(&condition_view
,
178 if (condition_size
< 0) {
179 ret
= condition_size
;
182 offset
+= condition_size
;
184 /* struct lttng_action */
185 action_view
= lttng_buffer_view_from_view(src_view
, offset
, -1);
186 action_size
= lttng_action_create_from_buffer(&action_view
, &action
);
187 if (action_size
< 0) {
191 offset
+= action_size
;
193 /* Unexpected size of inner-elements; the buffer is corrupted. */
194 if ((ssize_t
) trigger_comm
->length
!= condition_size
+ action_size
+ name_size
) {
199 *trigger
= lttng_trigger_create(condition
, action
);
205 /* Take ownership of the internal object from there */
206 lttng_trigger_set_internal_object_ownership(*trigger
);
211 status
= lttng_trigger_set_name(*trigger
, name
);
212 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
218 status
= lttng_trigger_set_firing_policy(*trigger
, firing_policy
, firing_threshold
);
219 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
228 lttng_condition_destroy(condition
);
229 lttng_action_destroy(action
);
234 * Both elements are stored contiguously, see their "*_comm" structure
235 * for the detailed format.
238 int lttng_trigger_serialize(const struct lttng_trigger
*trigger
,
239 struct lttng_dynamic_buffer
*buf
,
243 size_t header_offset
, size_before_payload
, size_name
;
244 struct lttng_trigger_comm trigger_comm
= { 0 };
245 struct lttng_trigger_comm
*header
;
247 header_offset
= buf
->size
;
249 if (trigger
->name
!= NULL
) {
250 size_name
= strlen(trigger
->name
) + 1;
255 trigger_comm
.name_length
= size_name
;
256 trigger_comm
.policy_type
= (uint8_t) trigger
->firing_policy
.type
;
257 trigger_comm
.policy_threshold
= (uint64_t) trigger
->firing_policy
.threshold
;
259 ret
= lttng_dynamic_buffer_append(buf
, &trigger_comm
,
260 sizeof(trigger_comm
));
265 size_before_payload
= buf
->size
;
268 ret
= lttng_dynamic_buffer_append(buf
, trigger
->name
, size_name
);
273 ret
= lttng_condition_serialize(trigger
->condition
, buf
, fd_to_send
);
278 ret
= lttng_action_serialize(trigger
->action
, buf
);
283 /* Update payload size. */
284 header
= (struct lttng_trigger_comm
*) ((char *) buf
->data
+ header_offset
);
285 header
->length
= buf
->size
- size_before_payload
;
290 enum lttng_trigger_status
lttng_trigger_set_name(struct lttng_trigger
*trigger
, const char* name
)
292 char *name_copy
= NULL
;
293 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
295 if (!trigger
|| !name
||
297 status
= LTTNG_TRIGGER_STATUS_INVALID
;
301 name_copy
= strdup(name
);
303 status
= LTTNG_TRIGGER_STATUS_ERROR
;
311 trigger
->name
= name_copy
;
317 enum lttng_trigger_status
lttng_trigger_get_name(const struct lttng_trigger
*trigger
, const char **name
)
319 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
321 if (!trigger
|| !name
) {
322 status
= LTTNG_TRIGGER_STATUS_INVALID
;
326 if (!trigger
->name
) {
327 status
= LTTNG_TRIGGER_STATUS_UNSET
;
330 *name
= trigger
->name
;
336 int lttng_trigger_assign(struct lttng_trigger
*dst
,
337 const struct lttng_trigger
*src
)
340 enum lttng_trigger_status status
;
341 /* todo some validation */
343 status
= lttng_trigger_set_name(dst
, src
->name
);
344 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
346 ERR("Failed to set name for trigger");
354 void lttng_trigger_set_key(struct lttng_trigger
*trigger
, uint64_t key
)
357 trigger
->key
.value
= key
;
358 trigger
->key
.set
= true;
362 uint64_t lttng_trigger_get_key(const struct lttng_trigger
*trigger
)
366 assert(trigger
->key
.set
== true);
367 return trigger
->key
.value
;
371 int lttng_trigger_generate_name(struct lttng_trigger
*trigger
, uint64_t offset
)
374 char *generated_name
= NULL
;
375 assert(trigger
->key
.set
);
377 ret
= asprintf(&generated_name
, "T%" PRIu64
"", trigger
->key
.value
+ offset
);
379 ERR("Failed to generate trigger name");
387 trigger
->name
= generated_name
;
393 bool lttng_trigger_is_equal(
394 const struct lttng_trigger
*a
, const struct lttng_trigger
*b
)
396 /* TODO: Optimization: for now a trigger with a firing policy that is
397 * not the same even if the conditions and actions is the same is
398 * treated as a "completely" different trigger. In a perfect world we
399 * would simply add a supplemental counter internally (sessiond side) to
400 * remove overhead on the tracer side.
402 if (a
->firing_policy
.type
!= b
->firing_policy
.type
) {
406 if (a
->firing_policy
.threshold
!= b
->firing_policy
.threshold
) {
411 * Name is not taken into account since it is cosmetic only
413 if (!lttng_condition_is_equal(a
->condition
, b
->condition
)) {
416 if (!lttng_action_is_equal(a
->action
, b
->action
)) {
423 static void delete_trigger_array_element(void *ptr
)
425 struct lttng_trigger
*trigger
= ptr
;
426 lttng_trigger_destroy(trigger
);
430 struct lttng_triggers
*lttng_triggers_create(void)
432 struct lttng_triggers
*triggers
= NULL
;
434 triggers
= zmalloc(sizeof(*triggers
));
439 lttng_dynamic_pointer_array_init(&triggers
->array
, delete_trigger_array_element
);
448 struct lttng_trigger
*lttng_triggers_get_pointer_of_index(
449 const struct lttng_triggers
*triggers
, unsigned int index
)
452 if (index
>= lttng_dynamic_pointer_array_get_count(&triggers
->array
)) {
455 return lttng_dynamic_pointer_array_get_pointer(&triggers
->array
, index
);
459 int lttng_triggers_add(
460 struct lttng_triggers
*triggers
, struct lttng_trigger
*trigger
)
465 return lttng_dynamic_pointer_array_add_pointer(&triggers
->array
, trigger
);
468 const struct lttng_trigger
*lttng_triggers_get_at_index(
469 const struct lttng_triggers
*triggers
, unsigned int index
)
472 return lttng_triggers_get_pointer_of_index(triggers
, index
);
475 enum lttng_trigger_status
lttng_triggers_get_count(const struct lttng_triggers
*triggers
, unsigned int *count
)
477 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
479 if (!triggers
|| !count
) {
480 status
= LTTNG_TRIGGER_STATUS_INVALID
;
484 *count
= lttng_dynamic_pointer_array_get_count(&triggers
->array
);
489 void lttng_triggers_destroy(struct lttng_triggers
*triggers
)
495 lttng_dynamic_pointer_array_reset(&triggers
->array
);
499 int lttng_triggers_serialize(const struct lttng_triggers
*triggers
,
500 struct lttng_dynamic_buffer
*buffer
)
504 size_t header_offset
, size_before_payload
;
505 struct lttng_triggers_comm triggers_comm
= { 0 };
506 struct lttng_triggers_comm
*header
;
507 struct lttng_trigger
*trigger
;
508 enum lttng_trigger_status status
;
510 header_offset
= buffer
->size
;
512 status
= lttng_triggers_get_count(triggers
, &count
);
513 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
514 ret
= LTTNG_ERR_INVALID
;
518 triggers_comm
.count
= count
;
520 ret
= lttng_dynamic_buffer_append(buffer
, &triggers_comm
,
521 sizeof(triggers_comm
));
526 size_before_payload
= buffer
->size
;
528 for (int i
= 0; i
< count
; i
++) {
529 trigger
= lttng_triggers_get_pointer_of_index(triggers
, i
);
534 ret
= lttng_trigger_serialize(trigger
, buffer
, NULL
);
540 /* Update payload size. */
541 header
= (struct lttng_triggers_comm
*) ((char *) buffer
->data
+ header_offset
);
542 header
->length
= buffer
->size
- size_before_payload
;
548 ssize_t
lttng_triggers_create_from_buffer(
549 const struct lttng_buffer_view
*src_view
,
550 struct lttng_triggers
**triggers
)
552 ssize_t ret
, offset
= 0, trigger_size
, triggers_size
= 0;
553 const struct lttng_triggers_comm
*triggers_comm
;
554 struct lttng_buffer_view trigger_view
;
555 struct lttng_triggers
*local_triggers
= NULL
;
557 if (!src_view
|| !triggers
) {
562 /* lttng_trigger_comms header */
563 triggers_comm
= (const struct lttng_triggers_comm
*) src_view
->data
;
564 offset
+= sizeof(*triggers_comm
);
566 local_triggers
= lttng_triggers_create();
567 if (!local_triggers
) {
572 for (int i
= 0; i
< triggers_comm
->count
; i
++) {
573 struct lttng_trigger
*trigger
= NULL
;
574 trigger_view
= lttng_buffer_view_from_view(src_view
, offset
, -1);
575 trigger_size
= lttng_trigger_create_from_buffer(&trigger_view
,
577 if (trigger_size
< 0) {
582 /* Pass ownership of the trigger to the collection */
583 ret
= lttng_triggers_add(local_triggers
, trigger
);
589 offset
+= trigger_size
;
590 triggers_size
+= trigger_size
;
593 /* Unexpected size of inner-elements; the buffer is corrupted. */
594 if ((ssize_t
) triggers_comm
->length
!= triggers_size
) {
599 /* Pass ownership to caller */
600 *triggers
= local_triggers
;
601 local_triggers
= NULL
;
606 lttng_triggers_destroy(local_triggers
);
611 const struct lttng_credentials
*lttng_trigger_get_credentials(
612 const struct lttng_trigger
*trigger
)
614 assert(trigger
->creds
.set
);
615 return &(trigger
->creds
.credentials
);
619 void lttng_trigger_set_credentials(
620 struct lttng_trigger
*trigger
, uid_t uid
, gid_t gid
)
622 trigger
->creds
.credentials
.uid
= uid
;
623 trigger
->creds
.credentials
.gid
= gid
;
624 trigger
->creds
.set
= true;
627 enum lttng_trigger_status
lttng_trigger_set_firing_policy(
628 struct lttng_trigger
*trigger
,
629 enum lttng_trigger_firing_policy_type policy_type
,
630 unsigned long long threshold
)
632 enum lttng_trigger_status ret
= LTTNG_TRIGGER_STATUS_OK
;
636 ret
= LTTNG_TRIGGER_STATUS_INVALID
;
640 trigger
->firing_policy
.type
= policy_type
;
641 trigger
->firing_policy
.threshold
= threshold
;
647 enum lttng_trigger_status
lttng_trigger_get_firing_policy(
648 const struct lttng_trigger
*trigger
,
649 enum lttng_trigger_firing_policy_type
*policy_type
,
650 unsigned long long *threshold
)
652 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
654 if (!trigger
|| !policy_type
|| !threshold
) {
655 status
= LTTNG_TRIGGER_STATUS_INVALID
;
659 *policy_type
= trigger
->firing_policy
.type
;
660 *threshold
= trigger
->firing_policy
.threshold
;
667 bool lttng_trigger_is_ready_to_fire(struct lttng_trigger
*trigger
)
670 bool ready_to_fire
= false;
672 trigger
->firing_policy
.current_count
++;
674 switch (trigger
->firing_policy
.type
) {
675 case LTTNG_TRIGGER_FIRE_EVERY_N
:
676 if (trigger
->firing_policy
.current_count
== trigger
->firing_policy
.threshold
) {
677 trigger
->firing_policy
.current_count
= 0;
678 ready_to_fire
= true;
681 case LTTNG_TRIGGER_FIRE_ONCE_AFTER_N
:
682 if (trigger
->firing_policy
.current_count
== trigger
->firing_policy
.threshold
) {
683 /* TODO: remove the trigger of at least deactivate it on
684 * the tracers side to remove any work overhead on the
685 * traced application or kernel since the trigger will
687 * Still this branch should be left here since event
688 * could still be in the pipe. These will be discarded.
690 ready_to_fire
= true;
697 return ready_to_fire
;
701 void lttng_trigger_get(struct lttng_trigger
*trigger
)
703 urcu_ref_get(&trigger
->ref
);
707 void lttng_trigger_put(struct lttng_trigger
*trigger
)
713 urcu_ref_put(&trigger
->ref
, trigger_destroy_ref
);
717 enum lttng_domain_type
lttng_trigger_get_underlying_domain_type_restriction(
718 const struct lttng_trigger
*trigger
)
720 enum lttng_domain_type type
= LTTNG_DOMAIN_NONE
;
721 const struct lttng_event_rule
*event_rule
;
722 enum lttng_condition_status c_status
;
723 enum lttng_condition_type c_type
;
726 assert(trigger
->condition
);
727 c_type
= lttng_condition_get_type(trigger
->condition
);
728 if (c_type
== LTTNG_CONDITION_TYPE_UNKNOWN
) {
733 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE
:
734 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING
:
735 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED
:
736 type
= LTTNG_DOMAIN_NONE
;
738 case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT
:
739 c_status
= lttng_condition_event_rule_get_rule(
740 trigger
->condition
, &event_rule
);
741 if (c_status
!= LTTNG_CONDITION_STATUS_OK
) {
742 /* The condition object is invalid */
746 type
= lttng_event_rule_get_domain_type(event_rule
);
748 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
:
749 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
:
750 c_status
= lttng_condition_buffer_usage_get_domain_type(
751 trigger
->condition
, &type
);
752 if (c_status
!= LTTNG_CONDITION_STATUS_OK
) {
753 /* The condition object is invalid */
758 type
= LTTNG_DOMAIN_NONE
;