Add client notification API
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 5 May 2017 03:08:47 +0000 (23:08 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 5 May 2017 04:15:01 +0000 (00:15 -0400)
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
36 files changed:
configure.ac
include/Makefile.am
include/lttng/action/action-internal.h [new file with mode: 0644]
include/lttng/action/action.h [new file with mode: 0644]
include/lttng/action/notify-internal.h [new file with mode: 0644]
include/lttng/action/notify.h [new file with mode: 0644]
include/lttng/condition/buffer-usage-internal.h [new file with mode: 0644]
include/lttng/condition/buffer-usage.h [new file with mode: 0644]
include/lttng/condition/condition-internal.h [new file with mode: 0644]
include/lttng/condition/condition.h [new file with mode: 0644]
include/lttng/condition/evaluation-internal.h [new file with mode: 0644]
include/lttng/condition/evaluation.h [new file with mode: 0644]
include/lttng/endpoint-internal.h [new file with mode: 0644]
include/lttng/endpoint.h [new file with mode: 0644]
include/lttng/lttng-error.h
include/lttng/lttng.h
include/lttng/notification/channel-internal.h [new file with mode: 0644]
include/lttng/notification/channel.h [new file with mode: 0644]
include/lttng/notification/notification-internal.h [new file with mode: 0644]
include/lttng/notification/notification.h [new file with mode: 0644]
include/lttng/trigger/trigger-internal.h [new file with mode: 0644]
include/lttng/trigger/trigger.h [new file with mode: 0644]
src/common/Makefile.am
src/common/action.c [new file with mode: 0644]
src/common/buffer-usage.c [new file with mode: 0644]
src/common/condition.c [new file with mode: 0644]
src/common/defaults.h
src/common/endpoint.c [new file with mode: 0644]
src/common/error.c
src/common/evaluation.c [new file with mode: 0644]
src/common/notification.c [new file with mode: 0644]
src/common/notify.c [new file with mode: 0644]
src/common/trigger.c [new file with mode: 0644]
src/lib/lttng-ctl/Makefile.am
src/lib/lttng-ctl/channel.c [new file with mode: 0644]
src/lib/lttng-ctl/lttng-ctl.c

index 0a7034e24eaaffd9f1c679b4eac896da18193045..9bc39412382261212197f78e9a9ce4b0bcdcb924 100644 (file)
@@ -948,8 +948,20 @@ CFLAGS="-Wall $CFLAGS -g -fno-strict-aliasing"
 DEFAULT_INCLUDES="-I\$(top_srcdir) -I\$(top_builddir) -I\$(top_builddir)/src -I\$(top_builddir)/include -include config.h"
 
 lttngincludedir="${includedir}/lttng"
-
 AC_SUBST(lttngincludedir)
+
+lttngactionincludedir="${includedir}/lttng/action"
+AC_SUBST(lttngactionincludedir)
+
+lttngconditionincludedir="${includedir}/lttng/condition"
+AC_SUBST(lttngconditionincludedir)
+
+lttngnotificationincludedir="${includedir}/lttng/notification"
+AC_SUBST(lttngnotificationincludedir)
+
+lttngtriggerincludedir="${includedir}/lttng/trigger"
+AC_SUBST(lttngtriggerincludedir)
+
 AC_SUBST(DEFAULT_INCLUDES)
 
 lttnglibexecdir="${libdir}/lttng/libexec"
index 0536dcdf00e328a1f83433df310e7a37c888c622..bc105b0649c482d0959aa35325c8cdc8909f3733 100644 (file)
@@ -77,10 +77,36 @@ lttnginclude_HEADERS = \
        lttng/snapshot.h \
        lttng/save.h \
        lttng/load.h \
+       lttng/endpoint.h \
        version.h.tmpl
 
+lttngactioninclude_HEADERS= \
+       lttng/action/action.h \
+       lttng/action/notify.h
+
+lttngconditioninclude_HEADERS= \
+       lttng/condition/condition.h \
+       lttng/condition/buffer-usage.h \
+       lttng/condition/evaluation.h
+
+lttngnotificationinclude_HEADERS= \
+       lttng/notification/channel.h \
+       lttng/notification/notification.h
+
+lttngtriggerinclude_HEADERS= \
+       lttng/trigger/trigger.h
+
 noinst_HEADERS = \
        lttng/snapshot-internal.h \
        lttng/health-internal.h \
        lttng/save-internal.h \
-       lttng/load-internal.h
+       lttng/load-internal.h \
+       lttng/action/action-internal.h \
+       lttng/action/notify-internal.h \
+       lttng/condition/condition-internal.h \
+       lttng/condition/buffer-usage-internal.h \
+       lttng/condition/evaluation-internal.h \
+       lttng/notification/notification-internal.h \
+       lttng/trigger/trigger-internal.h \
+       lttng/endpoint-internal.h \
+       lttng/notification/channel-internal.h
diff --git a/include/lttng/action/action-internal.h b/include/lttng/action/action-internal.h
new file mode 100644 (file)
index 0000000..746b0a4
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_INTERNAL_H
+#define LTTNG_ACTION_INTERNAL_H
+
+#include <lttng/action/action.h>
+#include <common/macros.h>
+#include <common/buffer-view.h>
+#include <stdbool.h>
+
+typedef bool (*action_validate_cb)(struct lttng_action *action);
+typedef void (*action_destroy_cb)(struct lttng_action *action);
+typedef ssize_t (*action_serialize_cb)(struct lttng_action *action, char *buf);
+
+struct lttng_action {
+       enum lttng_action_type type;
+       action_validate_cb validate;
+       action_serialize_cb serialize;
+       action_destroy_cb destroy;
+};
+
+struct lttng_action_comm {
+       /* enum lttng_action_type */
+       int8_t action_type;
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+bool lttng_action_validate(struct lttng_action *action);
+
+LTTNG_HIDDEN
+ssize_t lttng_action_serialize(struct lttng_action *action, char *buf);
+
+LTTNG_HIDDEN
+ssize_t lttng_action_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_action **action);
+
+#endif /* LTTNG_ACTION_INTERNAL_H */
diff --git a/include/lttng/action/action.h b/include/lttng/action/action.h
new file mode 100644 (file)
index 0000000..311f5a0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_H
+#define LTTNG_ACTION_H
+
+struct lttng_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum lttng_action_type {
+       LTTNG_ACTION_TYPE_UNKNOWN = -1,
+       LTTNG_ACTION_TYPE_NOTIFY = 0,
+};
+
+extern enum lttng_action_type lttng_action_get_type(
+               struct lttng_action *action);
+
+extern void lttng_action_destroy(struct lttng_action *action);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_H */
diff --git a/include/lttng/action/notify-internal.h b/include/lttng/action/notify-internal.h
new file mode 100644 (file)
index 0000000..509bd36
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_NOTIFY_INTERNAL_H
+#define LTTNG_ACTION_NOTIFY_INTERNAL_H
+
+#include <lttng/action/notify.h>
+#include <lttng/action/action-internal.h>
+
+struct lttng_action_notify {
+       struct lttng_action parent;
+};
+
+#endif /* LTTNG_ACTION_NOTIFY_INTERNAL_H */
diff --git a/include/lttng/action/notify.h b/include/lttng/action/notify.h
new file mode 100644 (file)
index 0000000..6c0d0ca
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ACTION_NOTIFY_H
+#define LTTNG_ACTION_NOTIFY_H
+
+struct lttng_action;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct lttng_action *lttng_action_notify_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_NOTIFY_H */
diff --git a/include/lttng/condition/buffer-usage-internal.h b/include/lttng/condition/buffer-usage-internal.h
new file mode 100644 (file)
index 0000000..4b605d6
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_BUFFER_USAGE_INTERNAL_H
+#define LTTNG_CONDITION_BUFFER_USAGE_INTERNAL_H
+
+#include <lttng/condition/buffer-usage.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/evaluation-internal.h>
+#include <lttng/domain.h>
+#include "common/buffer-view.h"
+
+struct lttng_condition_buffer_usage {
+       struct lttng_condition parent;
+       struct {
+               bool set;
+               uint64_t value;
+       } threshold_bytes;
+       struct {
+               bool set;
+               double value;
+       } threshold_ratio;
+       char *session_name;
+       char *channel_name;
+       struct {
+               bool set;
+               enum lttng_domain_type type;
+       } domain;
+};
+
+struct lttng_condition_buffer_usage_comm {
+       uint8_t threshold_set_in_bytes;
+       /*
+        * Expressed in bytes if "threshold_set_in_bytes" is not 0.
+        * Otherwise, it is expressed a ratio in the interval [0.0, 1.0]
+        * that is mapped to the range on a 32-bit unsigned integer.
+        * The ratio is obtained by (threshold / UINT32_MAX).
+        */
+       uint32_t threshold;
+       /* Both lengths include the trailing \0. */
+       uint32_t session_name_len;
+       uint32_t channel_name_len;
+       /* enum lttng_domain_type */
+       int8_t domain_type;
+       /* session and channel names. */
+       char names[];
+} LTTNG_PACKED;
+
+struct lttng_evaluation_buffer_usage {
+       struct lttng_evaluation parent;
+       uint64_t buffer_use;
+       uint64_t buffer_capacity;
+};
+
+struct lttng_evaluation_buffer_usage_comm {
+       uint64_t buffer_use;
+       uint64_t buffer_capacity;
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_buffer_usage_create(
+               enum lttng_condition_type type, uint64_t use,
+               uint64_t capacity);
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_buffer_usage_low_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_buffer_usage_high_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_buffer_usage_low_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_evaluation **evaluation);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_buffer_usage_high_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_evaluation **evaluation);
+
+#endif /* LTTNG_CONDITION_BUFFER_USAGE_INTERNAL_H */
diff --git a/include/lttng/condition/buffer-usage.h b/include/lttng/condition/buffer-usage.h
new file mode 100644 (file)
index 0000000..1463ef8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_BUFFER_USAGE_H
+#define LTTNG_CONDITION_BUFFER_USAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_condition;
+struct lttng_evaluation;
+
+extern struct lttng_condition *
+lttng_condition_buffer_usage_low_create(void);
+
+extern struct lttng_condition *
+lttng_condition_buffer_usage_high_create(void);
+
+/* threshold_ratio expressed as [0.0, 1.0]. */
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_get_threshold_ratio(
+               const struct lttng_condition *condition,
+               double *threshold_ratio);
+
+/* threshold_ratio expressed as [0.0, 1.0]. */
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_set_threshold_ratio(
+               struct lttng_condition *condition,
+               double threshold_ratio);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_get_threshold(
+               const struct lttng_condition *condition,
+               uint64_t *threshold_bytes);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_set_threshold(
+               struct lttng_condition *condition,
+               uint64_t threshold_bytes);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_get_session_name(
+               const struct lttng_condition *condition,
+               const char **session_name);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_set_session_name(
+               struct lttng_condition *condition,
+               const char *session_name);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_get_channel_name(
+               const struct lttng_condition *condition,
+               const char **channel_name);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_set_channel_name(
+               struct lttng_condition *condition,
+               const char *channel_name);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_get_domain_type(
+               const struct lttng_condition *condition,
+               enum lttng_domain_type *type);
+
+extern enum lttng_condition_status
+lttng_condition_buffer_usage_set_domain_type(
+               struct lttng_condition *condition,
+               enum lttng_domain_type type);
+
+
+/* LTTng Condition Evaluation */
+extern enum lttng_evaluation_status
+lttng_evaluation_buffer_usage_get_usage_ratio(
+               const struct lttng_evaluation *evaluation,
+               double *usage_ratio);
+
+extern enum lttng_evaluation_status
+lttng_evaluation_buffer_usage_get_usage(
+               const struct lttng_evaluation *evaluation,
+               uint64_t *usage_bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_CONDITION_BUFFER_USAGE_H */
diff --git a/include/lttng/condition/condition-internal.h b/include/lttng/condition/condition-internal.h
new file mode 100644 (file)
index 0000000..72a8922
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_INTERNAL_H
+#define LTTNG_CONDITION_INTERNAL_H
+
+#include <lttng/condition/condition.h>
+#include <common/macros.h>
+#include <common/buffer-view.h>
+#include <stdbool.h>
+#include <urcu/list.h>
+#include <stdint.h>
+
+typedef void (*condition_destroy_cb)(struct lttng_condition *condition);
+typedef bool (*condition_validate_cb)(const struct lttng_condition *condition);
+typedef ssize_t (*condition_serialize_cb)(
+               const struct lttng_condition *condition, char *buf);
+typedef bool (*condition_equal_cb)(const struct lttng_condition *a,
+               const struct lttng_condition *b);
+typedef ssize_t (*condition_create_from_buffer_cb)(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **condition);
+
+struct lttng_condition {
+       enum lttng_condition_type type;
+       condition_validate_cb validate;
+       condition_serialize_cb serialize;
+       condition_equal_cb equal;
+       condition_destroy_cb destroy;
+};
+
+struct lttng_condition_comm {
+       /* enum lttng_condition_type */
+       int8_t condition_type;
+       char payload[];
+};
+
+LTTNG_HIDDEN
+void lttng_condition_init(struct lttng_condition *condition,
+               enum lttng_condition_type type);
+
+LTTNG_HIDDEN
+bool lttng_condition_validate(const struct lttng_condition *condition);
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_create_from_buffer(
+               const struct lttng_buffer_view *buffer,
+               struct lttng_condition **condition);
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_serialize(const struct lttng_condition *condition,
+               char *buf);
+
+LTTNG_HIDDEN
+bool lttng_condition_is_equal(const struct lttng_condition *a,
+               const struct lttng_condition *b);
+
+#endif /* LTTNG_CONDITION_INTERNAL_H */
diff --git a/include/lttng/condition/condition.h b/include/lttng/condition/condition.h
new file mode 100644 (file)
index 0000000..38a071e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_CONDITION_H
+#define LTTNG_CONDITION_H
+
+#include <lttng/lttng.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_condition;
+
+enum lttng_condition_type {
+       LTTNG_CONDITION_TYPE_UNKNOWN = -1,
+       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW = 102,
+       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH = 101,
+};
+
+enum lttng_condition_status {
+       LTTNG_CONDITION_STATUS_OK = 0,
+       LTTNG_CONDITION_STATUS_ERROR = -1,
+       LTTNG_CONDITION_STATUS_UNKNOWN = -2,
+       LTTNG_CONDITION_STATUS_INVALID = -3,
+       LTTNG_CONDITION_STATUS_UNSET = -4,
+};
+
+extern enum lttng_condition_type lttng_condition_get_type(
+               const struct lttng_condition *condition);
+
+extern void lttng_condition_destroy(struct lttng_condition *condition);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_CONDITION_H */
diff --git a/include/lttng/condition/evaluation-internal.h b/include/lttng/condition/evaluation-internal.h
new file mode 100644 (file)
index 0000000..414760e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVALUATION_INTERNAL_H
+#define LTTNG_EVALUATION_INTERNAL_H
+
+#include <lttng/condition/evaluation.h>
+#include <common/macros.h>
+#include <common/buffer-view.h>
+#include <stdbool.h>
+
+typedef void (*evaluation_destroy_cb)(struct lttng_evaluation *evaluation);
+typedef ssize_t (*evaluation_serialize_cb)(struct lttng_evaluation *evaluation,
+               char *buf);
+
+struct lttng_evaluation_comm {
+       /* enum lttng_condition_type type */
+       int8_t type;
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_evaluation {
+       enum lttng_condition_type type;
+       evaluation_serialize_cb serialize;
+       evaluation_destroy_cb destroy;
+};
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_evaluation **evaluation);
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_serialize(struct lttng_evaluation *evaluation,
+               char *buf);
+
+#endif /* LTTNG_EVALUATION_INTERNAL_H */
diff --git a/include/lttng/condition/evaluation.h b/include/lttng/condition/evaluation.h
new file mode 100644 (file)
index 0000000..987fce3
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_EVALUATION_H
+#define LTTNG_EVALUATION_H
+
+#include <lttng/condition/condition.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_evaluation;
+
+enum lttng_evaluation_status {
+       LTTNG_EVALUATION_STATUS_OK = 0,
+       LTTNG_EVALUATION_STATUS_ERROR = -1,
+       LTTNG_EVALUATION_STATUS_INVALID = -2,
+       LTTNG_EVALUATION_STATUS_UNKNOWN = -2,
+       LTTNG_EVALUATION_STATUS_UNSET = -3,
+};
+
+extern enum lttng_condition_type lttng_evaluation_get_type(
+               const struct lttng_evaluation *evaluation);
+
+extern void lttng_evaluation_destroy(struct lttng_evaluation *evaluation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_EVALUATION_H */
diff --git a/include/lttng/endpoint-internal.h b/include/lttng/endpoint-internal.h
new file mode 100644 (file)
index 0000000..de6024b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ENDPOINT_INTERNAL_H
+#define LTTNG_ENDPOINT_INTERNAL_H
+
+#include <lttng/endpoint.h>
+#include <common/macros.h>
+
+enum lttng_endpoint_type {
+       LTTNG_ENDPOINT_TYPE_DEFAULT_SESSIOND_NOTIFICATION = 0,
+};
+
+struct lttng_endpoint {
+       enum lttng_endpoint_type type;
+};
+
+#endif /* LTTNG_ENDPOINT_INTERNAL_H */
diff --git a/include/lttng/endpoint.h b/include/lttng/endpoint.h
new file mode 100644 (file)
index 0000000..b93ed69
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_ENDPOINT_H
+#define LTTNG_ENDPOINT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Default LTTng session daemon endpoint singleton. */
+extern struct lttng_endpoint *lttng_session_daemon_notification_endpoint;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ENDPOINT_H */
index db6fe73c27741c2b269063519adda358bd91fea9..1b5ea699af63ef066e3b6ed7582f7d03a5eda13a 100644 (file)
@@ -145,6 +145,10 @@ enum lttng_error_code {
        LTTNG_ERR_REGEN_STATEDUMP_FAIL   = 122, /* Failed to regenerate the state dump */
        LTTNG_ERR_REGEN_STATEDUMP_NOMEM  = 123, /* Failed to regenerate the state dump, not enough memory */
        LTTNG_ERR_NOT_SNAPSHOT_SESSION   = 124, /* Session is not in snapshot mode. */
+       LTTNG_ERR_INVALID_TRIGGER        = 125, /* Invalid trigger provided. */
+       LTTNG_ERR_TRIGGER_EXISTS         = 126, /* Trigger already registered. */
+       LTTNG_ERR_TRIGGER_NOT_FOUND      = 127, /* Trigger not found. */
+       LTTNG_ERR_COMMAND_CANCELLED      = 128, /* Command cancelled. */
 
        /* MUST be last element */
        LTTNG_ERR_NR,                           /* Last element */
index 5478641b2eb66f0d6139281c2d4c7a61220f8cd4..72e8dcf0510d743dba5648e50343191cb8f044b8 100644 (file)
 #include <lttng/save.h>
 #include <lttng/session.h>
 #include <lttng/snapshot.h>
+#include <lttng/endpoint.h>
+#include <lttng/action/action.h>
+#include <lttng/action/notify.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/buffer-usage.h>
+#include <lttng/condition/evaluation.h>
+#include <lttng/notification/channel.h>
+#include <lttng/notification/notification.h>
+#include <lttng/trigger/trigger.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/lttng/notification/channel-internal.h b/include/lttng/notification/channel-internal.h
new file mode 100644 (file)
index 0000000..efe502f
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_NOTIFICATION_CHANNEL_INTERNAL_H
+#define LTTNG_NOTIFICATION_CHANNEL_INTERNAL_H
+
+#include <lttng/notification/channel.h>
+#include <common/macros.h>
+#include <common/dynamic-buffer.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <pthread.h>
+#include <urcu/list.h>
+
+#define LTTNG_NOTIFICATION_CHANNEL_VERSION_MAJOR 1
+#define LTTNG_NOTIFICATION_CHANNEL_VERSION_MINOR 0
+
+enum lttng_notification_channel_message_type {
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNKNOWN = -1,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE = 0,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE = 1,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE = 2,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_COMMAND_REPLY = 3,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION = 4,
+       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION_DROPPED = 5,
+};
+
+struct lttng_notification_channel_message {
+       /* enum lttng_notification_channel_message_type */
+       int8_t type;
+       /* Size of the payload following this field. */
+       uint32_t size;
+       char payload[];
+} LTTNG_PACKED;
+
+struct lttng_notification_channel_command_handshake {
+       uint8_t major;
+       uint8_t minor;
+} LTTNG_PACKED;
+
+struct lttng_notification_channel_command_reply {
+       /* enum lttng_notification_channel_status */
+       int8_t status;
+} LTTNG_PACKED;
+
+struct pending_notification {
+       /* NULL means "notification dropped". */
+       struct lttng_notification *notification;
+       struct cds_list_head node;
+};
+
+/*
+ * The notification channel protocol is bidirectional and accomodates
+ * synchronous and asynchronous communication modes:
+ *
+ *   - Synchronous: commands emitted by the client to which a reply is expected
+ *     (e.g. subscribing/unsubscribing to conditions),
+ *   - Asynchronous: notifications which are sent by the lttng_endpoint to the
+ *     client as one of the subscribed condition has occured.
+ *
+ * The nature of this hybrid communication mode means that asynchronous messages
+ * (e.g. notifications) may be interleaved between synchronous messages (e.g. a
+ * command and its reply).
+ *
+ * Notifications that are received between a command and its reply and enqueued
+ * in the pending_notifications list.
+ */
+struct lttng_notification_channel {
+       pthread_mutex_t lock;
+       int socket;
+       struct {
+               /* Count of pending notifications. */
+               unsigned int count;
+               /* List of struct pending_notification. */
+               struct cds_list_head list;
+       } pending_notifications;
+       struct lttng_dynamic_buffer reception_buffer;
+       /* Sessiond notification protocol version. */
+       struct {
+               bool set;
+               int8_t major, minor;
+       } version;
+};
+
+#endif /* LTTNG_NOTIFICATION_CHANNEL_INTERNAL_H */
diff --git a/include/lttng/notification/channel.h b/include/lttng/notification/channel.h
new file mode 100644 (file)
index 0000000..50334c5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_NOTIFICATION_CHANNEL_H
+#define LTTNG_NOTIFICATION_CHANNEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_endpoint;
+struct lttng_condition;
+struct lttng_notification;
+struct lttng_notification_channel;
+
+/* LTTng Notification channel */
+enum lttng_notification_channel_status {
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED = 1,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK = 0,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR = -1,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED = -2,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED = -3,
+       /* Condition unknown. */
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION = -4,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID = -5,
+       LTTNG_NOTIFICATION_CHANNEL_STATUS_UNSUPPORTED_VERSION = -6,
+};
+
+extern struct lttng_notification_channel *lttng_notification_channel_create(
+               struct lttng_endpoint *endpoint);
+
+extern enum lttng_notification_channel_status
+lttng_notification_channel_get_next_notification(
+               struct lttng_notification_channel *channel,
+               struct lttng_notification **notification);
+
+extern enum lttng_notification_channel_status
+lttng_notification_channel_subscribe(
+               struct lttng_notification_channel *channel,
+               const struct lttng_condition *condition);
+
+extern enum lttng_notification_channel_status
+lttng_notification_channel_unsubscribe(
+               struct lttng_notification_channel *channel,
+               const struct lttng_condition *condition);
+
+extern void lttng_notification_channel_destroy(
+               struct lttng_notification_channel *channel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_NOTIFICATION_CHANNEL_H */
diff --git a/include/lttng/notification/notification-internal.h b/include/lttng/notification/notification-internal.h
new file mode 100644 (file)
index 0000000..df9e8cb
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_NOTIFICATION_INTERNAL_H
+#define LTTNG_NOTIFICATION_INTERNAL_H
+
+#include <lttng/notification/notification.h>
+#include <common/macros.h>
+#include <common/buffer-view.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct lttng_notification {
+       struct lttng_condition *condition;
+       struct lttng_evaluation *evaluation;
+       /*
+        * The ownership of the notification's inner-elements depends
+        * on the way it was created. The notification owns both
+        * the condition and evaluation if it was obtained from a notification
+        * channel (i.e. created using lttng_notification_create_from_buffer)
+        * as the user may never access the condition and evaluation,
+        * thus never getting a chance to free them.
+        *
+        * However, when the _private_ lttng_notification_create() function
+        * is used, no ownership of condition and evaluation is assumed by
+        * the notification object. The main reason for this change in
+        * behavior is that internal users of this API only use the object
+        * to use its serialization facilities.
+        */
+       bool owns_elements;
+};
+
+struct lttng_notification_comm {
+       /* Size of the payload following this field. */
+       uint32_t length;
+       /* Condition and evaluation objects follow. */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+struct lttng_notification *lttng_notification_create(
+               struct lttng_condition *condition,
+               struct lttng_evaluation *evaluation);
+
+LTTNG_HIDDEN
+ssize_t lttng_notification_serialize(struct lttng_notification *notification,
+               char *buf);
+
+LTTNG_HIDDEN
+ssize_t lttng_notification_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_notification **notification);
+
+#endif /* LTTNG_NOTIFICATION_INTERNAL_H */
diff --git a/include/lttng/notification/notification.h b/include/lttng/notification/notification.h
new file mode 100644 (file)
index 0000000..dcaf974
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_NOTIFICATION_H
+#define LTTNG_NOTIFICATION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lttng_condition;
+struct lttng_evaluation;
+struct lttng_notification;
+
+/*
+ * The notification retains ownership of both the condition and evaluation.
+ * Destroying the notification will also destroy the notification and evaluation
+ * objects.
+ */
+extern const struct lttng_condition *lttng_notification_get_condition(
+               struct lttng_notification *notification);
+
+extern const struct lttng_evaluation *lttng_notification_get_evaluation(
+               struct lttng_notification *notification);
+
+extern void lttng_notification_destroy(struct lttng_notification *notification);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_NOTIFICATION_H */
diff --git a/include/lttng/trigger/trigger-internal.h b/include/lttng/trigger/trigger-internal.h
new file mode 100644 (file)
index 0000000..c92fa7d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_TRIGGER_INTERNAL_H
+#define LTTNG_TRIGGER_INTERNAL_H
+
+#include <lttng/trigger/trigger.h>
+#include <common/macros.h>
+#include <common/buffer-view.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+struct lttng_trigger {
+       struct lttng_condition *condition;
+       struct lttng_action *action;
+};
+
+struct lttng_trigger_comm {
+       /* length excludes its own length. */
+       uint32_t length;
+       /* A condition and action object follow. */
+       char payload[];
+} LTTNG_PACKED;
+
+LTTNG_HIDDEN
+ssize_t lttng_trigger_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_trigger **trigger);
+
+LTTNG_HIDDEN
+ssize_t lttng_trigger_serialize(struct lttng_trigger *trigger, char *buf);
+
+LTTNG_HIDDEN
+bool lttng_trigger_validate(struct lttng_trigger *trigger);
+
+#endif /* LTTNG_TRIGGER_INTERNAL_H */
diff --git a/include/lttng/trigger/trigger.h b/include/lttng/trigger/trigger.h
new file mode 100644 (file)
index 0000000..b2eab0e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef LTTNG_TRIGGER_H
+#define LTTNG_TRIGGER_H
+
+struct lttng_action;
+struct lttng_condition;
+struct lttng_trigger;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum lttng_register_trigger_status {
+       LTTNG_REGISTER_TRIGGER_STATUS_OK = 0,
+       LTTNG_REGISTER_TRIGGER_STATUS_INVALID = -1,
+};
+
+/* The caller retains the ownership of both condition and action. */
+extern struct lttng_trigger *lttng_trigger_create(
+               struct lttng_condition *condition, struct lttng_action *action);
+
+extern struct lttng_condition *lttng_trigger_get_condition(
+               struct lttng_trigger *trigger);
+
+extern struct lttng_action *lttng_trigger_get_action(
+               struct lttng_trigger *trigger);
+
+extern void lttng_trigger_destroy(struct lttng_trigger *trigger);
+
+extern int lttng_register_trigger(struct lttng_trigger *trigger);
+
+extern int lttng_unregister_trigger(struct lttng_trigger *trigger);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_TRIGGER_H */
index 83354d070ba6b755c663724731d308a5b7e93cea..2c734d7ecf6b38ce31da477db95b627a7cbbe376 100644 (file)
@@ -73,6 +73,9 @@ libcommon_la_SOURCES = error.h error.c utils.c utils.h runas.c runas.h \
                        mi-lttng.h mi-lttng.c \
                        daemonize.c daemonize.h \
                        unix.c unix.h \
+                       filter.c filter.h context.c context.h \
+                       action.c notify.c condition.c buffer-usage.c \
+                       evaluation.c notification.c trigger.c endpoint.c \
                        dynamic-buffer.h dynamic-buffer.c \
                        buffer-view.h buffer-view.c
 
diff --git a/src/common/action.c b/src/common/action.c
new file mode 100644 (file)
index 0000000..3abdfaf
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/action/action-internal.h>
+#include <lttng/action/notify-internal.h>
+#include <common/error.h>
+#include <assert.h>
+
+enum lttng_action_type lttng_action_get_type(struct lttng_action *action)
+{
+       return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN;
+}
+
+void lttng_action_destroy(struct lttng_action *action)
+{
+       if (!action) {
+               return;
+       }
+
+       assert(action->destroy);
+       action->destroy(action);
+}
+
+LTTNG_HIDDEN
+bool lttng_action_validate(struct lttng_action *action)
+{
+       bool valid;
+
+       if (!action) {
+               valid = false;
+               goto end;
+       }
+
+       if (!action->validate) {
+               /* Sub-class guarantees that it can never be invalid. */
+               valid = true;
+               goto end;
+       }
+
+       valid = action->validate(action);
+end:
+       return valid;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_action_serialize(struct lttng_action *action, char *buf)
+{
+       ssize_t ret, action_size;
+       struct lttng_action_comm action_comm;
+
+       if (!action) {
+               ret = -1;
+               goto end;
+       }
+
+       action_comm.action_type = (int8_t) action->type;
+       ret = sizeof(struct lttng_action_comm);
+       if (buf) {
+               memcpy(buf, &action_comm, ret);
+               buf += ret;
+       }
+
+       action_size = action->serialize(action, buf);
+       if (action_size < 0) {
+               ret = action_size;
+               goto end;
+       }
+       ret += action_size;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_action_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_action **_action)
+{
+       ssize_t ret, action_size = sizeof(struct lttng_action_comm);
+       struct lttng_action *action;
+       const struct lttng_action_comm *action_comm;
+
+       if (!view || !_action) {
+               ret = -1;
+               goto end;
+       }
+
+       action_comm = (const struct lttng_action_comm *) view->data;
+       DBG("Deserializing action from buffer");
+       switch (action_comm->action_type) {
+       case LTTNG_ACTION_TYPE_NOTIFY:
+               action = lttng_action_notify_create();
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+
+       if (!action) {
+               ret = -1;
+               goto end;
+       }
+       ret = action_size;
+       *_action = action;
+end:
+       return ret;
+}
diff --git a/src/common/buffer-usage.c b/src/common/buffer-usage.c
new file mode 100644 (file)
index 0000000..49696a3
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/buffer-usage-internal.h>
+#include <common/macros.h>
+#include <common/error.h>
+#include <assert.h>
+#include <math.h>
+#include <float.h>
+#include <time.h>
+
+#define IS_USAGE_CONDITION(condition) ( \
+       lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW || \
+       lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH   \
+       )
+
+static
+double fixed_to_double(uint32_t val)
+{
+       return (double) val / (double) UINT32_MAX;
+}
+
+static
+uint64_t double_to_fixed(double val)
+{
+       return (val * (double) UINT32_MAX);
+}
+
+static
+bool is_usage_evaluation(const struct lttng_evaluation *evaluation)
+{
+       enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
+
+       return type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW ||
+                       type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
+}
+
+static
+void lttng_condition_buffer_usage_destroy(struct lttng_condition *condition)
+{
+       struct lttng_condition_buffer_usage *usage;
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+
+       free(usage->session_name);
+       free(usage->channel_name);
+       free(usage);
+}
+
+static
+bool lttng_condition_buffer_usage_validate(
+               const struct lttng_condition *condition)
+{
+       bool valid = false;
+       struct lttng_condition_buffer_usage *usage;
+
+       if (!condition) {
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->session_name) {
+               ERR("Invalid buffer condition: a target session name must be set.");
+               goto end;
+       }
+       if (!usage->channel_name) {
+               ERR("Invalid buffer condition: a target channel name must be set.");
+               goto end;
+       }
+       if (!usage->threshold_ratio.set && !usage->threshold_bytes.set) {
+               ERR("Invalid buffer condition: a threshold must be set.");
+               goto end;
+       }
+
+       valid = true;
+end:
+       return valid;
+}
+
+static
+ssize_t lttng_condition_buffer_usage_serialize(
+               const struct lttng_condition *condition, char *buf)
+{
+       struct lttng_condition_buffer_usage *usage;
+       ssize_t ret, size;
+       size_t session_name_len, channel_name_len;
+
+       if (!condition || !IS_USAGE_CONDITION(condition)) {
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Serializing buffer usage condition");
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       size = sizeof(struct lttng_condition_buffer_usage_comm);
+       session_name_len = strlen(usage->session_name) + 1;
+       channel_name_len = strlen(usage->channel_name) + 1;
+       if (session_name_len > LTTNG_NAME_MAX ||
+                       channel_name_len > LTTNG_NAME_MAX) {
+               ret = -1;
+               goto end;
+       }
+       size += session_name_len + channel_name_len;
+       if (buf) {
+               struct lttng_condition_buffer_usage_comm usage_comm = {
+                       .threshold_set_in_bytes = usage->threshold_bytes.set ? 1 : 0,
+                       .session_name_len = session_name_len,
+                       .channel_name_len = channel_name_len,
+                       .domain_type = (int8_t) usage->domain.type,
+               };
+
+               if (usage->threshold_bytes.set) {
+                       usage_comm.threshold = usage->threshold_bytes.value;
+               } else {
+                       uint64_t val = double_to_fixed(
+                                       usage->threshold_ratio.value);
+
+                       if (val > UINT32_MAX) {
+                               /* overflow. */
+                               ret = -1;
+                               goto end;
+                       }
+                       usage_comm.threshold = val;
+               }
+
+               memcpy(buf, &usage_comm, sizeof(usage_comm));
+               buf += sizeof(usage_comm);
+               memcpy(buf, usage->session_name, session_name_len);
+               buf += session_name_len;
+               memcpy(buf, usage->channel_name, channel_name_len);
+               buf += channel_name_len;
+       }
+       ret = size;
+end:
+       return ret;
+}
+
+static
+bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition *_a,
+               const struct lttng_condition *_b)
+{
+       bool is_equal = false;
+       struct lttng_condition_buffer_usage *a, *b;
+
+       a = container_of(_a, struct lttng_condition_buffer_usage, parent);
+       b = container_of(_b, struct lttng_condition_buffer_usage, parent);
+
+       if ((a->threshold_ratio.set && !b->threshold_ratio.set) ||
+                       (a->threshold_bytes.set && !b->threshold_bytes.set)) {
+               goto end;
+       }
+
+       if (a->threshold_ratio.set && b->threshold_ratio.set) {
+               double a_value, b_value, diff;
+
+               a_value = a->threshold_ratio.value;
+               b_value = b->threshold_ratio.value;
+               diff = fabs(a_value - b_value);
+
+               if (diff > DBL_EPSILON) {
+                       goto end;
+               }
+       } else if (a->threshold_bytes.set && b->threshold_bytes.set) {
+               uint64_t a_value, b_value;
+
+               a_value = a->threshold_bytes.value;
+               b_value = b->threshold_bytes.value;
+               if (a_value != b_value) {
+                       goto end;
+               }
+       }
+
+       if ((a->session_name && !b->session_name) ||
+                       (!a->session_name && b->session_name)) {
+               goto end;
+       }
+
+       if (a->channel_name && b->channel_name) {
+               if (strcmp(a->channel_name, b->channel_name)) {
+                       goto end;
+               }
+       }       if ((a->channel_name && !b->channel_name) ||
+                       (!a->channel_name && b->channel_name)) {
+               goto end;
+       }
+
+       if (a->channel_name && b->channel_name) {
+               if (strcmp(a->channel_name, b->channel_name)) {
+                       goto end;
+               }
+       }
+
+       if ((a->domain.set && !b->domain.set) ||
+                       (!a->domain.set && b->domain.set)) {
+               goto end;
+       }
+
+       if (a->domain.set && b->domain.set) {
+               if (a->domain.type != b->domain.type) {
+                       goto end;
+               }
+       }
+       is_equal = true;
+end:
+       return is_equal;
+}
+
+static
+struct lttng_condition *lttng_condition_buffer_usage_create(
+               enum lttng_condition_type type)
+{
+       struct lttng_condition_buffer_usage *condition;
+
+       condition = zmalloc(sizeof(struct lttng_condition_buffer_usage));
+       if (!condition) {
+               goto end;
+       }
+
+       lttng_condition_init(&condition->parent, type);
+       condition->parent.validate = lttng_condition_buffer_usage_validate;
+       condition->parent.serialize = lttng_condition_buffer_usage_serialize;
+       condition->parent.equal = lttng_condition_buffer_usage_is_equal;
+       condition->parent.destroy = lttng_condition_buffer_usage_destroy;
+end:
+       return &condition->parent;
+}
+
+struct lttng_condition *lttng_condition_buffer_usage_low_create(void)
+{
+       return lttng_condition_buffer_usage_create(
+                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
+}
+
+struct lttng_condition *lttng_condition_buffer_usage_high_create(void)
+{
+       return lttng_condition_buffer_usage_create(
+                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
+}
+
+static
+ssize_t init_condition_from_buffer(struct lttng_condition *condition,
+               const struct lttng_buffer_view *src_view)
+{
+       ssize_t ret, condition_size;
+       enum lttng_condition_status status;
+       enum lttng_domain_type domain_type;
+       const struct lttng_condition_buffer_usage_comm *condition_comm;
+       const char *session_name, *channel_name;
+       struct lttng_buffer_view names_view;
+
+       if (src_view->size < sizeof(*condition_comm)) {
+               ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
+               ret = -1;
+               goto end;
+       }
+
+       condition_comm = (const struct lttng_condition_buffer_usage_comm *) src_view->data;
+       names_view = lttng_buffer_view_from_view(src_view,
+                       sizeof(*condition_comm), -1);
+
+       if (condition_comm->session_name_len > LTTNG_NAME_MAX ||
+                       condition_comm->channel_name_len > LTTNG_NAME_MAX) {
+               ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
+               ret = -1;
+               goto end;
+       }
+
+       if (names_view.size <
+                       (condition_comm->session_name_len +
+                       condition_comm->channel_name_len)) {
+               ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
+               ret = -1;
+               goto end;
+       }
+
+       if (condition_comm->threshold_set_in_bytes) {
+               status = lttng_condition_buffer_usage_set_threshold(condition,
+                               condition_comm->threshold);
+       } else {
+               status = lttng_condition_buffer_usage_set_threshold_ratio(
+                               condition,
+                               fixed_to_double(condition_comm->threshold));
+       }
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to initialize buffer usage condition threshold");
+               ret = -1;
+               goto end;
+       }
+
+       if (condition_comm->domain_type <= LTTNG_DOMAIN_NONE ||
+                       condition_comm->domain_type > LTTNG_DOMAIN_PYTHON) {
+               /* Invalid domain value. */
+               ERR("Invalid domain type value (%i) found in condition buffer",
+                               (int) condition_comm->domain_type);
+               ret = -1;
+               goto end;
+       }
+
+       domain_type = (enum lttng_domain_type) condition_comm->domain_type;
+       status = lttng_condition_buffer_usage_set_domain_type(condition,
+                       domain_type);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to set buffer usage condition domain");
+               ret = -1;
+               goto end;
+       }
+
+       session_name = names_view.data;
+       if (*(session_name + condition_comm->session_name_len - 1) != '\0') {
+               ERR("Malformed session name encountered in condition buffer");
+               ret = -1;
+               goto end;
+       }
+
+       channel_name = session_name + condition_comm->session_name_len;
+       if (*(channel_name + condition_comm->channel_name_len - 1) != '\0') {
+               ERR("Malformed channel name encountered in condition buffer");
+               ret = -1;
+               goto end;
+       }
+
+       status = lttng_condition_buffer_usage_set_session_name(condition,
+                       session_name);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to set buffer usage session name");
+               ret = -1;
+               goto end;
+       }
+
+       status = lttng_condition_buffer_usage_set_channel_name(condition,
+                       channel_name);
+       if (status != LTTNG_CONDITION_STATUS_OK) {
+               ERR("Failed to set buffer usage channel name");
+               ret = -1;
+               goto end;
+       }
+
+       if (!lttng_condition_validate(condition)) {
+               ret = -1;
+               goto end;
+       }
+
+       condition_size = sizeof(*condition_comm) +
+                       (ssize_t) condition_comm->session_name_len +
+                       (ssize_t) condition_comm->channel_name_len;
+       ret = condition_size;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_buffer_usage_low_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **_condition)
+{
+       ssize_t ret;
+       struct lttng_condition *condition =
+                       lttng_condition_buffer_usage_low_create();
+
+       if (!_condition || !condition) {
+               ret = -1;
+               goto error;
+       }
+
+       ret = init_condition_from_buffer(condition, view);
+       if (ret < 0) {
+               goto error;
+       }
+
+       *_condition = condition;
+       return ret;
+error:
+       lttng_condition_destroy(condition);
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_buffer_usage_high_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_condition **_condition)
+{
+       ssize_t ret;
+       struct lttng_condition *condition =
+                       lttng_condition_buffer_usage_high_create();
+
+       if (!_condition || !condition) {
+               ret = -1;
+               goto error;
+       }
+
+       ret = init_condition_from_buffer(condition, view);
+       if (ret < 0) {
+               goto error;
+       }
+
+       *_condition = condition;
+       return ret;
+error:
+       lttng_condition_destroy(condition);
+       return ret;
+}
+
+static
+struct lttng_evaluation *create_evaluation_from_buffer(
+               enum lttng_condition_type type,
+               const struct lttng_buffer_view *view)
+{
+       const struct lttng_evaluation_buffer_usage_comm *comm =
+                       (const struct lttng_evaluation_buffer_usage_comm *) view->data;
+       struct lttng_evaluation *evaluation = NULL;
+
+       if (view->size < sizeof(*comm)) {
+               goto end;
+       }
+
+       evaluation = lttng_evaluation_buffer_usage_create(type,
+                       comm->buffer_use, comm->buffer_capacity);
+end:
+       return evaluation;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_buffer_usage_low_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_evaluation **_evaluation)
+{
+       ssize_t ret;
+       struct lttng_evaluation *evaluation = NULL;
+
+       if (!_evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       evaluation = create_evaluation_from_buffer(
+                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW, view);
+       if (!evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       *_evaluation = evaluation;
+       ret = sizeof(struct lttng_evaluation_buffer_usage_comm);
+       return ret;
+error:
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_buffer_usage_high_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               struct lttng_evaluation **_evaluation)
+{
+       ssize_t ret;
+       struct lttng_evaluation *evaluation = NULL;
+
+       if (!_evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       evaluation = create_evaluation_from_buffer(
+                       LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH, view);
+       if (!evaluation) {
+               ret = -1;
+               goto error;
+       }
+
+       *_evaluation = evaluation;
+       ret = sizeof(struct lttng_evaluation_buffer_usage_comm);
+       return ret;
+error:
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_get_threshold_ratio(
+               const struct lttng_condition *condition,
+               double *threshold_ratio)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) ||
+                       !threshold_ratio) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->threshold_ratio.set) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+       *threshold_ratio = usage->threshold_ratio.value;
+end:
+       return status;
+}
+
+/* threshold_ratio expressed as [0.0, 1.0]. */
+enum lttng_condition_status
+lttng_condition_buffer_usage_set_threshold_ratio(
+               struct lttng_condition *condition, double threshold_ratio)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) ||
+                       threshold_ratio < 0.0 ||
+                       threshold_ratio > 1.0) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       usage->threshold_ratio.set = true;
+       usage->threshold_bytes.set = false;
+       usage->threshold_ratio.value = threshold_ratio;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_get_threshold(
+               const struct lttng_condition *condition,
+               uint64_t *threshold_bytes)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !threshold_bytes) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->threshold_bytes.set) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+       *threshold_bytes = usage->threshold_bytes.value;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_set_threshold(
+               struct lttng_condition *condition, uint64_t threshold_bytes)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition)) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       usage->threshold_ratio.set = false;
+       usage->threshold_bytes.set = true;
+       usage->threshold_bytes.value = threshold_bytes;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_get_session_name(
+               const struct lttng_condition *condition,
+               const char **session_name)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !session_name) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->session_name) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+       *session_name = usage->session_name;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_set_session_name(
+               struct lttng_condition *condition, const char *session_name)
+{
+       char *session_name_copy;
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !session_name ||
+                       strlen(session_name) == 0) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       session_name_copy = strdup(session_name);
+       if (!session_name_copy) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+       if (usage->session_name) {
+               free(usage->session_name);
+       }
+       usage->session_name = session_name_copy;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_get_channel_name(
+               const struct lttng_condition *condition,
+               const char **channel_name)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !channel_name) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->channel_name) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+       *channel_name = usage->channel_name;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_set_channel_name(
+               struct lttng_condition *condition, const char *channel_name)
+{
+       char *channel_name_copy;
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !channel_name ||
+                       strlen(channel_name) == 0) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       channel_name_copy = strdup(channel_name);
+       if (!channel_name_copy) {
+               status = LTTNG_CONDITION_STATUS_ERROR;
+               goto end;
+       }
+
+       if (usage->channel_name) {
+               free(usage->channel_name);
+       }
+       usage->channel_name = channel_name_copy;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_get_domain_type(
+               const struct lttng_condition *condition,
+               enum lttng_domain_type *type)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) || !type) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       if (!usage->domain.set) {
+               status = LTTNG_CONDITION_STATUS_UNSET;
+               goto end;
+       }
+       *type = usage->domain.type;
+end:
+       return status;
+}
+
+enum lttng_condition_status
+lttng_condition_buffer_usage_set_domain_type(
+               struct lttng_condition *condition, enum lttng_domain_type type)
+{
+       struct lttng_condition_buffer_usage *usage;
+       enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
+
+       if (!condition || !IS_USAGE_CONDITION(condition) ||
+                       type == LTTNG_DOMAIN_NONE) {
+               status = LTTNG_CONDITION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(condition, struct lttng_condition_buffer_usage,
+                       parent);
+       usage->domain.set = true;
+       usage->domain.type = type;
+end:
+       return status;
+}
+
+static
+ssize_t lttng_evaluation_buffer_usage_serialize(
+               struct lttng_evaluation *evaluation, char *buf)
+{
+       ssize_t ret;
+       struct lttng_evaluation_buffer_usage *usage;
+
+       usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
+                       parent);
+       if (buf) {
+               struct lttng_evaluation_buffer_usage_comm comm = {
+                       .buffer_use = usage->buffer_use,
+                       .buffer_capacity = usage->buffer_capacity,
+               };
+
+               memcpy(buf, &comm, sizeof(comm));
+       }
+
+       ret = sizeof(struct lttng_evaluation_buffer_usage_comm);
+       return ret;
+}
+
+static
+void lttng_evaluation_buffer_usage_destroy(
+               struct lttng_evaluation *evaluation)
+{
+       struct lttng_evaluation_buffer_usage *usage;
+
+       usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
+                       parent);
+       free(usage);
+}
+
+LTTNG_HIDDEN
+struct lttng_evaluation *lttng_evaluation_buffer_usage_create(
+               enum lttng_condition_type type, uint64_t use, uint64_t capacity)
+{
+       struct lttng_evaluation_buffer_usage *usage;
+
+       usage = zmalloc(sizeof(struct lttng_evaluation_buffer_usage));
+       if (!usage) {
+               goto end;
+       }
+
+       usage->parent.type = type;
+       usage->buffer_use = use;
+       usage->buffer_capacity = capacity;
+       usage->parent.serialize = lttng_evaluation_buffer_usage_serialize;
+       usage->parent.destroy = lttng_evaluation_buffer_usage_destroy;
+end:
+       return &usage->parent;
+}
+
+/*
+ * Get the sampled buffer usage which caused the associated condition to
+ * evaluate to "true".
+ */
+enum lttng_evaluation_status
+lttng_evaluation_buffer_usage_get_usage_ratio(
+               const struct lttng_evaluation *evaluation, double *usage_ratio)
+{
+       struct lttng_evaluation_buffer_usage *usage;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_usage_evaluation(evaluation) || !usage_ratio) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
+                       parent);
+       *usage_ratio = (double) usage->buffer_use /
+                       (double) usage->buffer_capacity;
+end:
+       return status;
+}
+
+enum lttng_evaluation_status
+lttng_evaluation_buffer_usage_get_usage(
+               const struct lttng_evaluation *evaluation,
+               uint64_t *usage_bytes)
+{
+       struct lttng_evaluation_buffer_usage *usage;
+       enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
+
+       if (!evaluation || !is_usage_evaluation(evaluation) || !usage_bytes) {
+               status = LTTNG_EVALUATION_STATUS_INVALID;
+               goto end;
+       }
+
+       usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
+                       parent);
+       *usage_bytes = usage->buffer_use;
+end:
+       return status;
+}
diff --git a/src/common/condition.c b/src/common/condition.c
new file mode 100644 (file)
index 0000000..0b18442
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/buffer-usage-internal.h>
+#include <common/macros.h>
+#include <common/error.h>
+#include <common/dynamic-buffer.h>
+#include <common/buffer-view.h>
+#include <stdbool.h>
+#include <assert.h>
+
+enum lttng_condition_type lttng_condition_get_type(
+               const struct lttng_condition *condition)
+{
+       return condition ? condition->type : LTTNG_CONDITION_TYPE_UNKNOWN;
+}
+
+void lttng_condition_destroy(struct lttng_condition *condition)
+{
+       if (!condition) {
+               return;
+       }
+
+       assert(condition->destroy);
+       condition->destroy(condition);
+}
+
+LTTNG_HIDDEN
+bool lttng_condition_validate(const struct lttng_condition *condition)
+{
+       bool valid;
+
+       if (!condition) {
+               valid = false;
+               goto end;
+       }
+
+       if (!condition->validate) {
+               /* Sub-class guarantees that it can never be invalid. */
+               valid = true;
+               goto end;
+       }
+
+       valid = condition->validate(condition);
+end:
+       return valid;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_serialize(const struct lttng_condition *condition,
+               char *buf)
+{
+       ssize_t ret, condition_size;
+       struct lttng_condition_comm condition_comm;
+
+       if (!condition) {
+               ret = -1;
+               goto end;
+       }
+
+       condition_comm.condition_type = (int8_t) condition->type;
+       ret = sizeof(struct lttng_condition_comm);
+       if (buf) {
+               memcpy(buf, &condition_comm, ret);
+               buf += ret;
+       }
+
+       condition_size = condition->serialize(condition, buf);
+       if (condition_size < 0) {
+               ret = condition_size;
+               goto end;
+       }
+       ret += condition_size;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+bool lttng_condition_is_equal(const struct lttng_condition *a,
+               const struct lttng_condition *b)
+{
+       bool is_equal = false;
+
+       if (!a || !b) {
+               goto end;
+       }
+
+       if (a->type != b->type) {
+               goto end;
+       }
+
+       is_equal = a->equal ? a->equal(a, b) : true;
+end:
+       return is_equal;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_condition_create_from_buffer(
+               const struct lttng_buffer_view *buffer,
+               struct lttng_condition **condition)
+{
+       ssize_t ret, condition_size = 0;
+       const struct lttng_condition_comm *condition_comm;
+       condition_create_from_buffer_cb create_from_buffer = NULL;
+
+       if (!buffer || !condition) {
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Deserializing condition from buffer");
+       condition_comm = (const struct lttng_condition_comm *) buffer->data;
+       condition_size += sizeof(*condition_comm);
+
+       switch ((enum lttng_condition_type) condition_comm->condition_type) {
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+               create_from_buffer = lttng_condition_buffer_usage_low_create_from_buffer;
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+               create_from_buffer = lttng_condition_buffer_usage_high_create_from_buffer;
+               break;
+       default:
+               ERR("Attempted to create condition of unknown type (%i)",
+                               (int) condition_comm->condition_type);
+               ret = -1;
+               goto end;
+       }
+
+       if (create_from_buffer) {
+               const struct lttng_buffer_view view =
+                               lttng_buffer_view_from_view(buffer,
+                                       sizeof(*condition_comm), -1);
+
+               ret = create_from_buffer(&view, condition);
+               if (ret < 0) {
+                       goto end;
+               }
+               condition_size += ret;
+
+       } else {
+               abort();
+       }
+
+       ret = condition_size;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+void lttng_condition_init(struct lttng_condition *condition,
+               enum lttng_condition_type type)
+{
+       condition->type = type;
+}
index 37d222a784fd0b3564a35b3a845fb8fe88b956e2..818332f54f146adc52e812a51c2677cb2649647c 100644 (file)
 #define DEFAULT_LTTNG_EXTRA_KMOD_PROBES                "LTTNG_EXTRA_KMOD_PROBES"
 
 /* Default unix socket path */
-#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK         DEFAULT_LTTNG_RUNDIR "/client-lttng-sessiond"
-#define DEFAULT_HOME_CLIENT_UNIX_SOCK           DEFAULT_LTTNG_HOME_RUNDIR "/client-lttng-sessiond"
-#define DEFAULT_GLOBAL_HEALTH_UNIX_SOCK         DEFAULT_LTTNG_RUNDIR "/sessiond-health"
-#define DEFAULT_HOME_HEALTH_UNIX_SOCK          DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-health"
+#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK                DEFAULT_LTTNG_RUNDIR "/client-lttng-sessiond"
+#define DEFAULT_HOME_CLIENT_UNIX_SOCK                  DEFAULT_LTTNG_HOME_RUNDIR "/client-lttng-sessiond"
+#define DEFAULT_GLOBAL_HEALTH_UNIX_SOCK                DEFAULT_LTTNG_RUNDIR "/sessiond-health"
+#define DEFAULT_HOME_HEALTH_UNIX_SOCK                  DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-health"
+#define DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK   DEFAULT_LTTNG_RUNDIR "/sessiond-notification"
+#define DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK    DEFAULT_LTTNG_HOME_RUNDIR "/sessiond-notification"
 
 /* Default consumer health unix socket path */
 #define DEFAULT_GLOBAL_USTCONSUMER32_HEALTH_UNIX_SOCK  DEFAULT_LTTNG_RUNDIR "/ustconsumerd32/health"
 /* Default thread stack size; the default mandated by pthread_create(3) */
 #define DEFAULT_LTTNG_THREAD_STACK_SIZE                2097152
 
+/* Default maximal size of message notification channel message payloads. */
+#define DEFAULT_MAX_NOTIFICATION_CLIENT_MESSAGE_PAYLOAD_SIZE   65536
+
+/* Default maximal size of message notification channel message payloads. */
+#define DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT          100
+
 /*
  * Returns the default subbuf size.
  *
diff --git a/src/common/endpoint.c b/src/common/endpoint.c
new file mode 100644 (file)
index 0000000..89066de
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/endpoint-internal.h>
+
+static
+struct lttng_endpoint lttng_session_daemon_notification_endpoint_instance = {
+       .type = LTTNG_ENDPOINT_TYPE_DEFAULT_SESSIOND_NOTIFICATION
+};
+
+struct lttng_endpoint *lttng_session_daemon_notification_endpoint =
+               &lttng_session_daemon_notification_endpoint_instance;
index 938932cdc7b5cbd6ab03a1789cf9330712a8b5f2..2215886db1be67d5c93e3b89233c8e101f26a96d 100644 (file)
@@ -186,6 +186,10 @@ static const char *error_string_array[] = {
        [ ERROR_INDEX(LTTNG_ERR_REGEN_STATEDUMP_FAIL) ] = "Failed to regenerate the state dump",
        [ ERROR_INDEX(LTTNG_ERR_REGEN_STATEDUMP_NOMEM) ] = "Failed to regenerate the state dump, not enough memory",
        [ ERROR_INDEX(LTTNG_ERR_NOT_SNAPSHOT_SESSION) ] = "Snapshot command can't be applied to a non-snapshot session",
+       [ ERROR_INDEX(LTTNG_ERR_INVALID_TRIGGER) ] = "Invalid trigger",
+       [ ERROR_INDEX(LTTNG_ERR_TRIGGER_EXISTS) ] = "Trigger already registered",
+       [ ERROR_INDEX(LTTNG_ERR_TRIGGER_NOT_FOUND) ] = "Trigger not found",
+       [ ERROR_INDEX(LTTNG_ERR_COMMAND_CANCELLED) ] = "Command cancelled",
 
        /* Last element */
        [ ERROR_INDEX(LTTNG_ERR_NR) ] = "Unknown error code"
diff --git a/src/common/evaluation.c b/src/common/evaluation.c
new file mode 100644 (file)
index 0000000..c6243d2
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/condition/evaluation-internal.h>
+#include <lttng/condition/buffer-usage-internal.h>
+#include <common/macros.h>
+#include <common/error.h>
+#include <stdbool.h>
+#include <assert.h>
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_serialize(struct lttng_evaluation *evaluation,
+               char *buf)
+{
+       ssize_t ret, offset = 0;
+       struct lttng_evaluation_comm evaluation_comm;
+
+       evaluation_comm.type = (int8_t) evaluation->type;
+       if (buf) {
+               memcpy(buf, &evaluation_comm, sizeof(evaluation_comm));
+       }
+       offset += sizeof(evaluation_comm);
+
+       if (evaluation->serialize) {
+               ret = evaluation->serialize(evaluation,
+                               buf ? (buf + offset) : NULL);
+               if (ret < 0) {
+                       goto end;
+               }
+               offset += ret;
+       }
+
+       ret = offset;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_evaluation_create_from_buffer(
+               const struct lttng_buffer_view *src_view,
+               struct lttng_evaluation **evaluation)
+{
+       ssize_t ret, evaluation_size = 0;
+       const struct lttng_evaluation_comm *evaluation_comm;
+       const struct lttng_buffer_view evaluation_view =
+                       lttng_buffer_view_from_view(src_view,
+                       sizeof(*evaluation_comm), -1);
+
+       if (!src_view || !evaluation) {
+               ret = -1;
+               goto end;
+       }
+
+       evaluation_comm = (const struct lttng_evaluation_comm *) src_view->data;
+       evaluation_size += sizeof(*evaluation_comm);
+
+       switch ((enum lttng_condition_type) evaluation_comm->type) {
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+               ret = lttng_evaluation_buffer_usage_low_create_from_buffer(
+                               &evaluation_view, evaluation);
+               if (ret < 0) {
+                       goto end;
+               }
+               evaluation_size += ret;
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+               ret = lttng_evaluation_buffer_usage_high_create_from_buffer(
+                               &evaluation_view, evaluation);
+               if (ret < 0) {
+                       goto end;
+               }
+               evaluation_size += ret;
+               break;
+       default:
+               ERR("Attempted to create evaluation of unknown type (%i)",
+                               (int) evaluation_comm->type);
+               ret = -1;
+               goto end;
+       }
+       ret = evaluation_size;
+end:
+       return ret;
+}
+
+enum lttng_condition_type lttng_evaluation_get_type(
+               const struct lttng_evaluation *evaluation)
+{
+       return evaluation ? evaluation->type : LTTNG_CONDITION_TYPE_UNKNOWN;
+}
+
+void lttng_evaluation_destroy(struct lttng_evaluation *evaluation)
+{
+       if (!evaluation) {
+               return;
+       }
+
+       assert(evaluation->destroy);
+       evaluation->destroy(evaluation);
+}
diff --git a/src/common/notification.c b/src/common/notification.c
new file mode 100644 (file)
index 0000000..5062ca5
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/notification/notification-internal.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/condition/evaluation-internal.h>
+#include <lttng/condition/condition.h>
+#include <lttng/condition/evaluation.h>
+#include <assert.h>
+
+LTTNG_HIDDEN
+struct lttng_notification *lttng_notification_create(
+               struct lttng_condition *condition,
+               struct lttng_evaluation *evaluation)
+{
+       struct lttng_notification *notification = NULL;
+
+       if (!condition || !evaluation) {
+               goto end;
+       }
+
+       notification = zmalloc(sizeof(struct lttng_notification));
+       if (!notification) {
+               goto end;
+       }
+
+       notification->condition = condition;
+       notification->evaluation = evaluation;
+       notification->owns_elements = false;
+end:
+       return notification;
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_notification_serialize(struct lttng_notification *notification,
+               char *buf)
+{
+       ssize_t ret, condition_size, evaluation_size, offset = 0;
+       struct lttng_notification_comm notification_comm;
+
+       if (!notification) {
+               ret = -1;
+               goto end;
+       }
+
+       offset += sizeof(notification_comm);
+       condition_size = lttng_condition_serialize(notification->condition,
+                       buf ? (buf + offset) : NULL);
+       if (condition_size < 0) {
+               ret = condition_size;
+               goto end;
+       }
+       offset += condition_size;
+
+       evaluation_size = lttng_evaluation_serialize(notification->evaluation,
+                       buf ? (buf + offset) : NULL);
+       if (evaluation_size < 0) {
+               ret = evaluation_size;
+               goto end;
+       }
+       offset += evaluation_size;
+
+       if (buf) {
+               notification_comm.length =
+                               (uint32_t) (condition_size + evaluation_size);
+               memcpy(buf, &notification_comm, sizeof(notification_comm));
+       }
+       ret = offset;
+end:
+       return ret;
+
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_notification_create_from_buffer(
+               const struct lttng_buffer_view *src_view,
+               struct lttng_notification **notification)
+{
+       ssize_t ret, notification_size = 0, condition_size, evaluation_size;
+       const struct lttng_notification_comm *notification_comm;
+       struct lttng_condition *condition;
+       struct lttng_evaluation *evaluation;
+       struct lttng_buffer_view condition_view;
+       struct lttng_buffer_view evaluation_view;
+
+       if (!src_view || !notification) {
+               ret = -1;
+               goto end;
+       }
+
+       notification_comm =
+                       (const struct lttng_notification_comm *) src_view->data;
+       notification_size += sizeof(*notification_comm);
+
+       /* struct lttng_condition */
+       condition_view = lttng_buffer_view_from_view(src_view,
+                       sizeof(*notification_comm), -1);
+       condition_size = lttng_condition_create_from_buffer(&condition_view,
+                       &condition);
+       if (condition_size < 0) {
+               ret = condition_size;
+               goto end;
+       }
+       notification_size += condition_size;
+
+       /* struct lttng_evaluation */
+       evaluation_view = lttng_buffer_view_from_view(&condition_view,
+                       condition_size, -1);
+       evaluation_size = lttng_evaluation_create_from_buffer(&evaluation_view,
+                       &evaluation);
+       if (evaluation_size < 0) {
+               ret = evaluation_size;
+               goto end;
+       }
+       notification_size += evaluation_size;
+
+       /* Unexpected size of inner-elements; the buffer is corrupted. */
+       if ((ssize_t) notification_comm->length !=
+                       condition_size + evaluation_size) {
+               ret = -1;
+               goto error;
+       }
+
+       *notification = lttng_notification_create(condition, evaluation);
+       if (!*notification) {
+               ret = -1;
+               goto error;
+       }
+       ret = notification_size;
+       (*notification)->owns_elements = true;
+end:
+       return ret;
+error:
+       lttng_condition_destroy(condition);
+       lttng_evaluation_destroy(evaluation);
+       return ret;
+}
+
+void lttng_notification_destroy(struct lttng_notification *notification)
+{
+       if (!notification) {
+               return;
+       }
+
+       if (notification->owns_elements) {
+               lttng_condition_destroy(notification->condition);
+               lttng_evaluation_destroy(notification->evaluation);
+       }
+       free(notification);
+}
+
+const struct lttng_condition *lttng_notification_get_condition(
+               struct lttng_notification *notification)
+{
+       return notification ? notification->condition : NULL;
+}
+
+const struct lttng_evaluation *lttng_notification_get_evaluation(
+               struct lttng_notification *notification)
+{
+       return notification ? notification->evaluation : NULL;
+}
diff --git a/src/common/notify.c b/src/common/notify.c
new file mode 100644 (file)
index 0000000..956c0ec
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/action/action-internal.h>
+#include <lttng/action/notify-internal.h>
+#include <common/macros.h>
+#include <assert.h>
+
+static
+void lttng_action_notify_destroy(struct lttng_action *action)
+{
+       free(action);
+}
+
+static
+ssize_t lttng_action_notify_serialize(struct lttng_action *action, char *buf)
+{
+       return 0;
+}
+
+struct lttng_action *lttng_action_notify_create(void)
+{
+       struct lttng_action_notify *notify;
+
+       notify = zmalloc(sizeof(struct lttng_action_notify));
+       if (!notify) {
+               goto end;
+       }
+
+       notify->parent.type = LTTNG_ACTION_TYPE_NOTIFY;
+       notify->parent.serialize = lttng_action_notify_serialize;
+       notify->parent.destroy = lttng_action_notify_destroy;
+end:
+       return &notify->parent;
+}
diff --git a/src/common/trigger.c b/src/common/trigger.c
new file mode 100644 (file)
index 0000000..13f26d6
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/trigger/trigger-internal.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/action/action-internal.h>
+#include <common/error.h>
+#include <assert.h>
+
+LTTNG_HIDDEN
+bool lttng_trigger_validate(struct lttng_trigger *trigger)
+{
+       bool valid;
+
+       if (!trigger) {
+               valid = false;
+               goto end;
+       }
+
+       valid = lttng_condition_validate(trigger->condition) &&
+                       lttng_action_validate(trigger->action);
+end:
+       return valid;
+}
+
+struct lttng_trigger *lttng_trigger_create(
+               struct lttng_condition *condition,
+               struct lttng_action *action)
+{
+       struct lttng_trigger *trigger = NULL;
+
+       if (!condition || !action) {
+               goto end;
+       }
+
+       trigger = zmalloc(sizeof(struct lttng_trigger));
+       if (!trigger) {
+               goto end;
+       }
+
+       trigger->condition = condition;
+       trigger->action = action;
+end:
+       return trigger;
+}
+
+struct lttng_condition *lttng_trigger_get_condition(
+               struct lttng_trigger *trigger)
+{
+       return trigger ? trigger->condition : NULL;
+}
+
+extern struct lttng_action *lttng_trigger_get_action(
+               struct lttng_trigger *trigger)
+{
+       return trigger ? trigger->action : NULL;
+}
+
+void lttng_trigger_destroy(struct lttng_trigger *trigger)
+{
+       if (!trigger) {
+               return;
+       }
+
+       free(trigger);
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_trigger_create_from_buffer(
+               const struct lttng_buffer_view *src_view,
+               struct lttng_trigger **trigger)
+{
+       ssize_t ret, offset = 0, condition_size, action_size;
+       struct lttng_condition *condition = NULL;
+       struct lttng_action *action = NULL;
+       const struct lttng_trigger_comm *trigger_comm;
+       struct lttng_buffer_view condition_view;
+       struct lttng_buffer_view action_view;
+
+       if (!src_view || !trigger) {
+               ret = -1;
+               goto end;
+       }
+
+       /* lttng_trigger_comm header */
+       trigger_comm = (const struct lttng_trigger_comm *) src_view->data;
+       offset += sizeof(*trigger_comm);
+
+       condition_view = lttng_buffer_view_from_view(src_view, offset, -1);
+
+       /* struct lttng_condition */
+       condition_size = lttng_condition_create_from_buffer(&condition_view,
+                       &condition);
+       if (condition_size < 0) {
+               ret = condition_size;
+               goto end;
+       }
+       offset += condition_size;
+
+       /* struct lttng_action */
+       action_view = lttng_buffer_view_from_view(src_view, offset, -1);
+       action_size = lttng_action_create_from_buffer(&action_view, &action);
+       if (action_size < 0) {
+               ret = action_size;
+               goto end;
+       }
+       offset += action_size;
+
+       /* Unexpected size of inner-elements; the buffer is corrupted. */
+       if ((ssize_t) trigger_comm->length != condition_size + action_size) {
+               ret = -1;
+               goto error;
+       }
+
+       *trigger = lttng_trigger_create(condition, action);
+       if (!*trigger) {
+               ret = -1;
+               goto error;
+       }
+       ret = offset;
+end:
+       return ret;
+error:
+       lttng_condition_destroy(condition);
+       lttng_action_destroy(action);
+       return ret;
+}
+
+/*
+ * Returns the size of a trigger (header + condition + action).
+ * Both elements are stored contiguously, see their "*_comm" structure
+ * for the detailed format.
+ */
+LTTNG_HIDDEN
+ssize_t lttng_trigger_serialize(struct lttng_trigger *trigger, char *buf)
+{
+       struct lttng_trigger_comm trigger_comm;
+       ssize_t action_size, condition_size, offset = 0, ret;
+
+       if (!trigger) {
+               ret = -1;
+               goto end;
+       }
+
+       offset += sizeof(trigger_comm);
+       condition_size = lttng_condition_serialize(trigger->condition,
+                       buf ? (buf + offset) : NULL);
+       if (condition_size < 0) {
+               ret = -1;
+               goto end;
+       }
+       offset += condition_size;
+
+       action_size = lttng_action_serialize(trigger->action,
+                       buf ? (buf + offset) : NULL);
+       if (action_size < 0) {
+               ret = -1;
+               goto end;
+       }
+       offset += action_size;
+
+       if (buf) {
+               trigger_comm.length = (uint32_t) (condition_size + action_size);
+               memcpy(buf, &trigger_comm, sizeof(trigger_comm));
+       }
+       ret = offset;
+end:
+       return ret;
+}
index 6b6a6eed127525f17a2a94454ea18e8fbf3dacc1..b5156caf94aa9320a2712a7525a5138bff1b4b74 100644 (file)
@@ -5,7 +5,8 @@ SUBDIRS = filter
 lib_LTLIBRARIES = liblttng-ctl.la
 
 liblttng_ctl_la_SOURCES = lttng-ctl.c snapshot.c lttng-ctl-helper.h \
-               lttng-ctl-health.c save.c load.c deprecated-symbols.c
+               lttng-ctl-health.c save.c load.c deprecated-symbols.c \
+               channel.c
 
 liblttng_ctl_la_LDFLAGS = \
                $(LT_NO_UNDEFINED)
diff --git a/src/lib/lttng-ctl/channel.c b/src/lib/lttng-ctl/channel.c
new file mode 100644 (file)
index 0000000..75a911f
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/notification/notification-internal.h>
+#include <lttng/notification/channel-internal.h>
+#include <lttng/condition/condition-internal.h>
+#include <lttng/endpoint.h>
+#include <common/defaults.h>
+#include <common/error.h>
+#include <common/dynamic-buffer.h>
+#include <common/utils.h>
+#include <common/defaults.h>
+#include <assert.h>
+#include "lttng-ctl-helper.h"
+
+static
+int handshake(struct lttng_notification_channel *channel);
+
+/*
+ * Populates the reception buffer with the next complete message.
+ * The caller must acquire the client's lock.
+ */
+static
+int receive_message(struct lttng_notification_channel *channel)
+{
+       ssize_t ret;
+       struct lttng_notification_channel_message msg;
+
+       ret = lttng_dynamic_buffer_set_size(&channel->reception_buffer, 0);
+       if (ret) {
+               goto error;
+       }
+
+       ret = lttcomm_recv_unix_sock(channel->socket, &msg, sizeof(msg));
+       if (ret <= 0) {
+               ret = -1;
+               goto error;
+       }
+
+       if (msg.size > DEFAULT_MAX_NOTIFICATION_CLIENT_MESSAGE_PAYLOAD_SIZE) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Add message header at buffer's start. */
+       ret = lttng_dynamic_buffer_append(&channel->reception_buffer, &msg,
+                       sizeof(msg));
+       if (ret) {
+               goto error;
+       }
+
+       /* Reserve space for the payload. */
+       ret = lttng_dynamic_buffer_set_size(&channel->reception_buffer,
+                       channel->reception_buffer.size + msg.size);
+       if (ret) {
+               goto error;
+       }
+
+       /* Receive message payload. */
+       ret = lttcomm_recv_unix_sock(channel->socket,
+                       channel->reception_buffer.data + sizeof(msg), msg.size);
+       if (ret < (ssize_t) msg.size) {
+               ret = -1;
+               goto error;
+       }
+       ret = 0;
+end:
+       return ret;
+error:
+       lttng_dynamic_buffer_set_size(&channel->reception_buffer, 0);
+       goto end;
+}
+
+static
+enum lttng_notification_channel_message_type get_current_message_type(
+               struct lttng_notification_channel *channel)
+{
+       struct lttng_notification_channel_message *msg;
+
+       assert(channel->reception_buffer.size >= sizeof(*msg));
+
+       msg = (struct lttng_notification_channel_message *)
+                       channel->reception_buffer.data;
+       return (enum lttng_notification_channel_message_type) msg->type;
+}
+
+static
+struct lttng_notification *create_notification_from_current_message(
+               struct lttng_notification_channel *channel)
+{
+       ssize_t ret;
+       struct lttng_notification *notification = NULL;
+       struct lttng_buffer_view view;
+
+       if (channel->reception_buffer.size <=
+                       sizeof(struct lttng_notification_channel_message)) {
+               goto end;
+       }
+
+       view = lttng_buffer_view_from_dynamic_buffer(&channel->reception_buffer,
+                       sizeof(struct lttng_notification_channel_message), -1);
+
+       ret = lttng_notification_create_from_buffer(&view, &notification);
+       if (ret != channel->reception_buffer.size -
+                       sizeof(struct lttng_notification_channel_message)) {
+               lttng_notification_destroy(notification);
+               notification = NULL;
+               goto end;
+       }
+end:
+       return notification;
+}
+
+struct lttng_notification_channel *lttng_notification_channel_create(
+               struct lttng_endpoint *endpoint)
+{
+       int fd, ret;
+       bool is_in_tracing_group = false, is_root = false;
+       char *sock_path = NULL;
+       struct lttng_notification_channel *channel = NULL;
+
+       if (!endpoint ||
+                       endpoint != lttng_session_daemon_notification_endpoint) {
+               goto end;
+       }
+
+       sock_path = zmalloc(LTTNG_PATH_MAX);
+       if (!sock_path) {
+               goto end;
+       }
+
+       channel = zmalloc(sizeof(struct lttng_notification_channel));
+       if (!channel) {
+               goto end;
+       }
+       channel->socket = -1;
+       pthread_mutex_init(&channel->lock, NULL);
+       lttng_dynamic_buffer_init(&channel->reception_buffer);
+       CDS_INIT_LIST_HEAD(&channel->pending_notifications.list);
+
+       is_root = (getuid() == 0);
+       if (!is_root) {
+               is_in_tracing_group = lttng_check_tracing_group();
+       }
+
+       if (is_root || is_in_tracing_group) {
+               lttng_ctl_copy_string(sock_path,
+                               DEFAULT_GLOBAL_NOTIFICATION_CHANNEL_UNIX_SOCK,
+                               LTTNG_PATH_MAX);
+               ret = lttcomm_connect_unix_sock(sock_path);
+               if (ret >= 0) {
+                       fd = ret;
+                       goto set_fd;
+               }
+       }
+
+       /* Fallback to local session daemon. */
+       ret = snprintf(sock_path, LTTNG_PATH_MAX,
+                       DEFAULT_HOME_NOTIFICATION_CHANNEL_UNIX_SOCK,
+                       utils_get_home_dir());
+       if (ret < 0 || ret >= LTTNG_PATH_MAX) {
+               goto error;
+       }
+
+       ret = lttcomm_connect_unix_sock(sock_path);
+       if (ret < 0) {
+               goto error;
+       }
+       fd = ret;
+
+set_fd:
+       channel->socket = fd;
+
+       ret = handshake(channel);
+       if (ret) {
+               goto error;
+       }
+end:
+       free(sock_path);
+       return channel;
+error:
+       lttng_notification_channel_destroy(channel);
+       channel = NULL;
+       goto end;
+}
+
+enum lttng_notification_channel_status
+lttng_notification_channel_get_next_notification(
+               struct lttng_notification_channel *channel,
+               struct lttng_notification **_notification)
+{
+       int ret;
+       struct lttng_notification *notification = NULL;
+       enum lttng_notification_channel_status status =
+                       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
+
+       if (!channel || !_notification) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
+               goto end;
+       }
+
+       if (channel->pending_notifications.count) {
+               struct pending_notification *pending_notification;
+
+               assert(!cds_list_empty(&channel->pending_notifications.list));
+
+               /* Deliver one of the pending notifications. */
+               pending_notification = cds_list_first_entry(
+                               &channel->pending_notifications.list,
+                               struct pending_notification,
+                               node);
+               notification = pending_notification->notification;
+               if (!notification) {
+                       status = LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED;
+               }
+               cds_list_del(&pending_notification->node);
+               channel->pending_notifications.count--;
+               free(pending_notification);
+               goto end;
+       }
+
+       pthread_mutex_lock(&channel->lock);
+
+       ret = receive_message(channel);
+       if (ret) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
+               goto end_unlock;
+       }
+
+       switch (get_current_message_type(channel)) {
+       case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION:
+               notification = create_notification_from_current_message(
+                               channel);
+               if (!notification) {
+                       status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
+                       goto end_unlock;
+               }
+               break;
+       case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION_DROPPED:
+               /* No payload to consume. */
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED;
+               break;
+       default:
+               /* Protocol error. */
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
+               goto end_unlock;
+       }
+
+end_unlock:
+       pthread_mutex_unlock(&channel->lock);
+end:
+       if (_notification) {
+               *_notification = notification;
+       }
+       return status;
+}
+
+static
+int enqueue_dropped_notification(
+               struct lttng_notification_channel *channel)
+{
+       int ret = 0;
+       struct pending_notification *pending_notification;
+       struct cds_list_head *last_element =
+                       channel->pending_notifications.list.prev;
+
+       pending_notification = caa_container_of(last_element,
+                       struct pending_notification, node);
+       if (!pending_notification->notification) {
+               /*
+                * The last enqueued notification indicates dropped
+                * notifications; there is nothing to do as we group
+                * dropped notifications together.
+                */
+               goto end;
+       }
+
+       if (channel->pending_notifications.count >=
+                       DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT &&
+                       pending_notification->notification) {
+               /*
+                * Discard the last enqueued notification to indicate
+                * that notifications were dropped at this point.
+                */
+               lttng_notification_destroy(
+                               pending_notification->notification);
+               pending_notification->notification = NULL;
+               goto end;
+       }
+
+       pending_notification = zmalloc(sizeof(*pending_notification));
+       if (!pending_notification) {
+               ret = -1;
+               goto end;
+       }
+       CDS_INIT_LIST_HEAD(&pending_notification->node);
+       cds_list_add(&pending_notification->node,
+                       &channel->pending_notifications.list);
+       channel->pending_notifications.count++;
+end:
+       return ret;
+}
+
+static
+int enqueue_notification_from_current_message(
+               struct lttng_notification_channel *channel)
+{
+       int ret = 0;
+       struct lttng_notification *notification;
+       struct pending_notification *pending_notification;
+
+       if (channel->pending_notifications.count >=
+                       DEFAULT_CLIENT_MAX_QUEUED_NOTIFICATIONS_COUNT) {
+               /* Drop the notification. */
+               ret = enqueue_dropped_notification(channel);
+               goto end;
+       }
+
+       pending_notification = zmalloc(sizeof(*pending_notification));
+       if (!pending_notification) {
+               ret = -1;
+               goto error;
+       }
+       CDS_INIT_LIST_HEAD(&pending_notification->node);
+
+       notification = create_notification_from_current_message(channel);
+       if (!notification) {
+               ret = -1;
+               goto error;
+       }
+
+       pending_notification->notification = notification;
+       cds_list_add(&pending_notification->node,
+                       &channel->pending_notifications.list);
+       channel->pending_notifications.count++;
+end:
+       return ret;
+error:
+       free(pending_notification);
+       goto end;
+}
+
+static
+int receive_command_reply(struct lttng_notification_channel *channel,
+               enum lttng_notification_channel_status *status)
+{
+       int ret;
+       struct lttng_notification_channel_command_reply *reply;
+
+       while (true) {
+               enum lttng_notification_channel_message_type msg_type;
+
+               ret = receive_message(channel);
+               if (ret) {
+                       goto end;
+               }
+
+               msg_type = get_current_message_type(channel);
+               switch (msg_type) {
+               case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_COMMAND_REPLY:
+                       goto exit_loop;
+               case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION:
+                       ret = enqueue_notification_from_current_message(
+                                       channel);
+                       if (ret) {
+                               goto end;
+                       }
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION_DROPPED:
+                       ret = enqueue_dropped_notification(channel);
+                       if (ret) {
+                               goto end;
+                       }
+                       break;
+               case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE:
+               {
+                       struct lttng_notification_channel_command_handshake *handshake;
+
+                       handshake = (struct lttng_notification_channel_command_handshake *)
+                                       (channel->reception_buffer.data +
+                                       sizeof(struct lttng_notification_channel_message));
+                       channel->version.major = handshake->major;
+                       channel->version.minor = handshake->minor;
+                       channel->version.set = true;
+                       break;
+               }
+               default:
+                       ret = -1;
+                       goto end;
+               }
+       }
+
+exit_loop:
+       if (channel->reception_buffer.size <
+                       (sizeof(struct lttng_notification_channel_message) +
+                       sizeof(*reply))) {
+               /* Invalid message received. */
+               ret = -1;
+               goto end;
+       }
+
+       reply = (struct lttng_notification_channel_command_reply *)
+                       (channel->reception_buffer.data +
+                       sizeof(struct lttng_notification_channel_message));
+       *status = (enum lttng_notification_channel_status) reply->status;
+end:
+       return ret;
+}
+
+static
+int handshake(struct lttng_notification_channel *channel)
+{
+       ssize_t ret;
+       enum lttng_notification_channel_status status =
+                       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
+       struct lttng_notification_channel_command_handshake handshake = {
+               .major = LTTNG_NOTIFICATION_CHANNEL_VERSION_MAJOR,
+               .minor = LTTNG_NOTIFICATION_CHANNEL_VERSION_MINOR,
+       };
+       struct lttng_notification_channel_message msg_header = {
+               .type = LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE,
+               .size = sizeof(handshake),
+       };
+       char send_buffer[sizeof(msg_header) + sizeof(handshake)];
+
+       memcpy(send_buffer, &msg_header, sizeof(msg_header));
+       memcpy(send_buffer + sizeof(msg_header), &handshake, sizeof(handshake));
+
+       pthread_mutex_lock(&channel->lock);
+
+       ret = lttcomm_send_unix_sock(channel->socket, send_buffer,
+                       sizeof(send_buffer));
+       if (ret < 0) {
+               goto end_unlock;
+       }
+
+       /* Receive handshake info from the sessiond. */
+       ret = receive_command_reply(channel, &status);
+       if (ret < 0) {
+               goto end_unlock;
+       }
+
+       if (!channel->version.set) {
+               ret = -1;
+               goto end_unlock;
+       }
+
+       if (channel->version.major != LTTNG_NOTIFICATION_CHANNEL_VERSION_MAJOR) {
+               ret = -1;
+               goto end_unlock;
+       }
+
+end_unlock:
+       pthread_mutex_unlock(&channel->lock);
+       return ret;
+}
+
+static
+enum lttng_notification_channel_status send_condition_command(
+               struct lttng_notification_channel *channel,
+               enum lttng_notification_channel_message_type type,
+               const struct lttng_condition *condition)
+{
+       int socket;
+       ssize_t command_size, ret;
+       enum lttng_notification_channel_status status =
+                       LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
+       char *command_buffer = NULL;
+       struct lttng_notification_channel_message cmd_message = {
+               .type = type,
+       };
+
+       if (!channel) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
+               goto end;
+       }
+
+       assert(type == LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE ||
+               type == LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE);
+
+       pthread_mutex_lock(&channel->lock);
+       socket = channel->socket;
+       if (!lttng_condition_validate(condition)) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
+               goto end_unlock;
+       }
+
+       ret = lttng_condition_serialize(condition, NULL);
+       if (ret < 0) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_INVALID;
+               goto end_unlock;
+       }
+       assert(ret < UINT32_MAX);
+       cmd_message.size = (uint32_t) ret;
+       command_size = ret + sizeof(
+                       struct lttng_notification_channel_message);
+       command_buffer = zmalloc(command_size);
+       if (!command_buffer) {
+               goto end_unlock;
+       }
+
+       memcpy(command_buffer, &cmd_message, sizeof(cmd_message));
+       ret = lttng_condition_serialize(condition,
+                       command_buffer + sizeof(cmd_message));
+       if (ret < 0) {
+               goto end_unlock;
+       }
+
+       ret = lttcomm_send_unix_sock(socket, command_buffer, command_size);
+       if (ret < 0) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
+               goto end_unlock;
+       }
+
+       ret = receive_command_reply(channel, &status);
+       if (ret < 0) {
+               status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ERROR;
+               goto end_unlock;
+       }
+end_unlock:
+       pthread_mutex_unlock(&channel->lock);
+end:
+       free(command_buffer);
+       return status;
+}
+
+enum lttng_notification_channel_status lttng_notification_channel_subscribe(
+               struct lttng_notification_channel *channel,
+               const struct lttng_condition *condition)
+{
+       return send_condition_command(channel,
+                       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE,
+                       condition);
+}
+
+enum lttng_notification_channel_status lttng_notification_channel_unsubscribe(
+               struct lttng_notification_channel *channel,
+               const struct lttng_condition *condition)
+{
+       return send_condition_command(channel,
+                       LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE,
+                       condition);
+}
+
+void lttng_notification_channel_destroy(
+               struct lttng_notification_channel *channel)
+{
+       if (!channel) {
+               return;
+       }
+
+       if (channel->socket >= 0) {
+               (void) lttcomm_close_unix_sock(channel->socket);
+       }
+       pthread_mutex_destroy(&channel->lock);
+       lttng_dynamic_buffer_reset(&channel->reception_buffer);
+       free(channel);
+}
index f0b211c7b4a426e959855637ce23d7c08496143d..4e1665f401a333719b7220638e43a80c95cee4a6 100644 (file)
@@ -36,6 +36,9 @@
 #include <common/utils.h>
 #include <lttng/lttng.h>
 #include <lttng/health-internal.h>
+#include <lttng/trigger/trigger-internal.h>
+#include <lttng/endpoint.h>
+#include <lttng/channel-internal.h>
 
 #include "filter/filter-ast.h"
 #include "filter/filter-parser.h"
@@ -2435,6 +2438,94 @@ end:
        return ret;
 }
 
+int lttng_register_trigger(struct lttng_trigger *trigger)
+{
+       int ret;
+       struct lttcomm_session_msg lsm;
+       char *trigger_buf = NULL;
+       ssize_t trigger_size;
+
+       if (!trigger) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       if (!lttng_trigger_validate(trigger)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       trigger_size = lttng_trigger_serialize(trigger, NULL);
+       if (trigger_size < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       trigger_buf = zmalloc(trigger_size);
+       if (!trigger_buf) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_REGISTER_TRIGGER;
+       if (lttng_trigger_serialize(trigger, trigger_buf) < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       lsm.u.trigger.length = (uint32_t) trigger_size;
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, trigger_buf,
+                       trigger_size, NULL);
+end:
+       free(trigger_buf);
+       return ret;
+}
+
+int lttng_unregister_trigger(struct lttng_trigger *trigger)
+{
+       int ret;
+       struct lttcomm_session_msg lsm;
+       char *trigger_buf = NULL;
+       ssize_t trigger_size;
+
+       if (!trigger) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       if (!lttng_trigger_validate(trigger)) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       trigger_size = lttng_trigger_serialize(trigger, NULL);
+       if (trigger_size < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       trigger_buf = zmalloc(trigger_size);
+       if (!trigger_buf) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       memset(&lsm, 0, sizeof(lsm));
+       lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER;
+       if (lttng_trigger_serialize(trigger, trigger_buf) < 0) {
+               ret = -LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       lsm.u.trigger.length = (uint32_t) trigger_size;
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, trigger_buf,
+                       trigger_size, NULL);
+end:
+       free(trigger_buf);
+       return ret;
+}
+
 /*
  * lib constructor.
  */
This page took 0.090827 seconds and 4 git commands to generate.