} u;
} LTTNG_PACKED;
+#define LTTNG_UST_EVENT_NOTIFIER_PADDING1 16
+struct lttng_ust_event_notifier {
+ struct lttng_ust_event event;
+ char padding[LTTNG_UST_EVENT_NOTIFIER_PADDING1];
+} LTTNG_PACKED;
+
+#define LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING 32
+struct lttng_ust_event_notifier_notification {
+ uint64_t token;
+ char padding[LTTNG_EVENT_NOTIFIER_NOTIFICATION_PADDING];
+} LTTNG_PACKED;
+
enum lttng_ust_field_type {
LTTNG_UST_FIELD_OTHER = 0,
LTTNG_UST_FIELD_INTEGER = 1,
LTTNG_UST_OBJECT_TYPE_STREAM = 1,
LTTNG_UST_OBJECT_TYPE_EVENT = 2,
LTTNG_UST_OBJECT_TYPE_CONTEXT = 3,
+ LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER_GROUP = 4,
+ LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER = 5,
};
#define LTTNG_UST_OBJECT_DATA_PADDING1 32
#define LTTNG_UST_WAIT_QUIESCENT _UST_CMD(0x43)
#define LTTNG_UST_REGISTER_DONE _UST_CMD(0x44)
#define LTTNG_UST_TRACEPOINT_FIELD_LIST _UST_CMD(0x45)
+#define LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE _UST_CMD(0x46)
/* Session FD commands */
#define LTTNG_UST_CHANNEL \
#define LTTNG_UST_FILTER _UST_CMD(0xA0)
#define LTTNG_UST_EXCLUSION _UST_CMD(0xA1)
+/* Event notifier group commands */
+#define LTTNG_UST_EVENT_NOTIFIER_CREATE \
+ _UST_CMDW(0xB0, struct lttng_ust_event_notifier)
+
#define LTTNG_UST_ROOT_HANDLE 0
struct lttng_ust_obj;
struct {
char *ctxname;
} app_context;
+ struct {
+ int event_notifier_notif_fd;
+ } event_notifier_handle;
};
struct lttng_ust_objd_ops {
int ustctl_start_session(int sock, int handle);
int ustctl_stop_session(int sock, int handle);
+/*
+ * ustctl_create_event notifier_group creates a event notifier group. It
+ * establishes the connection with the application by providing a file
+ * descriptor of the pipe to be used by the application when a event notifier
+ * of that group is fired. It returns a handle to be used when creating event
+ * notifier in that group.
+ */
+int ustctl_create_event_notifier_group(int sock, int pipe_fd,
+ struct lttng_ust_object_data **event_notifier_group);
+
+/*
+ * ustctl_create_event notifier creates a event notifier in a event notifier
+ * group giving a event notifier description and a event notifier group handle.
+ * It returns a event notifier handle to be used when enabling the event
+ * notifier, attaching filter, attaching exclusion, and disabling the event
+ * notifier.
+ */
+int ustctl_create_event_notifier(int sock,
+ struct lttng_ust_event_notifier *event_notifier,
+ struct lttng_ust_object_data *event_notifier_group,
+ struct lttng_ust_object_data **event_notifier_data);
+
/*
* ustctl_tracepoint_list returns a tracepoint list handle, or negative
* error value.
union {
struct {
const char **model_emf_uri;
+ void (*event_notifier_callback)(void);
} ext;
char padding[LTTNG_UST_EVENT_DESC_PADDING];
} u;
int link_failed;
struct cds_list_head node; /* list of bytecode runtime in event */
/*
- * Pointer to a `struct lttng_session`-owned and URCU-protected
- * pointer.
+ * Pointer to a URCU-protected pointer owned by an `struct
+ * lttng_session`or `struct lttng_event_notifier_group`.
*/
struct lttng_ctx **pctx;
};
/*
- * Objects in a linked-list of enablers, owned by an event.
+ * Objects in a linked-list of enablers, owned by an event or event_notifier.
+ * This is used because an event (or a event_notifier) can be enabled by more
+ * than one enabler and we want a quick way to iterate over all enablers of an
+ * object.
+ *
+ * For example, event rules "my_app:a*" and "my_app:ab*" will both match the
+ * event with the name "my_app:abc".
*/
struct lttng_enabler_ref {
struct cds_list_head node; /* enabler ref list */
int registered; /* has reg'd tracepoint probe */
};
+struct lttng_event_notifier {
+ uint64_t user_token;
+ int enabled;
+ int registered; /* has reg'd tracepoint probe */
+ struct cds_list_head filter_bytecode_runtime_head;
+ int has_enablers_without_bytecode;
+ struct cds_list_head enablers_ref_head;
+ const struct lttng_event_desc *desc;
+ struct cds_hlist_node hlist; /* hashtable of event_notifiers */
+ struct cds_list_head node; /* event_notifier list in session */
+ struct lttng_event_notifier_group *group; /* weak ref */
+};
+
struct lttng_enum {
const struct lttng_enum_desc *desc;
struct lttng_session *session;
struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE];
};
+#define LTTNG_UST_EVENT_NOTIFIER_HT_BITS 12
+#define LTTNG_UST_EVENT_NOTIFIER_HT_SIZE (1U << LTTNG_UST_EVENT_NOTIFIER_HT_BITS)
+struct lttng_ust_event_notifier_ht {
+ struct cds_hlist_head table[LTTNG_UST_EVENT_NOTIFIER_HT_SIZE];
+};
+
#define LTTNG_UST_ENUM_HT_BITS 12
#define LTTNG_UST_ENUM_HT_SIZE (1U << LTTNG_UST_ENUM_HT_BITS)
struct lttng_ctx *ctx; /* contexts for filters. */
};
+struct lttng_event_notifier_group {
+ int objd;
+ void *owner;
+ int notification_fd;
+ struct cds_list_head node; /* Event notifier group handle list */
+ struct cds_list_head enablers_head;
+ struct cds_list_head event_notifiers_head; /* list of event_notifiers */
+ struct lttng_ust_event_notifier_ht event_notifiers_ht; /* hashtable of event_notifiers */
+ struct lttng_ctx *ctx; /* contexts for filters. */
+};
+
struct lttng_transport {
char *name;
struct cds_list_head node;
int lttng_session_statedump(struct lttng_session *session);
void lttng_session_destroy(struct lttng_session *session);
+void lttng_event_notifier_notification_send(
+ struct lttng_event_notifier *event_notifier);
+
struct lttng_channel *lttng_channel_create(struct lttng_session *session,
const char *transport_name,
void *buf_addr,
#include TRACEPOINT_INCLUDE
+/*
+ * Stage 2.1 of tracepoint event generation.
+ *
+ * Create probe event notifier callback prototypes.
+ */
+
+/* Reset all macros within TRACEPOINT_EVENT */
+#include <lttng/ust-tracepoint-event-reset.h>
+
+#undef TP_ARGS
+#define TP_ARGS(...) __VA_ARGS__
+
+#undef TRACEPOINT_EVENT_CLASS
+#define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \
+static void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args));
+
+#include TRACEPOINT_INCLUDE
+
/*
* Stage 3.0 of tracepoint event generation.
*
#undef _TP_EXTRACT_STRING2
+/*
+ * Stage 5.2 of tracepoint event generation.
+ *
+ * Create the event notifier probe function.
+ */
+#undef TRACEPOINT_EVENT_CLASS
+#define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \
+static lttng_ust_notrace \
+void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \
+static \
+void __event_notifier_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \
+{ \
+ struct lttng_event_notifier *__event_notifier = (struct lttng_event_notifier *) __tp_data; \
+ const size_t __num_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1;\
+ union { \
+ size_t __dynamic_len[__num_fields]; \
+ char __filter_stack_data[2 * sizeof(unsigned long) * __num_fields]; \
+ } __stackvar; \
+ if (caa_unlikely(!CMM_ACCESS_ONCE(__event_notifier->enabled))) \
+ return; \
+ if (caa_unlikely(!TP_RCU_LINK_TEST())) \
+ return; \
+ if (caa_unlikely(!cds_list_empty(&__event_notifier->filter_bytecode_runtime_head))) { \
+ struct lttng_bytecode_runtime *__filter_bc_runtime; \
+ int __filter_record = __event_notifier->has_enablers_without_bytecode; \
+ \
+ __event_prepare_filter_stack__##_provider##___##_name(__stackvar.__filter_stack_data, \
+ _TP_ARGS_DATA_VAR(_args)); \
+ tp_list_for_each_entry_rcu(__filter_bc_runtime, &__event_notifier->filter_bytecode_runtime_head, node) { \
+ if (caa_unlikely(__filter_bc_runtime->filter(__filter_bc_runtime, \
+ __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \
+ __filter_record = 1; \
+ } \
+ if (caa_likely(!__filter_record)) \
+ return; \
+ } \
+ \
+ lttng_event_notifier_notification_send(__event_notifier); \
+}
+
+#include TRACEPOINT_INCLUDE
+
/*
* Stage 6 of tracepoint event generation.
*
.u = { \
.ext = { \
.model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \
+ .event_notifier_callback = (void (*)(void)) &__event_notifier_probe__##_provider##___##_template,\
}, \
}, \
};
uint32_t cmd;
char padding[USTCOMM_MSG_PADDING1];
union {
+ struct lttng_ust_event_notifier event_notifier;
struct lttng_ust_channel channel;
struct lttng_ust_stream stream;
struct lttng_ust_event event;
int ustcomm_recv_stream_from_sessiond(int sock,
uint64_t *memory_map_size,
int *shm_fd, int *wakeup_fd);
+ssize_t ustcomm_recv_event_notifier_notif_fd_from_sessiond(int sock,
+ int *event_notifier_notif_fd);
/*
* Returns 0 on success, negative error value on error.
return len;
}
+ssize_t ustcomm_recv_event_notifier_notif_fd_from_sessiond(int sock,
+ int *_event_notifier_notif_fd)
+{
+ ssize_t nr_fd;
+ int event_notifier_notif_fd, ret;
+
+ /* Receive event_notifier notification fd */
+ lttng_ust_lock_fd_tracker();
+ nr_fd = ustcomm_recv_fds_unix_sock(sock, &event_notifier_notif_fd, 1);
+ if (nr_fd <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (nr_fd < 0) {
+ ret = nr_fd;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(event_notifier_notif_fd);
+ if (ret < 0) {
+ ret = close(event_notifier_notif_fd);
+ if (ret) {
+ PERROR("close on event_notifier notif fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+
+ *_event_notifier_notif_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+
+ ret = nr_fd;
+
+error:
+ return ret;
+}
+
int ustcomm_recv_stream_from_sessiond(int sock,
uint64_t *memory_map_size,
int *shm_fd, int *wakeup_fd)
break;
case LTTNG_UST_OBJECT_TYPE_EVENT:
case LTTNG_UST_OBJECT_TYPE_CONTEXT:
+ case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER_GROUP:
+ case LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER:
break;
default:
assert(0);
return ustctl_disable(sock, &obj);
}
+int ustctl_create_event_notifier_group(int sock, int pipe_fd,
+ struct lttng_ust_object_data **_event_notifier_group_data)
+{
+ struct lttng_ust_object_data *event_notifier_group_data;
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ ssize_t len;
+ int ret;
+
+ if (!_event_notifier_group_data)
+ return -EINVAL;
+
+ event_notifier_group_data = zmalloc(sizeof(*event_notifier_group_data));
+ if (!event_notifier_group_data)
+ return -ENOMEM;
+
+ event_notifier_group_data->type = LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER_GROUP;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = LTTNG_UST_ROOT_HANDLE;
+ lum.cmd = LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE;
+
+ ret = ustcomm_send_app_msg(sock, &lum);
+ if (ret)
+ goto error;
+
+ /* Send event_notifier notification pipe. */
+ len = ustcomm_send_fds_unix_sock(sock, &pipe_fd, 1);
+ if (len <= 0) {
+ ret = len;
+ goto error;
+ }
+
+ ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+ if (ret)
+ goto error;
+
+ event_notifier_group_data->handle = lur.ret_val;
+ DBG("received event_notifier group handle %d", event_notifier_group_data->handle);
+
+ *_event_notifier_group_data = event_notifier_group_data;
+
+ ret = 0;
+ goto end;
+error:
+ free(event_notifier_group_data);
+
+end:
+ return ret;
+}
+
+int ustctl_create_event_notifier(int sock, struct lttng_ust_event_notifier *event_notifier,
+ struct lttng_ust_object_data *event_notifier_group,
+ struct lttng_ust_object_data **_event_notifier_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ struct lttng_ust_object_data *event_notifier_data;
+ int ret;
+
+ if (!event_notifier_group || !_event_notifier_data)
+ return -EINVAL;
+
+ event_notifier_data = zmalloc(sizeof(*event_notifier_data));
+ if (!event_notifier_data)
+ return -ENOMEM;
+
+ event_notifier_data->type = LTTNG_UST_OBJECT_TYPE_EVENT_NOTIFIER;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = event_notifier_group->handle;
+ lum.cmd = LTTNG_UST_EVENT_NOTIFIER_CREATE;
+
+ strncpy(lum.u.event_notifier.event.name, event_notifier->event.name,
+ LTTNG_UST_SYM_NAME_LEN);
+ lum.u.event_notifier.event.instrumentation = event_notifier->event.instrumentation;
+ lum.u.event_notifier.event.loglevel_type = event_notifier->event.loglevel_type;
+ lum.u.event_notifier.event.loglevel = event_notifier->event.loglevel;
+ lum.u.event_notifier.event.token = event_notifier->event.token;
+ ret = ustcomm_send_app_cmd(sock, &lum, &lur);
+ if (ret) {
+ free(event_notifier_data);
+ return ret;
+ }
+ event_notifier_data->handle = lur.ret_val;
+ DBG("received event_notifier handle %u", event_notifier_data->handle);
+ *_event_notifier_data = event_notifier_data;
+
+ return ret;
+}
+
int ustctl_tracepoint_list(int sock)
{
struct ustcomm_ust_msg lum;
lttng-ust-statedump-provider.h \
ust_lib.c \
ust_lib.h \
+ context-provider-internal.h \
tracepoint-internal.h \
ust-events-internal.h \
clock.h \
getenv.h \
string-utils.c \
string-utils.h \
+ event-notifier-notification.c \
ns.h \
creds.h
--- /dev/null
+#ifndef _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H
+#define _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H
+
+/*
+ * Copyright 2019 - Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stddef.h>
+#include <lttng/ust-events.h>
+
+void lttng_ust_context_set_event_notifier_group_provider(const char *name,
+ size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+ void (*record)(struct lttng_ctx_field *field,
+ struct lttng_ust_lib_ring_buffer_ctx *ctx,
+ struct lttng_channel *chan),
+ void (*get_value)(struct lttng_ctx_field *field,
+ struct lttng_ctx_value *value));
+
+#endif /* _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H */
--- /dev/null
+/*
+ * event-notifier-notification.c
+ *
+ * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@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 as published by the Free Software Foundation; only
+ * version 2.1 of the License.
+ *
+ * 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
+ */
+
+#define _LGPL_SOURCE
+
+#include <errno.h>
+#include <lttng/ust-events.h>
+#include <usterr-signal-safe.h>
+
+#include "share.h"
+
+void lttng_event_notifier_notification_send(
+ struct lttng_event_notifier *event_notifier)
+{
+ /*
+ * We want this write to be atomic AND non-blocking, meaning that we
+ * want to write either everything OR nothing.
+ * According to `pipe(7)`, writes that are smaller that the `PIPE_BUF`
+ * value must be atomic, so we assert that the message we send is less
+ * than PIPE_BUF.
+ */
+ struct lttng_ust_event_notifier_notification notif;
+ ssize_t ret;
+
+ assert(event_notifier);
+ assert(event_notifier->group);
+ assert(sizeof(notif) <= PIPE_BUF);
+
+ notif.token = event_notifier->user_token;
+
+ ret = patient_write(event_notifier->group->notification_fd, ¬if,
+ sizeof(notif));
+ if (ret == -1) {
+ if (errno == EAGAIN) {
+ DBG("Cannot send event notifier notification without blocking: %s",
+ strerror(errno));
+ } else {
+ DBG("Error to sending event notifier notification: %s",
+ strerror(errno));
+ abort();
+ }
+ }
+}
#include <unistd.h>
#include <lttng/ust-context-provider.h>
+
#include "lttng-tracer-core.h"
#include "jhash.h"
+#include "context-provider-internal.h"
#include <helper.h>
#define CONTEXT_PROVIDER_HT_BITS 12
hash = jhash(provider->name, name_len, 0);
head = &context_provider_ht.table[hash & (CONTEXT_PROVIDER_HT_SIZE - 1)];
cds_hlist_add_head(&provider->node, head);
+
lttng_ust_context_set_session_provider(provider->name,
provider->get_size, provider->record,
provider->get_value);
+
+ lttng_ust_context_set_event_notifier_group_provider(provider->name,
+ provider->get_size, provider->record,
+ provider->get_value);
end:
ust_unlock();
return ret;
lttng_ust_context_set_session_provider(provider->name,
lttng_ust_dummy_get_size, lttng_ust_dummy_record,
lttng_ust_dummy_get_value);
+
+ lttng_ust_context_set_event_notifier_group_provider(provider->name,
+ lttng_ust_dummy_get_size, lttng_ust_dummy_record,
+ lttng_ust_dummy_get_value);
+
cds_hlist_del(&provider->node);
end:
ust_unlock();
#define _LGPL_SOURCE
#include <stdio.h>
-#include <urcu/list.h>
-#include <urcu/hlist.h>
-#include <pthread.h>
+#include <assert.h>
#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <stdint.h>
#include <inttypes.h>
#include <time.h>
#include <stdbool.h>
+#include <unistd.h>
#include <lttng/ust-endian.h>
-#include "clock.h"
#include <urcu-bp.h>
+#include <urcu/arch.h>
#include <urcu/compiler.h>
+#include <urcu/hlist.h>
+#include <urcu/list.h>
#include <urcu/uatomic.h>
-#include <urcu/arch.h>
#include <lttng/tracepoint.h>
#include <lttng/ust-events.h>
#include <helper.h>
#include <lttng/ust-ctl.h>
#include <ust-comm.h>
+#include <ust-fd.h>
#include <lttng/ust-dynamic-type.h>
#include <lttng/ust-context-provider.h>
#include "error.h"
#include "wait.h"
#include "../libringbuffer/shm.h"
#include "jhash.h"
+#include <lttng/ust-abi.h>
/*
* All operations within this file are called by the communication
*/
static CDS_LIST_HEAD(sessions);
+static CDS_LIST_HEAD(event_notifier_groups);
struct cds_list_head *_lttng_get_sessions(void)
{
}
static void _lttng_event_destroy(struct lttng_event *event);
+static void _lttng_event_notifier_destroy(
+ struct lttng_event_notifier *event_notifier);
static void _lttng_enum_destroy(struct lttng_enum *_enum);
static
static
void lttng_session_sync_event_enablers(struct lttng_session *session);
static
+void lttng_event_notifier_group_sync_enablers(
+ struct lttng_event_notifier_group *event_notifier_group);
+static
void lttng_enabler_destroy(struct lttng_enabler *enabler);
/*
return session;
}
+struct lttng_event_notifier_group *lttng_event_notifier_group_create(void)
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+ int i;
+
+ event_notifier_group = zmalloc(sizeof(struct lttng_event_notifier_group));
+ if (!event_notifier_group)
+ return NULL;
+
+ CDS_INIT_LIST_HEAD(&event_notifier_group->enablers_head);
+ CDS_INIT_LIST_HEAD(&event_notifier_group->event_notifiers_head);
+ for (i = 0; i < LTTNG_UST_EVENT_NOTIFIER_HT_SIZE; i++)
+ CDS_INIT_HLIST_HEAD(&event_notifier_group->event_notifiers_ht.table[i]);
+
+ cds_list_add(&event_notifier_group->node, &event_notifier_groups);
+
+ return event_notifier_group;
+}
+
/*
* Only used internally at session destruction.
*/
event->registered = 1;
}
+static
+void register_event_notifier(struct lttng_event_notifier *event_notifier)
+{
+ int ret;
+ const struct lttng_event_desc *desc;
+
+ assert(event_notifier->registered == 0);
+ desc = event_notifier->desc;
+ ret = __tracepoint_probe_register_queue_release(desc->name,
+ desc->u.ext.event_notifier_callback, event_notifier, desc->signature);
+ WARN_ON_ONCE(ret);
+ if (!ret)
+ event_notifier->registered = 1;
+}
+
static
void unregister_event(struct lttng_event *event)
{
event->registered = 0;
}
+static
+void unregister_event_notifier(struct lttng_event_notifier *event_notifier)
+{
+ int ret;
+ const struct lttng_event_desc *desc;
+
+ assert(event_notifier->registered == 1);
+ desc = event_notifier->desc;
+ ret = __tracepoint_probe_unregister_queue_release(desc->name,
+ desc->u.ext.event_notifier_callback, event_notifier);
+ WARN_ON_ONCE(ret);
+ if (!ret)
+ event_notifier->registered = 0;
+}
+
/*
* Only used internally at session destruction.
*/
unregister_event(event);
}
+/*
+ * Only used internally at session destruction.
+ */
+static
+void _lttng_event_notifier_unregister(struct lttng_event_notifier *event_notifier)
+{
+ if (event_notifier->registered)
+ unregister_event_notifier(event_notifier);
+}
+
void lttng_session_destroy(struct lttng_session *session)
{
struct lttng_channel *chan, *tmpchan;
free(session);
}
+void lttng_event_notifier_group_destroy(
+ struct lttng_event_notifier_group *event_notifier_group)
+{
+ int close_ret;
+ struct lttng_event_notifier_enabler *notifier_enabler, *tmpnotifier_enabler;
+ struct lttng_event_notifier *notifier, *tmpnotifier;
+
+ if (!event_notifier_group) {
+ return;
+ }
+
+ cds_list_for_each_entry(notifier,
+ &event_notifier_group->event_notifiers_head, node)
+ _lttng_event_notifier_unregister(notifier);
+
+ synchronize_trace();
+
+ cds_list_for_each_entry_safe(notifier_enabler, tmpnotifier_enabler,
+ &event_notifier_group->enablers_head, node)
+ lttng_event_notifier_enabler_destroy(notifier_enabler);
+
+ cds_list_for_each_entry_safe(notifier, tmpnotifier,
+ &event_notifier_group->event_notifiers_head, node)
+ _lttng_event_notifier_destroy(notifier);
+
+ /* Close the notification fd to the listener of event notifiers. */
+
+ lttng_ust_lock_fd_tracker();
+ close_ret = close(event_notifier_group->notification_fd);
+ if (!close_ret) {
+ lttng_ust_delete_fd_from_tracker(
+ event_notifier_group->notification_fd);
+ } else {
+ PERROR("close");
+ abort();
+ }
+ lttng_ust_unlock_fd_tracker();
+
+ cds_list_del(&event_notifier_group->node);
+
+ free(event_notifier_group);
+}
+
static
void lttng_enabler_destroy(struct lttng_enabler *enabler)
{
}
}
+ void lttng_event_notifier_enabler_destroy(struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ if (!event_notifier_enabler) {
+ return;
+ }
+
+ cds_list_del(&event_notifier_enabler->node);
+
+ lttng_enabler_destroy(lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+
+ free(event_notifier_enabler);
+}
+
static
int lttng_enum_create(const struct lttng_enum_desc *desc,
struct lttng_session *session)
return ret;
}
+static
+int lttng_event_notifier_create(const struct lttng_event_desc *desc,
+ uint64_t token,
+ struct lttng_event_notifier_group *event_notifier_group)
+{
+ struct lttng_event_notifier *event_notifier;
+ struct cds_hlist_head *head;
+ int ret = 0;
+
+ /*
+ * Get the hashtable bucket the created lttng_event_notifier object
+ * should be inserted.
+ */
+ head = borrow_hash_table_bucket(
+ event_notifier_group->event_notifiers_ht.table,
+ LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc);
+
+ event_notifier = zmalloc(sizeof(struct lttng_event_notifier));
+ if (!event_notifier) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ event_notifier->group = event_notifier_group;
+ event_notifier->user_token = token;
+
+ /* Event notifier will be enabled by enabler sync. */
+ event_notifier->enabled = 0;
+ event_notifier->registered = 0;
+
+ CDS_INIT_LIST_HEAD(&event_notifier->filter_bytecode_runtime_head);
+ CDS_INIT_LIST_HEAD(&event_notifier->enablers_ref_head);
+ event_notifier->desc = desc;
+
+ cds_list_add(&event_notifier->node,
+ &event_notifier_group->event_notifiers_head);
+ cds_hlist_add_head(&event_notifier->hlist, head);
+
+ return 0;
+
+error:
+ return ret;
+}
+
+static
+void _lttng_event_notifier_destroy(struct lttng_event_notifier *event_notifier)
+{
+ struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref;
+
+ /* Remove from event_notifier list. */
+ cds_list_del(&event_notifier->node);
+ /* Remove from event_notifier hash table. */
+ cds_hlist_del(&event_notifier->hlist);
+
+ lttng_free_event_notifier_filter_runtime(event_notifier);
+
+ /* Free event_notifier enabler refs */
+ cds_list_for_each_entry_safe(enabler_ref, tmp_enabler_ref,
+ &event_notifier->enablers_ref_head, node)
+ free(enabler_ref);
+ free(event_notifier);
+}
+
static
int lttng_desc_match_star_glob_enabler(const struct lttng_event_desc *desc,
struct lttng_enabler *enabler)
return 0;
}
+static
+int lttng_event_notifier_enabler_match_event_notifier(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_event_notifier *event_notifier)
+{
+ int desc_matches = lttng_desc_match_enabler(event_notifier->desc,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+
+ if (desc_matches && event_notifier->group == event_notifier_enabler->group &&
+ event_notifier->user_token == event_notifier_enabler->user_token)
+ return 1;
+ else
+ return 0;
+}
+
static
struct lttng_enabler_ref *lttng_enabler_ref(
struct cds_list_head *enabler_ref_list,
static
void probe_provider_event_for_each(struct lttng_probe_desc *provider_desc,
- void (*event_func)(struct lttng_session *session, struct lttng_event *event))
+ void (*event_func)(struct lttng_session *session,
+ struct lttng_event *event),
+ void (*event_notifier_func)(struct lttng_event_notifier *event_notifier))
{
struct cds_hlist_node *node, *tmp_node;
struct cds_list_head *sessionsp;
*/
for (i = 0; i < provider_desc->nr_events; i++) {
const struct lttng_event_desc *event_desc;
+ struct lttng_event_notifier_group *event_notifier_group;
+ struct lttng_event_notifier *event_notifier;
struct lttng_session *session;
struct cds_hlist_head *head;
struct lttng_event *event;
}
}
}
+
+ /*
+ * Iterate over all event_notifier groups to find the current event
+ * description.
+ */
+ cds_list_for_each_entry(event_notifier_group, &event_notifier_groups, node) {
+ /*
+ * Get the list of event_notifiers in the hashtable bucket and
+ * iterate to find the event_notifier matching this
+ * descriptor.
+ */
+ head = borrow_hash_table_bucket(
+ event_notifier_group->event_notifiers_ht.table,
+ LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, event_desc);
+
+ cds_hlist_for_each_entry_safe(event_notifier, node, tmp_node, head, hlist) {
+ if (event_desc == event_notifier->desc) {
+ event_notifier_func(event_notifier);
+ break;
+ }
+ }
+ }
}
}
* Iterate over all events in the probe provider descriptions and sessions
* to queue the unregistration of the events.
*/
- probe_provider_event_for_each(provider_desc, _unregister_event);
+ probe_provider_event_for_each(provider_desc, _unregister_event,
+ _lttng_event_notifier_unregister);
/* Wait for grace period. */
synchronize_trace();
* It is now safe to destroy the events and remove them from the event list
* and hashtables.
*/
- probe_provider_event_for_each(provider_desc, _event_enum_destroy);
+ probe_provider_event_for_each(provider_desc, _event_enum_destroy,
+ _lttng_event_notifier_destroy);
}
/*
- * Create events associated with an enabler (if not already present),
+ * Create events associated with an event enabler (if not already present),
* and add backward reference from the event to the enabler.
*/
static
return 0;
}
+int lttng_fix_pending_event_notifiers(void)
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+
+ cds_list_for_each_entry(event_notifier_group, &event_notifier_groups, node) {
+ lttng_event_notifier_group_sync_enablers(event_notifier_group);
+ }
+ return 0;
+}
+
/*
* For each session of the owner thread, execute pending statedump.
* Only dump state for the sessions owned by the caller thread, because
return event_enabler;
}
+struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
+ struct lttng_event_notifier_group *event_notifier_group,
+ enum lttng_enabler_format_type format_type,
+ struct lttng_ust_event_notifier *event_notifier_param)
+{
+ struct lttng_event_notifier_enabler *event_notifier_enabler;
+
+ event_notifier_enabler = zmalloc(sizeof(*event_notifier_enabler));
+ if (!event_notifier_enabler)
+ return NULL;
+ event_notifier_enabler->base.format_type = format_type;
+ CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.filter_bytecode_head);
+ CDS_INIT_LIST_HEAD(&event_notifier_enabler->base.excluder_head);
+
+ event_notifier_enabler->user_token = event_notifier_param->event.token;
+
+ memcpy(&event_notifier_enabler->base.event_param.name,
+ event_notifier_param->event.name,
+ sizeof(event_notifier_enabler->base.event_param.name));
+ event_notifier_enabler->base.event_param.instrumentation =
+ event_notifier_param->event.instrumentation;
+ event_notifier_enabler->base.event_param.loglevel =
+ event_notifier_param->event.loglevel;
+ event_notifier_enabler->base.event_param.loglevel_type =
+ event_notifier_param->event.loglevel_type;
+
+ event_notifier_enabler->base.enabled = 0;
+ event_notifier_enabler->group = event_notifier_group;
+
+ cds_list_add(&event_notifier_enabler->node,
+ &event_notifier_group->enablers_head);
+
+ lttng_event_notifier_group_sync_enablers(event_notifier_group);
+
+ return event_notifier_enabler;
+}
+
int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler)
{
lttng_event_enabler_as_enabler(event_enabler)->enabled = 1;
return 0;
}
+int lttng_event_notifier_enabler_enable(
+ struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->enabled = 1;
+ lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+
+ return 0;
+}
+
+int lttng_event_notifier_enabler_disable(
+ struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->enabled = 0;
+ lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+
+ return 0;
+}
+
+int lttng_event_notifier_enabler_attach_bytecode(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode)
+{
+ _lttng_enabler_attach_bytecode(
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler),
+ bytecode);
+
+ lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+ return 0;
+}
+
+int lttng_event_notifier_enabler_attach_exclusion(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_ust_excluder_node *excluder)
+{
+ _lttng_enabler_attach_exclusion(
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler),
+ excluder);
+
+ lttng_event_notifier_group_sync_enablers(event_notifier_enabler->group);
+ return 0;
+}
+
int lttng_attach_context(struct lttng_ust_context *context_param,
union ust_args *uargs,
struct lttng_ctx **ctx, struct lttng_session *session)
__tracepoint_probe_prune_release_queue();
}
+static
+void lttng_create_event_notifier_if_missing(
+ struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ struct lttng_event_notifier_group *event_notifier_group = event_notifier_enabler->group;
+ struct lttng_probe_desc *probe_desc;
+ struct cds_list_head *probe_list;
+ int i;
+
+ probe_list = lttng_get_probe_list_head();
+
+ cds_list_for_each_entry(probe_desc, probe_list, head) {
+ for (i = 0; i < probe_desc->nr_events; i++) {
+ int ret;
+ bool found = false;
+ const struct lttng_event_desc *desc;
+ struct lttng_event_notifier *event_notifier;
+ struct cds_hlist_head *head;
+ struct cds_hlist_node *node;
+
+ desc = probe_desc->event_desc[i];
+ if (!lttng_desc_match_enabler(desc,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
+ continue;
+
+ /*
+ * Given the current event_notifier group, get the bucket that
+ * the target event_notifier would be if it was already
+ * created.
+ */
+ head = borrow_hash_table_bucket(
+ event_notifier_group->event_notifiers_ht.table,
+ LTTNG_UST_EVENT_NOTIFIER_HT_SIZE, desc);
+
+ cds_hlist_for_each_entry(event_notifier, node, head, hlist) {
+ /*
+ * Check if event_notifier already exists by checking
+ * if the event_notifier and enabler share the same
+ * description and id.
+ */
+ if (event_notifier->desc == desc &&
+ event_notifier->user_token == event_notifier_enabler->user_token) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ /*
+ * We need to create a event_notifier for this event probe.
+ */
+ ret = lttng_event_notifier_create(desc,
+ event_notifier_enabler->user_token,
+ event_notifier_group);
+ if (ret) {
+ DBG("Unable to create event_notifier %s, error %d\n",
+ probe_desc->event_desc[i]->name, ret);
+ }
+ }
+ }
+}
+
+/*
+ * Create event_notifiers associated with a event_notifier enabler (if not already present).
+ */
+static
+int lttng_event_notifier_enabler_ref_event_notifiers(
+ struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ struct lttng_event_notifier_group *event_notifier_group = event_notifier_enabler->group;
+ struct lttng_event_notifier *event_notifier;
+
+ /*
+ * Only try to create event_notifiers for enablers that are enabled, the user
+ * might still be attaching filter or exclusion to the
+ * event_notifier_enabler.
+ */
+ if (!lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)->enabled)
+ goto end;
+
+ /* First, ensure that probe event_notifiers are created for this enabler. */
+ lttng_create_event_notifier_if_missing(event_notifier_enabler);
+
+ /* Link the created event_notifier with its associated enabler. */
+ cds_list_for_each_entry(event_notifier, &event_notifier_group->event_notifiers_head, node) {
+ struct lttng_enabler_ref *enabler_ref;
+
+ if (!lttng_event_notifier_enabler_match_event_notifier(event_notifier_enabler, event_notifier))
+ continue;
+
+ enabler_ref = lttng_enabler_ref(&event_notifier->enablers_ref_head,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+ if (!enabler_ref) {
+ /*
+ * If no backward ref, create it.
+ * Add backward ref from event_notifier to enabler.
+ */
+ enabler_ref = zmalloc(sizeof(*enabler_ref));
+ if (!enabler_ref)
+ return -ENOMEM;
+
+ enabler_ref->ref = lttng_event_notifier_enabler_as_enabler(
+ event_notifier_enabler);
+ cds_list_add(&enabler_ref->node,
+ &event_notifier->enablers_ref_head);
+ }
+
+ /*
+ * Link filter bytecodes if not linked yet.
+ */
+ lttng_enabler_link_bytecode(event_notifier->desc,
+ &event_notifier_group->ctx, &event_notifier->filter_bytecode_runtime_head,
+ lttng_event_notifier_enabler_as_enabler(event_notifier_enabler));
+ }
+end:
+ return 0;
+}
+
+static
+void lttng_event_notifier_group_sync_enablers(struct lttng_event_notifier_group *event_notifier_group)
+{
+ struct lttng_event_notifier_enabler *event_notifier_enabler;
+ struct lttng_event_notifier *event_notifier;
+
+ cds_list_for_each_entry(event_notifier_enabler, &event_notifier_group->enablers_head, node)
+ lttng_event_notifier_enabler_ref_event_notifiers(event_notifier_enabler);
+
+ /*
+ * For each event_notifier, if at least one of its enablers is enabled,
+ * we enable the event_notifier, else we disable it.
+ */
+ cds_list_for_each_entry(event_notifier, &event_notifier_group->event_notifiers_head, node) {
+ struct lttng_enabler_ref *enabler_ref;
+ struct lttng_bytecode_runtime *runtime;
+ int enabled = 0, has_enablers_without_bytecode = 0;
+
+ /* Enable event_notifiers */
+ cds_list_for_each_entry(enabler_ref,
+ &event_notifier->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled) {
+ enabled = 1;
+ break;
+ }
+ }
+
+ CMM_STORE_SHARED(event_notifier->enabled, enabled);
+ /*
+ * Sync tracepoint registration with event_notifier enabled
+ * state.
+ */
+ if (enabled) {
+ if (!event_notifier->registered)
+ register_event_notifier(event_notifier);
+ } else {
+ if (event_notifier->registered)
+ unregister_event_notifier(event_notifier);
+ }
+
+ /* Check if has enablers without bytecode enabled */
+ cds_list_for_each_entry(enabler_ref,
+ &event_notifier->enablers_ref_head, node) {
+ if (enabler_ref->ref->enabled
+ && cds_list_empty(&enabler_ref->ref->filter_bytecode_head)) {
+ has_enablers_without_bytecode = 1;
+ break;
+ }
+ }
+ event_notifier->has_enablers_without_bytecode =
+ has_enablers_without_bytecode;
+
+ /* Enable filters */
+ cds_list_for_each_entry(runtime,
+ &event_notifier->filter_bytecode_runtime_head, node) {
+ lttng_filter_sync_state(runtime);
+ }
+ }
+ __tracepoint_probe_prune_release_queue();
+}
+
/*
* Apply enablers to session events, adding events to session if need
* be. It is required after each modification applied to an active
}
}
}
+
+/*
+ * Update all event_notifier groups with the given app context.
+ * Called with ust lock held.
+ * This is invoked when an application context gets loaded/unloaded. It
+ * ensures the context callbacks are in sync with the application
+ * context (either app context callbacks, or dummy callbacks).
+ */
+void lttng_ust_context_set_event_notifier_group_provider(const char *name,
+ size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
+ void (*record)(struct lttng_ctx_field *field,
+ struct lttng_ust_lib_ring_buffer_ctx *ctx,
+ struct lttng_channel *chan),
+ void (*get_value)(struct lttng_ctx_field *field,
+ struct lttng_ctx_value *value))
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+
+ cds_list_for_each_entry(event_notifier_group, &event_notifier_groups, node) {
+ int ret;
+
+ ret = lttng_ust_context_set_provider_rcu(
+ &event_notifier_group->ctx,
+ name, get_size, record, get_value);
+ if (ret)
+ abort();
+ }
+}
{
free_filter_runtime(&event->bytecode_runtime_head);
}
+
+void lttng_free_event_notifier_filter_runtime(
+ struct lttng_event_notifier *event_notifier)
+{
+ free_filter_runtime(&event_notifier->filter_bytecode_runtime_head);
+}
#include "lttng-tracer-core.h"
#include "jhash.h"
#include "error.h"
+#include "ust-events-internal.h"
/*
* probe list is protected by ust_lock()/ust_unlock().
if (lttng_session_active())
fixup_lazy_probes();
+ lttng_fix_pending_event_notifiers();
+
ust_unlock();
return ret;
}
*/
#define _LGPL_SOURCE
+#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
*/
static const struct lttng_ust_objd_ops lttng_ops;
+static const struct lttng_ust_objd_ops lttng_event_notifier_group_ops;
static const struct lttng_ust_objd_ops lttng_session_ops;
static const struct lttng_ust_objd_ops lttng_channel_ops;
static const struct lttng_ust_objd_ops lttng_event_enabler_ops;
+static const struct lttng_ust_objd_ops lttng_event_notifier_enabler_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops;
return 0;
}
+static
+int lttng_abi_event_notifier_send_fd(void *owner, int event_notifier_notif_fd)
+{
+ struct lttng_event_notifier_group *event_notifier_group;
+ int event_notifier_group_objd, ret, fd_flag, close_ret;
+
+ event_notifier_group = lttng_event_notifier_group_create();
+ if (!event_notifier_group)
+ return -ENOMEM;
+
+ /*
+ * Set this file descriptor as NON-BLOCKING.
+ */
+ fd_flag = fcntl(event_notifier_notif_fd, F_GETFL);
+
+ fd_flag |= O_NONBLOCK;
+
+ ret = fcntl(event_notifier_notif_fd, F_SETFL, fd_flag);
+ if (ret) {
+ ret = -errno;
+ goto fd_error;
+ }
+
+ event_notifier_group_objd = objd_alloc(event_notifier_group,
+ <tng_event_notifier_group_ops, owner, "event_notifier_group");
+ if (event_notifier_group_objd < 0) {
+ ret = event_notifier_group_objd;
+ goto objd_error;
+ }
+
+ event_notifier_group->objd = event_notifier_group_objd;
+ event_notifier_group->owner = owner;
+ event_notifier_group->notification_fd = event_notifier_notif_fd;
+
+ return event_notifier_group_objd;
+
+objd_error:
+ lttng_event_notifier_group_destroy(event_notifier_group);
+fd_error:
+ close_ret = close(event_notifier_notif_fd);
+ if (close_ret) {
+ PERROR("close");
+ }
+
+ return ret;
+}
+
static
long lttng_abi_add_context(int objd,
struct lttng_ust_context *context_param,
case LTTNG_UST_WAIT_QUIESCENT:
synchronize_trace();
return 0;
+ case LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE:
+ return lttng_abi_event_notifier_send_fd(owner,
+ uargs->event_notifier_handle.event_notifier_notif_fd);
default:
return -EINVAL;
}
.cmd = lttng_session_cmd,
};
+static int lttng_ust_event_notifier_enabler_create(int event_notifier_group_obj,
+ void *owner, struct lttng_ust_event_notifier *event_notifier_param,
+ enum lttng_enabler_format_type type)
+{
+ struct lttng_event_notifier_group *event_notifier_group =
+ objd_private(event_notifier_group_obj);
+ struct lttng_event_notifier_enabler *event_notifier_enabler;
+ int event_notifier_objd, ret;
+
+ event_notifier_param->event.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+ event_notifier_objd = objd_alloc(NULL, <tng_event_notifier_enabler_ops, owner,
+ "event_notifier enabler");
+ if (event_notifier_objd < 0) {
+ ret = event_notifier_objd;
+ goto objd_error;
+ }
+
+ event_notifier_enabler = lttng_event_notifier_enabler_create(
+ event_notifier_group, type, event_notifier_param);
+ if (!event_notifier_enabler) {
+ ret = -ENOMEM;
+ goto event_notifier_error;
+ }
+
+ objd_set_private(event_notifier_objd, event_notifier_enabler);
+ /* The event_notifier holds a reference on the event_notifier group. */
+ objd_ref(event_notifier_enabler->group->objd);
+
+ return event_notifier_objd;
+
+event_notifier_error:
+ {
+ int err;
+
+ err = lttng_ust_objd_unref(event_notifier_objd, 1);
+ assert(!err);
+ }
+objd_error:
+ return ret;
+}
+
+static
+long lttng_event_notifier_enabler_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ struct lttng_event_notifier_enabler *event_notifier_enabler = objd_private(objd);
+ switch (cmd) {
+ case LTTNG_UST_FILTER:
+ return lttng_event_notifier_enabler_attach_bytecode(event_notifier_enabler,
+ (struct lttng_ust_filter_bytecode_node *) arg);
+ case LTTNG_UST_EXCLUSION:
+ return lttng_event_notifier_enabler_attach_exclusion(event_notifier_enabler,
+ (struct lttng_ust_excluder_node *) arg);
+ case LTTNG_UST_ENABLE:
+ return lttng_event_notifier_enabler_enable(event_notifier_enabler);
+ case LTTNG_UST_DISABLE:
+ return lttng_event_notifier_enabler_disable(event_notifier_enabler);
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+long lttng_event_notifier_group_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ switch (cmd) {
+ case LTTNG_UST_EVENT_NOTIFIER_CREATE:
+ {
+ struct lttng_ust_event_notifier *event_notifier_param =
+ (struct lttng_ust_event_notifier *) arg;
+ if (strutils_is_star_glob_pattern(event_notifier_param->event.name)) {
+ /*
+ * If the event name is a star globbing pattern,
+ * we create the special star globbing enabler.
+ */
+ return lttng_ust_event_notifier_enabler_create(objd,
+ owner, event_notifier_param,
+ LTTNG_ENABLER_FORMAT_STAR_GLOB);
+ } else {
+ return lttng_ust_event_notifier_enabler_create(objd,
+ owner, event_notifier_param,
+ LTTNG_ENABLER_FORMAT_EVENT);
+ }
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+int lttng_event_notifier_enabler_release(int objd)
+{
+ struct lttng_event_notifier_enabler *event_notifier_enabler = objd_private(objd);
+
+ if (event_notifier_enabler)
+ return lttng_ust_objd_unref(event_notifier_enabler->group->objd, 0);
+ return 0;
+}
+
+static const struct lttng_ust_objd_ops lttng_event_notifier_enabler_ops = {
+ .release = lttng_event_notifier_enabler_release,
+ .cmd = lttng_event_notifier_enabler_cmd,
+};
+
+static
+int lttng_release_event_notifier_group(int objd)
+{
+ struct lttng_event_notifier_group *event_notifier_group = objd_private(objd);
+
+ if (event_notifier_group) {
+ lttng_event_notifier_group_destroy(event_notifier_group);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
+static const struct lttng_ust_objd_ops lttng_event_notifier_group_ops = {
+ .release = lttng_release_event_notifier_group,
+ .cmd = lttng_event_notifier_group_cmd,
+};
+
static
long lttng_tracepoint_list_cmd(int objd, unsigned int cmd, unsigned long arg,
union ust_args *uargs, void *owner)
[ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
[ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+ [ LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE ] = "Create event notifier group",
+
/* Session FD commands */
[ LTTNG_UST_CHANNEL ] = "Create Channel",
[ LTTNG_UST_SESSION_START ] = "Start Session",
/* Event FD commands */
[ LTTNG_UST_FILTER ] = "Create Filter",
[ LTTNG_UST_EXCLUSION ] = "Add exclusions to event",
+
+ /* Event notifier group commands */
+ [ LTTNG_UST_EVENT_NOTIFIER_CREATE ] = "Create event notifier",
};
static const char *str_timeout;
}
break;
}
+ case LTTNG_UST_EVENT_NOTIFIER_GROUP_CREATE:
+ {
+ int event_notifier_notif_fd;
+
+ len = ustcomm_recv_event_notifier_notif_fd_from_sessiond(sock,
+ &event_notifier_notif_fd);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ case 1:
+ break;
+ default:
+ if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d",
+ (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection",
+ sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto error;
+ } else {
+ DBG("Incorrect event notifier fd message size: %zd",
+ len);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
+ args.event_notifier_handle.event_notifier_notif_fd =
+ event_notifier_notif_fd;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
case LTTNG_UST_CHANNEL:
{
void *chan_data;
struct lttng_ctx *ctx;
};
+struct lttng_event_notifier_enabler {
+ struct lttng_enabler base;
+ struct cds_list_head node; /* per-app list of event notifier enablers */
+ struct lttng_event_notifier_group *group; /* weak ref */
+ uint64_t user_token; /* User-provided token */
+};
+
struct lttng_ust_filter_bytecode_node {
struct cds_list_head node;
struct lttng_enabler *enabler;
return &event_enabler->base;
}
+static inline
+struct lttng_enabler *lttng_event_notifier_enabler_as_enabler(
+ struct lttng_event_notifier_enabler *event_notifier_enabler)
+{
+ return &event_notifier_enabler->base;
+}
/*
* Allocate and initialize a `struct lttng_event_enabler` object.
struct cds_list_head *bytecode_runtime_head,
struct lttng_enabler *enabler);
+/*
+ * Allocate and initialize a `struct lttng_event_notifier_group` object.
+ *
+ * On success, returns a `struct lttng_triggre_group`,
+ * on memory error, returns NULL.
+ */
+LTTNG_HIDDEN
+struct lttng_event_notifier_group *lttng_event_notifier_group_create(void);
+
+/*
+ * Destroy a `struct lttng_event_notifier_group` object.
+ */
+LTTNG_HIDDEN
+void lttng_event_notifier_group_destroy(
+ struct lttng_event_notifier_group *event_notifier_group);
+
+/*
+ * Allocate and initialize a `struct lttng_event_notifier_enabler` object.
+ *
+ * On success, returns a `struct lttng_event_notifier_enabler`,
+ * On memory error, returns NULL.
+ */
+LTTNG_HIDDEN
+struct lttng_event_notifier_enabler *lttng_event_notifier_enabler_create(
+ struct lttng_event_notifier_group *event_notifier_group,
+ enum lttng_enabler_format_type format_type,
+ struct lttng_ust_event_notifier *event_notifier_param);
+
+/*
+ * Destroy a `struct lttng_event_notifier_enabler` object.
+ */
+LTTNG_HIDDEN
+void lttng_event_notifier_enabler_destroy(
+ struct lttng_event_notifier_enabler *event_notifier_enabler);
+
+/*
+ * Enable a `struct lttng_event_notifier_enabler` object and all event
+ * notifiers related to this enabler.
+ */
+LTTNG_HIDDEN
+int lttng_event_notifier_enabler_enable(
+ struct lttng_event_notifier_enabler *event_notifier_enabler);
+
+/*
+ * Disable a `struct lttng_event_notifier_enabler` object and all event
+ * notifiers related to this enabler.
+ */
+LTTNG_HIDDEN
+int lttng_event_notifier_enabler_disable(
+ struct lttng_event_notifier_enabler *event_notifier_enabler);
+
+/*
+ * Attach filter bytecode program to `struct lttng_event_notifier_enabler` and
+ * all event notifiers related to this enabler.
+ */
+LTTNG_HIDDEN
+int lttng_event_notifier_enabler_attach_bytecode(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_ust_filter_bytecode_node *bytecode);
+
+/*
+ * Attach exclusion list to `struct lttng_event_notifier_enabler` and all
+ * event notifiers related to this enabler.
+ */
+LTTNG_HIDDEN
+int lttng_event_notifier_enabler_attach_exclusion(
+ struct lttng_event_notifier_enabler *event_notifier_enabler,
+ struct lttng_ust_excluder_node *excluder);
+
+LTTNG_HIDDEN
+void lttng_free_event_notifier_filter_runtime(
+ struct lttng_event_notifier *event_notifier);
+
+/*
+ * Connect the probe on all enablers matching this event description.
+ * Called on library load.
+ */
+LTTNG_HIDDEN
+int lttng_fix_pending_event_notifiers(void);
+
#endif /* _LTTNG_UST_EVENTS_INTERNAL_H */