#include <common/macros.h>
#include <lttng/condition/condition.h>
#include <lttng/action/action-internal.h>
-#include <lttng/action/group-internal.h>
+#include <lttng/action/list-internal.h>
#include <lttng/domain-internal.h>
#include <lttng/notification/notification-internal.h>
#include <lttng/condition/condition-internal.h>
#include <lttng/condition/buffer-usage-internal.h>
#include <lttng/condition/session-consumed-size-internal.h>
#include <lttng/condition/session-rotation-internal.h>
-#include <lttng/condition/on-event-internal.h>
+#include <lttng/condition/event-rule-matches-internal.h>
#include <lttng/domain-internal.h>
#include <lttng/notification/channel-internal.h>
#include <lttng/trigger/trigger-internal.h>
return "REMOVE_TRACER_EVENT_SOURCE";
case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS:
return "LIST_TRIGGERS";
+ case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+ return "GET_TRIGGER";
case NOTIFICATION_COMMAND_TYPE_QUIT:
return "QUIT";
case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
const void *key)
{
bool match = false;
- const char *name;
+ const char *element_trigger_name;
const char *key_name;
enum lttng_trigger_status status;
const struct lttng_credentials *key_creds;
struct lttng_trigger_ht_element,
node_by_name_uid);
- status = lttng_trigger_get_name(trigger_ht_element->trigger, &name);
- assert(status == LTTNG_TRIGGER_STATUS_OK);
+ status = lttng_trigger_get_name(trigger_ht_element->trigger,
+ &element_trigger_name);
+ element_trigger_name = status == LTTNG_TRIGGER_STATUS_OK ?
+ element_trigger_name : NULL;
status = lttng_trigger_get_name(trigger_key, &key_name);
- assert(status == LTTNG_TRIGGER_STATUS_OK);
+ key_name = status == LTTNG_TRIGGER_STATUS_OK ? key_name : NULL;
- /* Compare the names. */
- if (strcmp(name, key_name) != 0) {
+ /*
+ * Compare the names.
+ * Consider null names as not equal. This is to maintain backwards
+ * compatibility with pre-2.13 anonymous triggers. Multiples anonymous
+ * triggers are allowed for a given user.
+ */
+ if (!element_trigger_name || !key_name) {
+ goto end;
+ }
+
+ if (strcmp(element_trigger_name, key_name) != 0) {
goto end;
}
case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
return LTTNG_OBJECT_TYPE_SESSION;
- case LTTNG_CONDITION_TYPE_ON_EVENT:
+ case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
return LTTNG_OBJECT_TYPE_NONE;
default:
return LTTNG_OBJECT_TYPE_UNKNOWN;
* Ownership of `evaluation` transferred to the action executor
* no matter the result.
*/
- executor_status = action_executor_enqueue(state->executor,
- trigger, evaluation, &session_creds,
- client_list);
+ executor_status = action_executor_enqueue_trigger(
+ state->executor, trigger, evaluation,
+ &session_creds, client_list);
evaluation = NULL;
switch (executor_status) {
case ACTION_EXECUTOR_STATUS_OK:
return ret;
}
-static
-int condition_on_event_update_error_count(struct lttng_trigger *trigger)
-{
- int ret = 0;
- uint64_t error_count = 0;
- struct lttng_condition *condition;
- enum event_notifier_error_accounting_status status;
-
- condition = lttng_trigger_get_condition(trigger);
- assert(lttng_condition_get_type(condition) ==
- LTTNG_CONDITION_TYPE_ON_EVENT);
-
- status = event_notifier_error_accounting_get_count(trigger, &error_count);
- if (status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
- uid_t trigger_owner_uid;
- const char *trigger_name;
- const enum lttng_trigger_status trigger_status =
- lttng_trigger_get_owner_uid(
- trigger, &trigger_owner_uid);
-
- assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
- if (lttng_trigger_get_name(trigger, &trigger_name) != LTTNG_TRIGGER_STATUS_OK) {
- trigger_name = "(unnamed)";
- }
-
- ERR("Failed to get event notifier error count of trigger for update: trigger owner = %d, trigger name = '%s'",
- trigger_owner_uid, trigger_name);
- ret = -1;
- }
-
- lttng_condition_on_event_set_error_count(condition, error_count);
- return ret;
-}
-
int handle_notification_thread_remove_tracer_event_source_no_result(
struct notification_thread_state *state,
int tracer_event_source_fd)
continue;
}
- if (lttng_trigger_needs_tracer_notifier(trigger_ht_element->trigger)) {
- ret = condition_on_event_update_error_count(
- trigger_ht_element->trigger);
- assert(!ret);
- }
-
ret = lttng_triggers_add(local_triggers,
trigger_ht_element->trigger);
if (ret < 0) {
return ret;
}
+static inline void get_trigger_info_for_log(const struct lttng_trigger *trigger,
+ const char **trigger_name,
+ uid_t *trigger_owner_uid)
+{
+ enum lttng_trigger_status trigger_status;
+
+ trigger_status = lttng_trigger_get_name(trigger, trigger_name);
+ switch (trigger_status) {
+ case LTTNG_TRIGGER_STATUS_OK:
+ break;
+ case LTTNG_TRIGGER_STATUS_UNSET:
+ *trigger_name = "(anonymous)";
+ break;
+ default:
+ abort();
+ }
+
+ trigger_status = lttng_trigger_get_owner_uid(trigger,
+ trigger_owner_uid);
+ assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+}
+
+static int handle_notification_thread_command_get_trigger(
+ struct notification_thread_state *state,
+ const struct lttng_trigger *trigger,
+ struct lttng_trigger **registered_trigger,
+ enum lttng_error_code *_cmd_result)
+{
+ int ret = -1;
+ struct cds_lfht_iter iter;
+ struct lttng_trigger_ht_element *trigger_ht_element;
+ enum lttng_error_code cmd_result = LTTNG_ERR_TRIGGER_NOT_FOUND;
+ const char *trigger_name;
+ uid_t trigger_owner_uid;
+
+ rcu_read_lock();
+
+ cds_lfht_for_each_entry(
+ state->triggers_ht, &iter, trigger_ht_element, node) {
+ if (lttng_trigger_is_equal(
+ trigger, trigger_ht_element->trigger)) {
+ /* Take one reference on the return trigger. */
+ *registered_trigger = trigger_ht_element->trigger;
+ lttng_trigger_get(*registered_trigger);
+ ret = 0;
+ cmd_result = LTTNG_OK;
+ goto end;
+ }
+ }
+
+ /* Not a fatal error if the trigger is not found. */
+ get_trigger_info_for_log(trigger, &trigger_name, &trigger_owner_uid);
+ DBG("Failed to retrieve registered version of trigger: trigger name = '%s', trigger owner uid = %d",
+ trigger_name, (int) trigger_owner_uid);
+
+ ret = 0;
+
+end:
+ rcu_read_unlock();
+ *_cmd_result = cmd_result;
+ return ret;
+}
+
static
bool condition_is_supported(struct lttng_condition *condition)
{
is_supported = kernel_supports_ring_buffer_snapshot_sample_positions() == 1;
break;
}
- case LTTNG_CONDITION_TYPE_ON_EVENT:
+ case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
{
const struct lttng_event_rule *event_rule;
enum lttng_domain_type domain;
const enum lttng_condition_status status =
- lttng_condition_on_event_get_rule(
+ lttng_condition_event_rule_matches_get_rule(
condition, &event_rule);
assert(status == LTTNG_CONDITION_STATUS_OK);
if (action_type == LTTNG_ACTION_TYPE_NOTIFY) {
is_notify = true;
goto end;
- } else if (action_type != LTTNG_ACTION_TYPE_GROUP) {
+ } else if (action_type != LTTNG_ACTION_TYPE_LIST) {
goto end;
}
- action_status = lttng_action_group_get_count(action, &count);
+ action_status = lttng_action_list_get_count(action, &count);
assert(action_status == LTTNG_ACTION_STATUS_OK);
for (i = 0; i < count; i++) {
const struct lttng_action *inner_action =
- lttng_action_group_get_at_index(
+ lttng_action_list_get_at_index(
action, i);
action_type = lttng_action_get_type(inner_action);
trigger, &error_counter_index);
if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) {
if (error_accounting_status == EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_NO_INDEX_AVAILABLE) {
- DBG("Trigger group error accounting counter full.");
+ DBG("Trigger list error accounting counter full.");
ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING_FULL;
} else {
ERR("Error registering trigger for error accounting");
goto error_remove_ht_element;
}
- lttng_condition_on_event_set_error_counter_index(
+ lttng_condition_event_rule_matches_set_error_counter_index(
condition, error_counter_index);
ret = LTTNG_OK;
int handle_notification_thread_command_register_trigger(
struct notification_thread_state *state,
struct lttng_trigger *trigger,
+ bool is_trigger_anonymous,
enum lttng_error_code *cmd_result)
{
int ret = 0;
/* Set the trigger's tracer token. */
lttng_trigger_set_tracer_token(trigger, trigger_tracer_token);
- if (lttng_trigger_get_name(trigger, &trigger_name) ==
- LTTNG_TRIGGER_STATUS_UNSET) {
- const enum lttng_error_code ret_code = generate_trigger_name(
- state, trigger, &trigger_name);
+ if (!is_trigger_anonymous) {
+ if (lttng_trigger_get_name(trigger, &trigger_name) ==
+ LTTNG_TRIGGER_STATUS_UNSET) {
+ const enum lttng_error_code ret_code =
+ generate_trigger_name(state, trigger,
+ &trigger_name);
- if (ret_code != LTTNG_OK) {
- /* Fatal error. */
- ret = -1;
- *cmd_result = ret_code;
+ if (ret_code != LTTNG_OK) {
+ /* Fatal error. */
+ ret = -1;
+ *cmd_result = ret_code;
+ goto error;
+ }
+ } else if (trigger_name_taken(state, trigger)) {
+ /* Not a fatal error. */
+ *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+ ret = 0;
goto error;
}
- } else if (trigger_name_taken(state, trigger)) {
- /* Not a fatal error. */
- *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
- ret = 0;
- goto error;
+ } else {
+ trigger_name = "(anonymous)";
}
condition = lttng_trigger_get_condition(trigger);
trigger,
&trigger_ht_element->node_by_name_uid);
if (node != &trigger_ht_element->node_by_name_uid) {
- /* Not a fatal error, simply report it to the client. */
- cds_lfht_del(state->triggers_ht, &trigger_ht_element->node);
- *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
+ /* Internal error: add to triggers_ht should have failed. */
+ ret = -1;
goto error_free_ht_element;
}
+ /* From this point consider the trigger registered. */
+ lttng_trigger_set_as_registered(trigger);
+
/*
* Some triggers might need a tracer notifier depending on its
* condition and actions.
* Ownership of `evaluation` transferred to the action executor
* no matter the result.
*/
- executor_status = action_executor_enqueue(state->executor, trigger,
- evaluation, &object_creds, client_list);
+ executor_status = action_executor_enqueue_trigger(state->executor,
+ trigger, evaluation, &object_creds, client_list);
evaluation = NULL;
switch (executor_status) {
case ACTION_EXECUTOR_STATUS_OK:
}
error:
if (free_trigger) {
+ /*
+ * Other objects might have a reference to the trigger, mark it
+ * as unregistered.
+ */
+ lttng_trigger_set_as_unregistered(trigger);
lttng_trigger_destroy(trigger);
}
end:
cmd_reply = LTTNG_OK;
}
+ trigger_ht_element = caa_container_of(triggers_ht_node,
+ struct lttng_trigger_ht_element, node);
+
/* Remove trigger from channel_triggers_ht. */
cds_lfht_for_each_entry(state->channel_triggers_ht, &iter, trigger_list,
channel_triggers_ht_node) {
teardown_tracer_notifier(state, trigger);
}
- trigger_ht_element = caa_container_of(triggers_ht_node,
- struct lttng_trigger_ht_element, node);
-
if (is_trigger_action_notify(trigger)) {
/*
* Remove and release the client list from
case NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER:
ret = handle_notification_thread_command_register_trigger(state,
cmd->parameters.register_trigger.trigger,
+ cmd->parameters.register_trigger.is_trigger_anonymous,
&cmd->reply_code);
break;
case NOTIFICATION_COMMAND_TYPE_UNREGISTER_TRIGGER:
cmd->reply_code = LTTNG_OK;
ret = 1;
goto end;
+ case NOTIFICATION_COMMAND_TYPE_GET_TRIGGER:
+ {
+ struct lttng_trigger *trigger = NULL;
+
+ ret = handle_notification_thread_command_get_trigger(state,
+ cmd->parameters.get_trigger.trigger, &trigger,
+ &cmd->reply_code);
+ cmd->reply.get_trigger.trigger = trigger;
+ break;
+ }
case NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE:
{
const enum client_transmission_status client_status =
struct cds_lfht_node *node;
struct cds_lfht_iter iter;
struct notification_trigger_tokens_ht_element *element;
- enum lttng_trigger_status trigger_status;
struct lttng_evaluation *evaluation = NULL;
enum action_executor_status executor_status;
struct notification_client_list *client_list = NULL;
- const char *trigger_name;
int ret;
unsigned int capture_count = 0;
struct notification_trigger_tokens_ht_element,
node);
- trigger_status = lttng_trigger_get_name(element->trigger, &trigger_name);
- assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
- if (lttng_condition_on_event_get_capture_descriptor_count(
+ if (lttng_condition_event_rule_matches_get_capture_descriptor_count(
lttng_trigger_get_const_condition(element->trigger),
&capture_count) != LTTNG_CONDITION_STATUS_OK) {
ERR("Failed to get capture count");
goto end;
}
- evaluation = lttng_evaluation_on_event_create(
+ evaluation = lttng_evaluation_event_rule_matches_create(
container_of(lttng_trigger_get_const_condition(
element->trigger),
- struct lttng_condition_on_event,
+ struct lttng_condition_event_rule_matches,
parent),
notification->capture_buffer,
notification->capture_buf_size, false);
}
client_list = get_client_list_from_condition(state,
lttng_trigger_get_const_condition(element->trigger));
- executor_status = action_executor_enqueue(state->executor,
+ executor_status = action_executor_enqueue_trigger(state->executor,
element->trigger, evaluation, NULL, client_list);
switch (executor_status) {
case ACTION_EXECUTOR_STATUS_OK:
* Ownership of `evaluation` transferred to the action executor
* no matter the result.
*/
- executor_status = action_executor_enqueue(state->executor,
- trigger, evaluation, &channel_creds,
- client_list);
+ executor_status = action_executor_enqueue_trigger(
+ state->executor, trigger, evaluation,
+ &channel_creds, client_list);
evaluation = NULL;
switch (executor_status) {
case ACTION_EXECUTOR_STATUS_OK: