summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
6487ad5)
Background
==========
* Clients can subscribe to certain specific conditions (e.g. buffer
usage) using the `lttng_notification_channel_subscribe()` function.
* This subscription is only useful once a trigger with that condition
AND at least one notify action is registered.
* The sessiond keeps a list for client subscribed to each registered
condition.
* More than one trigger with the same condition may be registered
the sessiond at the same time if they have different actions.
Issue
=====
Currently, when registering a trigger (T1) the sessiond looks if there
is already a client list for the condition of this trigger. If not, the
sessiond links the newly created client list object to that trigger T1
by keeping a pointer to it.
This means that if another trigger (T2) is registered with the same
condition (but a different name, or different actions) it will reuse the
same client list object and use the pointer to the T1.
This causes problems if T1 is unregistered before T2. In that case, the
pointer to T1 in the client list object is pointing to a deallocated
trigger object.
This issue is not encountered with the current test suite, namely the
`test_notification_multi_app` test case, because triggers with the same
condition also had the same action, so they are considered identical and
are not registered.
This issue was first witnessed when adding a trigger name comparison in
the `lttng_trigger_is_equal()` function.
Fix
===
Change the client list object so that it has its own copy of the
condition and a list of dependent triggers. Each trigger with that
condition has a reference on this client list object.
When unregistering a trigger, the notification thread removes it for the
client list's triggers list and put its reference on the client list
object.
Tests
=====
This commit adds a parameter to the base_client that dictates if the
notify action should be in a group. This is a trick to create triggers
that are not equal but have the same behaviour.
The `test_notification_multi_app` test case is modified to turn on this
option every other trigger registration.
Semi-related cleanups
=====================
* Merge `notification_client_list_create()` and
`publish_notification_client_list()` functions since they are used
together anyway. This removes the need to call
`notification_client_list_put()` at the end of the
`_register_trigger()` function
* Rename `trigger_applies_to_client()` to `condition_applies_to_client()`.
Signed-off-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I3ebb90a1a64236a440a085e6fc1b82726a0e5af9
+
+LTTNG_HIDDEN
+struct lttng_condition *lttng_condition_copy(const struct lttng_condition *condition)
+{
+ int ret;
+ struct lttng_payload copy_buffer;
+ struct lttng_condition *copy = NULL;
+
+ lttng_payload_init(©_buffer);
+
+ ret = lttng_condition_serialize(condition, ©_buffer);
+ if (ret < 0) {
+ goto end;
+ }
+
+ {
+ struct lttng_payload_view view =
+ lttng_payload_view_from_payload(
+ ©_buffer, 0, -1);
+
+ ret = lttng_condition_create_from_payload(
+ &view, ©);
+ if (ret < 0) {
+ copy = NULL;
+ goto end;
+ }
+ }
+
+end:
+ lttng_payload_reset(©_buffer);
+ return copy;
+}
*/
unsigned long lttng_condition_hash(const struct lttng_condition *condition);
*/
unsigned long lttng_condition_hash(const struct lttng_condition *condition);
+struct lttng_condition *lttng_condition_copy(
+ const struct lttng_condition *condition);
#endif /* LTTNG_SESSIOND_CONDITION_INTERNAL_H */
#endif /* LTTNG_SESSIOND_CONDITION_INTERNAL_H */
struct lttng_trigger *trigger;
struct cds_lfht_node node;
struct cds_lfht_node node_by_name_uid;
struct lttng_trigger *trigger;
struct cds_lfht_node node;
struct cds_lfht_node node_by_name_uid;
+ struct cds_list_head client_list_trigger_node;
/* call_rcu delayed reclaim. */
struct rcu_head rcu_node;
};
/* call_rcu delayed reclaim. */
struct rcu_head rcu_node;
};
client_list = caa_container_of(node, struct notification_client_list,
notification_trigger_clients_ht_node);
client_list = caa_container_of(node, struct notification_client_list,
notification_trigger_clients_ht_node);
- condition = lttng_trigger_get_const_condition(client_list->trigger);
+ condition = client_list->condition;
return !!lttng_condition_is_equal(condition_key, condition);
}
return !!lttng_condition_is_equal(condition_key, condition);
}
container_of(list_ref, typeof(*list), ref);
struct notification_client_list_element *client_list_element, *tmp;
container_of(list_ref, typeof(*list), ref);
struct notification_client_list_element *client_list_element, *tmp;
+ lttng_condition_put(list->condition);
+
if (list->notification_trigger_clients_ht) {
rcu_read_lock();
if (list->notification_trigger_clients_ht) {
rcu_read_lock();
cds_lfht_del(list->notification_trigger_clients_ht,
&list->notification_trigger_clients_ht_node);
rcu_read_unlock();
list->notification_trigger_clients_ht = NULL;
}
cds_list_for_each_entry_safe(client_list_element, tmp,
cds_lfht_del(list->notification_trigger_clients_ht,
&list->notification_trigger_clients_ht_node);
rcu_read_unlock();
list->notification_trigger_clients_ht = NULL;
}
cds_list_for_each_entry_safe(client_list_element, tmp,
+ &list->clients_list, node) {
free(client_list_element);
}
free(client_list_element);
}
+
+ assert(cds_list_empty(&list->triggers_list));
+
pthread_mutex_destroy(&list->lock);
call_rcu(&list->rcu_node, free_notification_client_list_rcu);
}
pthread_mutex_destroy(&list->lock);
call_rcu(&list->rcu_node, free_notification_client_list_rcu);
}
+static
+bool condition_applies_to_client(const struct lttng_condition *condition,
+ struct notification_client *client)
+{
+ bool applies = false;
+ struct lttng_condition_list_element *condition_list_element;
+
+ cds_list_for_each_entry(condition_list_element, &client->condition_list,
+ node) {
+ applies = lttng_condition_is_equal(
+ condition_list_element->condition,
+ condition);
+ if (applies) {
+ break;
+ }
+ }
+
+ return applies;
+}
+
static
struct notification_client_list *notification_client_list_create(
static
struct notification_client_list *notification_client_list_create(
- const struct lttng_trigger *trigger)
+ struct notification_thread_state *state,
+ const struct lttng_condition *condition)
- struct notification_client_list *client_list =
- zmalloc(sizeof(*client_list));
+ struct notification_client *client;
+ struct cds_lfht_iter iter;
+ struct notification_client_list *client_list;
+ client_list = zmalloc(sizeof(*client_list));
+ PERROR("Failed to allocate notification client list");
+ goto end;
pthread_mutex_init(&client_list->lock, NULL);
pthread_mutex_init(&client_list->lock, NULL);
+ /*
+ * The trigger that owns the condition has the first reference to this
+ * client list.
+ */
urcu_ref_init(&client_list->ref);
cds_lfht_node_init(&client_list->notification_trigger_clients_ht_node);
urcu_ref_init(&client_list->ref);
cds_lfht_node_init(&client_list->notification_trigger_clients_ht_node);
- CDS_INIT_LIST_HEAD(&client_list->list);
- client_list->trigger = trigger;
-error:
- return client_list;
-}
+ CDS_INIT_LIST_HEAD(&client_list->clients_list);
+ CDS_INIT_LIST_HEAD(&client_list->triggers_list);
-static
-void publish_notification_client_list(
- struct notification_thread_state *state,
- struct notification_client_list *list)
-{
- const struct lttng_condition *condition =
- lttng_trigger_get_const_condition(list->trigger);
+ /*
+ * Create a copy of the condition so that it's independent of any
+ * trigger. The client list may outlive the trigger object (which owns
+ * the condition) that is used to create it.
+ */
+ client_list->condition = lttng_condition_copy(condition);
+
+ /* Build a list of clients to which this new condition applies. */
+ cds_lfht_for_each_entry (state->client_socket_ht, &iter, client,
+ client_socket_ht_node) {
+ struct notification_client_list_element *client_list_element;
- assert(!list->notification_trigger_clients_ht);
- notification_client_list_get(list);
+ if (!condition_applies_to_client(condition, client)) {
+ continue;
+ }
+
+ client_list_element = zmalloc(sizeof(*client_list_element));
+ if (!client_list_element) {
+ goto error_put_client_list;
+ }
- list->notification_trigger_clients_ht =
+ CDS_INIT_LIST_HEAD(&client_list_element->node);
+ client_list_element->client = client;
+ cds_list_add(&client_list_element->node, &client_list->clients_list);
+ }
+
+ client_list->notification_trigger_clients_ht =
state->notification_trigger_clients_ht;
rcu_read_lock();
state->notification_trigger_clients_ht;
rcu_read_lock();
- cds_lfht_add(state->notification_trigger_clients_ht,
- lttng_condition_hash(condition),
- &list->notification_trigger_clients_ht_node);
+ /*
+ * Add the client list to the global list of client list.
+ */
+ cds_lfht_add_unique(state->notification_trigger_clients_ht,
+ lttng_condition_hash(client_list->condition),
+ match_client_list_condition,
+ client_list->condition,
+ &client_list->notification_trigger_clients_ht_node);
+ goto end;
+
+error_put_client_list:
+ notification_client_list_put(client_list);
+ client_list = NULL;
+
+end:
+ return client_list;
void notification_client_list_put(struct notification_client_list *list)
{
if (!list) {
void notification_client_list_put(struct notification_client_list *list)
{
if (!list) {
* subscribing.
*/
cds_lfht_node_init(&client_list.notification_trigger_clients_ht_node);
* subscribing.
*/
cds_lfht_node_init(&client_list.notification_trigger_clients_ht_node);
- CDS_INIT_LIST_HEAD(&client_list.list);
- client_list.trigger = trigger;
+ CDS_INIT_LIST_HEAD(&client_list.clients_list);
CDS_INIT_LIST_HEAD(&client_list_element.node);
client_list_element.client = client;
CDS_INIT_LIST_HEAD(&client_list_element.node);
client_list_element.client = client;
- cds_list_add(&client_list_element.node, &client_list.list);
+ cds_list_add(&client_list_element.node, &client_list.clients_list);
/* Send evaluation result to the newly-subscribed client. */
DBG("[notification-thread] Newly subscribed-to condition evaluated to true, notifying client");
/* Send evaluation result to the newly-subscribed client. */
DBG("[notification-thread] Newly subscribed-to condition evaluated to true, notifying client");
* This is correct since the list doesn't own the trigger and the
* object is immutable.
*/
* This is correct since the list doesn't own the trigger and the
* object is immutable.
*/
- if (evaluate_condition_for_client(client_list->trigger, condition,
- client, state)) {
- WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
- ret = -1;
- free(client_list_element);
- goto end;
+ struct lttng_trigger_ht_element *trigger_ht_element;
+ pthread_mutex_lock(&client_list->lock);
+ cds_list_for_each_entry(trigger_ht_element,
+ &client_list->triggers_list, client_list_trigger_node) {
+ if (evaluate_condition_for_client(trigger_ht_element->trigger, condition,
+ client, state)) {
+ WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
+ ret = -1;
+ free(client_list_element);
+ goto end;
+ }
+ pthread_mutex_unlock(&client_list->lock);
/*
* Add the client to the list of clients interested in a given trigger
/*
* Add the client to the list of clients interested in a given trigger
CDS_INIT_LIST_HEAD(&client_list_element->node);
pthread_mutex_lock(&client_list->lock);
CDS_INIT_LIST_HEAD(&client_list_element->node);
pthread_mutex_lock(&client_list->lock);
- cds_list_add(&client_list_element->node, &client_list->list);
+ cds_list_add(&client_list_element->node, &client_list->clients_list);
pthread_mutex_unlock(&client_list->lock);
end:
if (_status) {
pthread_mutex_unlock(&client_list->lock);
end:
if (_status) {
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, client_tmp,
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, client_tmp,
- &client_list->list, node) {
+ &client_list->clients_list, node) {
if (client_list_element->client->id != client->id) {
continue;
}
if (client_list_element->client->id != client->id) {
continue;
}
-static
-bool trigger_applies_to_client(struct lttng_trigger *trigger,
- struct notification_client *client)
-{
- bool applies = false;
- struct lttng_condition_list_element *condition_list_element;
-
- cds_list_for_each_entry(condition_list_element, &client->condition_list,
- node) {
- applies = lttng_condition_is_equal(
- condition_list_element->condition,
- lttng_trigger_get_condition(trigger));
- if (applies) {
- break;
- }
- }
- return applies;
-}
-
/* Must be called with RCU read lock held. */
static
struct lttng_session_trigger_list *get_session_trigger_list(
/* Must be called with RCU read lock held. */
static
struct lttng_session_trigger_list *get_session_trigger_list(
{
int ret = 0;
struct lttng_condition *condition;
{
int ret = 0;
struct lttng_condition *condition;
- struct notification_client *client;
struct notification_client_list *client_list = NULL;
struct lttng_trigger_ht_element *trigger_ht_element = NULL;
struct notification_client_list *client_list = NULL;
struct lttng_trigger_ht_element *trigger_ht_element = NULL;
- struct notification_client_list_element *client_list_element;
struct cds_lfht_node *node;
struct cds_lfht_node *node;
- struct cds_lfht_iter iter;
const char* trigger_name;
bool free_trigger = true;
struct lttng_evaluation *evaluation = NULL;
const char* trigger_name;
bool free_trigger = true;
struct lttng_evaluation *evaluation = NULL;
- /*
- * Ownership of the trigger and of its wrapper was transfered to
- * the triggers_ht. Same for token ht element if necessary.
- */
- trigger_ht_element = NULL;
- free_trigger = false;
-
/*
* The rest only applies to triggers that have a "notify" action.
* It is not skipped as this is the only action type currently
* supported.
*/
if (is_trigger_action_notify(trigger)) {
/*
* The rest only applies to triggers that have a "notify" action.
* It is not skipped as this is the only action type currently
* supported.
*/
if (is_trigger_action_notify(trigger)) {
- client_list = notification_client_list_create(trigger);
+ /*
+ * Find or create the client list of this condition. It may
+ * already be present if another trigger is already registered
+ * with the same condition.
+ */
+ client_list = get_client_list_from_condition(state, condition);
- ret = -1;
- goto error_free_ht_element;
- }
-
- /* Build a list of clients to which this new trigger applies. */
- cds_lfht_for_each_entry (state->client_socket_ht, &iter, client,
- client_socket_ht_node) {
- if (!trigger_applies_to_client(trigger, client)) {
- continue;
- }
-
- client_list_element =
- zmalloc(sizeof(*client_list_element));
- if (!client_list_element) {
- ret = -1;
- goto error_put_client_list;
+ /*
+ * No client list for this condition yet. We create new
+ * one and build it up.
+ */
+ client_list = notification_client_list_create(state, condition);
+ if (!client_list) {
+ ERR("Error creating notification client list for trigger %s", trigger->name);
+ goto error_free_ht_element;
-
- CDS_INIT_LIST_HEAD(&client_list_element->node);
- client_list_element->client = client;
- cds_list_add(&client_list_element->node,
- &client_list->list);
- /*
- * Client list ownership transferred to the
- * notification_trigger_clients_ht.
- */
- publish_notification_client_list(state, client_list);
+ CDS_INIT_LIST_HEAD(&trigger_ht_element->client_list_trigger_node);
+
+ pthread_mutex_lock(&client_list->lock);
+ cds_list_add(&trigger_ht_element->client_list_trigger_node, &client_list->triggers_list);
+ pthread_mutex_unlock(&client_list->lock);
+ /*
+ * Ownership of the trigger and of its wrapper was transfered to
+ * the triggers_ht. Same for token ht element if necessary.
+ */
+ trigger_ht_element = NULL;
+ free_trigger = false;
+
switch (get_condition_binding_object(condition)) {
case LTTNG_OBJECT_TYPE_SESSION:
/* Add the trigger to the list if it matches a known session. */
ret = bind_trigger_to_matching_session(trigger, state);
if (ret) {
switch (get_condition_binding_object(condition)) {
case LTTNG_OBJECT_TYPE_SESSION:
/* Add the trigger to the list if it matches a known session. */
ret = bind_trigger_to_matching_session(trigger, state);
if (ret) {
- goto error_put_client_list;
+ goto error_free_ht_element;
}
break;
case LTTNG_OBJECT_TYPE_CHANNEL:
}
break;
case LTTNG_OBJECT_TYPE_CHANNEL:
*/
ret = bind_trigger_to_matching_channels(trigger, state);
if (ret) {
*/
ret = bind_trigger_to_matching_channels(trigger, state);
if (ret) {
- goto error_put_client_list;
+ goto error_free_ht_element;
}
break;
case LTTNG_OBJECT_TYPE_NONE:
}
break;
case LTTNG_OBJECT_TYPE_NONE:
default:
ERR("Unknown object type on which to bind a newly registered trigger was encountered");
ret = -1;
default:
ERR("Unknown object type on which to bind a newly registered trigger was encountered");
ret = -1;
- goto error_put_client_list;
+ goto error_free_ht_element;
if (ret) {
/* Fatal error. */
if (ret) {
/* Fatal error. */
- goto error_put_client_list;
+ goto error_free_ht_element;
}
DBG("Newly registered trigger's condition evaluated to %s",
}
DBG("Newly registered trigger's condition evaluated to %s",
if (!evaluation) {
/* Evaluation yielded nothing. Normal exit. */
ret = 0;
if (!evaluation) {
/* Evaluation yielded nothing. Normal exit. */
ret = 0;
*/
ERR("Fatal error occurred while enqueuing action associated to newly registered trigger");
ret = -1;
*/
ERR("Fatal error occurred while enqueuing action associated to newly registered trigger");
ret = -1;
- goto error_put_client_list;
+ goto error_free_ht_element;
case ACTION_EXECUTOR_STATUS_OVERFLOW:
/*
* TODO Add trigger identification (name/id) when
case ACTION_EXECUTOR_STATUS_OVERFLOW:
/*
* TODO Add trigger identification (name/id) when
*/
WARN("No space left when enqueuing action associated to newly registered trigger");
ret = 0;
*/
WARN("No space left when enqueuing action associated to newly registered trigger");
ret = 0;
*cmd_result = LTTNG_OK;
DBG("Registered trigger: name = `%s`, tracer token = %" PRIu64,
trigger_name, trigger_tracer_token);
*cmd_result = LTTNG_OK;
DBG("Registered trigger: name = `%s`, tracer token = %" PRIu64,
trigger_name, trigger_tracer_token);
-
-error_put_client_list:
- notification_client_list_put(client_list);
error_free_ht_element:
if (trigger_ht_element) {
error_free_ht_element:
if (trigger_ht_element) {
if (free_trigger) {
lttng_trigger_destroy(trigger);
}
if (free_trigger) {
lttng_trigger_destroy(trigger);
}
rcu_read_unlock();
return ret;
}
rcu_read_unlock();
return ret;
}
teardown_tracer_notifier(state, trigger);
}
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
if (is_trigger_action_notify(trigger)) {
/*
* Remove and release the client list from
client_list = get_client_list_from_condition(state, condition);
assert(client_list);
client_list = get_client_list_from_condition(state, condition);
assert(client_list);
+ pthread_mutex_lock(&client_list->lock);
+ cds_list_del(&trigger_ht_element->client_list_trigger_node);
+ pthread_mutex_unlock(&client_list->lock);
+
/* Put new reference and the hashtable's reference. */
notification_client_list_put(client_list);
notification_client_list_put(client_list);
client_list = NULL;
}
/* Put new reference and the hashtable's reference. */
notification_client_list_put(client_list);
notification_client_list_put(client_list);
client_list = NULL;
}
- trigger_ht_element = caa_container_of(triggers_ht_node,
- struct lttng_trigger_ht_element, node);
-
/* Remove trigger from triggers_ht. */
notif_thread_state_remove_trigger_ht_elem(state, trigger_ht_element);
/* Remove trigger from triggers_ht. */
notif_thread_state_remove_trigger_ht_elem(state, trigger_ht_element);
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, tmp,
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, tmp,
- &client_list->list, node) {
+ &client_list->clients_list, node) {
enum client_transmission_status transmission_status;
struct notification_client *client =
client_list_element->client;
enum client_transmission_status transmission_status;
struct notification_client *client =
client_list_element->client;
/* Warn clients that a notification (or more) was dropped. */
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, tmp,
/* Warn clients that a notification (or more) was dropped. */
pthread_mutex_lock(&client_list->lock);
cds_list_for_each_entry_safe(client_list_element, tmp,
- &client_list->list, node) {
+ &client_list->clients_list, node) {
enum client_transmission_status transmission_status;
struct notification_client *client =
client_list_element->client;
enum client_transmission_status transmission_status;
struct notification_client *client =
client_list_element->client;
struct notification_client_list {
pthread_mutex_t lock;
struct urcu_ref ref;
struct notification_client_list {
pthread_mutex_t lock;
struct urcu_ref ref;
- const struct lttng_trigger *trigger;
- struct cds_list_head list;
+ struct lttng_condition *condition;
+ struct cds_list_head triggers_list;
+ struct cds_list_head clients_list;
/* Weak reference to container. */
struct cds_lfht *notification_trigger_clients_ht;
struct cds_lfht_node notification_trigger_clients_ht_node;
/* Weak reference to container. */
struct cds_lfht *notification_trigger_clients_ht;
struct cds_lfht_node notification_trigger_clients_ht_node;
#include <assert.h>
#include <lttng/action/action.h>
#include <assert.h>
#include <lttng/action/action.h>
+#include <lttng/action/group.h>
#include <lttng/action/notify.h>
#include <lttng/condition/buffer-usage.h>
#include <lttng/condition/condition.h>
#include <lttng/action/notify.h>
#include <lttng/condition/buffer-usage.h>
#include <lttng/condition/condition.h>
static double threshold_ratio = 0.0;
static uint64_t threshold_bytes = 0;
static bool is_threshold_ratio = false;
static double threshold_ratio = 0.0;
static uint64_t threshold_bytes = 0;
static bool is_threshold_ratio = false;
+static bool use_action_group = false;
static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
const char *buffer_usage_threshold_type = NULL;
const char *buffer_usage_threshold_value = NULL;
const char *nr_expected_notifications_string = NULL;
const char *buffer_usage_threshold_type = NULL;
const char *buffer_usage_threshold_value = NULL;
const char *nr_expected_notifications_string = NULL;
+ const char *use_action_group_value = NULL;
session_name = argv[1];
channel_name = argv[2];
session_name = argv[1];
channel_name = argv[2];
buffer_usage_threshold_type = argv[5];
buffer_usage_threshold_value = argv[6];
nr_expected_notifications_string = argv[7];
buffer_usage_threshold_type = argv[5];
buffer_usage_threshold_value = argv[6];
nr_expected_notifications_string = argv[7];
+ use_action_group_value = argv[8];
/* Parse arguments */
/* Domain type */
/* Parse arguments */
/* Domain type */
/* Number of notification to expect */
sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
/* Number of notification to expect */
sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
+ /* Put notify action in a group. */
+ if (!strcasecmp("1", use_action_group_value)) {
+ use_action_group = true;
+ }
+
return 0;
error:
return 1;
return 0;
error:
return 1;
{
int ret = 0;
enum lttng_condition_status condition_status;
{
int ret = 0;
enum lttng_condition_status condition_status;
+ enum lttng_action_status action_status;
enum lttng_notification_channel_status nc_status;
struct lttng_notification_channel *notification_channel = NULL;
struct lttng_condition *condition = NULL;
enum lttng_notification_channel_status nc_status;
struct lttng_notification_channel *notification_channel = NULL;
struct lttng_condition *condition = NULL;
printf("error: Missing arguments for tests\n");
ret = 1;
goto end;
printf("error: Missing arguments for tests\n");
ret = 1;
goto end;
- action = lttng_action_notify_create();
- if (!action) {
- printf("error: Could not create action notify\n");
- ret = 1;
- goto end;
+ if (use_action_group) {
+ struct lttng_action *notify, *group;
+
+ group = lttng_action_group_create();
+ if (!group) {
+ printf("error: Could not create action group\n");
+ ret = 1;
+ goto end;
+ }
+
+ notify = lttng_action_notify_create();
+ if (!notify) {
+ lttng_action_destroy(group);
+ printf("error: Could not create action notify\n");
+ ret = 1;
+ goto end;
+ }
+
+ action_status = lttng_action_group_add_action(group, notify);
+ if (action_status != LTTNG_ACTION_STATUS_OK) {
+ printf("error: Could not add action notify to action group\n");
+ lttng_action_destroy(group);
+ lttng_action_destroy(notify);
+ ret = 1;
+ goto end;
+ }
+
+ action = group;
+ } else {
+ action = lttng_action_notify_create();
+ if (!action) {
+ printf("error: Could not create action notify\n");
+ ret = 1;
+ goto end;
+ }
}
trigger = lttng_trigger_create(condition, action);
}
trigger = lttng_trigger_create(condition, action);
goto end;
default:
/* Unhandled conditions / errors. */
goto end;
default:
/* Unhandled conditions / errors. */
- printf("error: Unknown notification channel status\n");
+ printf("error: Unknown notification channel status (%d) \n", status);
local buffer_usage_threshold_type=$6
local buffer_usage_threshold_value=$7
local nr_expected_notification=$8
local buffer_usage_threshold_type=$6
local buffer_usage_threshold_value=$7
local nr_expected_notification=$8
+ local use_action_group=$9
- ${CURDIR}/base_client ${session_name} ${channel_name} ${domain_type} ${buffer_usage_type} ${buffer_usage_threshold_type} ${buffer_usage_threshold_value} ${nr_expected_notification} > ${output_file} &
+ ${CURDIR}/base_client ${session_name} ${channel_name} ${domain_type} ${buffer_usage_type} ${buffer_usage_threshold_type} ${buffer_usage_threshold_value} ${nr_expected_notification} ${use_action_group} > ${output_file} &
pid=$!
app_pids+=("$pid")
pid=$!
app_pids+=("$pid")
for (( i = 0; i < $nr_client_app; i++ )); do
low_app_output_file=$output_dir/${low_output_file_pattern}${i}
high_app_output_file=$output_dir/${high_output_file_pattern}${i}
for (( i = 0; i < $nr_client_app; i++ )); do
low_app_output_file=$output_dir/${low_output_file_pattern}${i}
high_app_output_file=$output_dir/${high_output_file_pattern}${i}
- start_client $low_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string LOW RATIO 0.0 $nr_notification_expected
- start_client $high_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 $nr_notification_expected
+ start_client $low_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string LOW RATIO 0.0 $nr_notification_expected $(( $i % 2))
+ start_client $high_app_output_file $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 $nr_notification_expected $(( $i % 2))
done
wait_for_message $output_dir "${low_output_file_pattern}" "sync: ready"
done
wait_for_message $output_dir "${low_output_file_pattern}" "sync: ready"
high_app_output_file=${high_output_file_pattern}.first_receiver
high_app_output_path=$output_dir/${high_app_output_file}
high_app_output_file=${high_output_file_pattern}.first_receiver
high_app_output_path=$output_dir/${high_app_output_file}
- start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+ start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1 0
wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
# notification on subscription
high_app_output_file=${high_output_file_pattern}.second_receiver
high_app_output_path=$output_dir/${high_app_output_file}
# notification on subscription
high_app_output_file=${high_output_file_pattern}.second_receiver
high_app_output_path=$output_dir/${high_app_output_file}
- start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1
+ start_client $high_app_output_path $SESSION_NAME $CHANNEL_NAME $domain_string HIGH RATIO 0.420 1 0
wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
wait_for_message $output_dir "${high_app_output_file}" "notification: high 0"
wait_for_message $output_dir "${high_app_output_file}" "sync: ready"
wait_for_message $output_dir "${high_app_output_file}" "notification: high 0"