From: Francis Deslauriers Date: Thu, 28 Nov 2019 19:15:02 +0000 (-0500) Subject: SoW-2019-0002: Dynamic Snapshot X-Git-Url: http://git.efficios.com/?p=lttng-ust.git;a=commitdiff_plain;h=refs%2Fheads%2Fsow-2019-0002-rev1 SoW-2019-0002: Dynamic Snapshot Revision 1 --- diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 461e77c2..3a662d94 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -102,6 +102,29 @@ struct lttng_ust_stream { */ } LTTNG_PACKED; +#define LTTNG_UST_TRIGGER_PADDING1 16 +#define LTTNG_UST_TRIGGER_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) +struct lttng_ust_trigger { + uint64_t id; + enum lttng_ust_instrumentation instrumentation; + char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */ + + enum lttng_ust_loglevel_type loglevel_type; + int loglevel; /* value, -1: all */ + char padding[LTTNG_UST_TRIGGER_PADDING1]; + + /* Per instrumentation type configuration */ + union { + char padding[LTTNG_UST_TRIGGER_PADDING2]; + } u; +} LTTNG_PACKED; + +#define LTTNG_TRIGGER_NOTIFICATION_PADDING 32 +struct lttng_ust_trigger_notification { + uint64_t id; + char padding[LTTNG_TRIGGER_NOTIFICATION_PADDING]; +} LTTNG_PACKED; + #define LTTNG_UST_EVENT_PADDING1 16 #define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_event { @@ -215,6 +238,8 @@ enum lttng_ust_object_type { LTTNG_UST_OBJECT_TYPE_STREAM = 1, LTTNG_UST_OBJECT_TYPE_EVENT = 2, LTTNG_UST_OBJECT_TYPE_CONTEXT = 3, + LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP = 4, + LTTNG_UST_OBJECT_TYPE_TRIGGER = 5, }; #define LTTNG_UST_OBJECT_DATA_PADDING1 32 @@ -320,6 +345,11 @@ struct lttng_ust_event_exclusion { #define LTTNG_UST_FILTER _UST_CMD(0xA0) #define LTTNG_UST_EXCLUSION _UST_CMD(0xA1) +/* Trigger commands */ +#define LTTNG_UST_TRIGGER_GROUP_CREATE _UST_CMD(0xB0) +#define LTTNG_UST_TRIGGER_CREATE \ + _UST_CMDW(0xB1, struct lttng_ust_trigger) + #define LTTNG_UST_ROOT_HANDLE 0 struct lttng_ust_obj; @@ -339,6 +369,9 @@ union ust_args { struct { char *ctxname; } app_context; + struct { + int trigger_notif_fd; + } trigger_handle; }; struct lttng_ust_objd_ops { diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 4b254efa..473d8028 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -101,6 +101,25 @@ int ustctl_disable(int sock, struct lttng_ust_object_data *object); int ustctl_start_session(int sock, int handle); int ustctl_stop_session(int sock, int handle); +/* + * ustctl_create_trigger_group creates a trigger group. It establishes the + * connection with the application by providing a file descriptor of the pipe + * to be used by the application when a trigger of that group is fired. It + * returns a handle to be used when creating trigger in that group. + */ +int ustctl_create_trigger_group(int sock, int pipe_fd, + struct lttng_ust_object_data **trigger_group); + +/* + * ustctl_create_trigger creates a trigger in a trigger group giving a trigger + * description and a trigger group handle. It returns a trigger handle to be + * used when enabling the trigger, attaching filter, attaching exclusion, and + * disabling the trigger. + */ +int ustctl_create_trigger(int sock, struct lttng_ust_trigger *trigger, + struct lttng_ust_object_data *trigger_group, + struct lttng_ust_object_data **trigger_data); + /* * ustctl_tracepoint_list returns a tracepoint list handle, or negative * error value. diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index fd27396f..03d53bae 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -326,6 +326,7 @@ struct lttng_event_desc { union { struct { const char **model_emf_uri; + void (*trigger_callback)(void); } ext; char padding[LTTNG_UST_EVENT_DESC_PADDING]; } u; @@ -346,9 +347,9 @@ struct lttng_probe_desc { /* Data structures used by the tracer. */ -enum lttng_enabler_type { - LTTNG_ENABLER_STAR_GLOB, - LTTNG_ENABLER_EVENT, +enum lttng_enabler_format_type { + LTTNG_ENABLER_FORMAT_STAR_GLOB, + LTTNG_ENABLER_FORMAT_EVENT, }; /* @@ -356,21 +357,14 @@ enum lttng_enabler_type { * backward reference. */ struct lttng_enabler { - enum lttng_enabler_type type; + enum lttng_enabler_format_type format_type; /* head list of struct lttng_ust_filter_bytecode_node */ struct cds_list_head filter_bytecode_head; /* head list of struct lttng_ust_excluder_node */ struct cds_list_head excluder_head; - struct cds_list_head node; /* per-session list of enablers */ struct lttng_ust_event event_param; - struct lttng_channel *chan; - /* - * Unused, but kept around to make it explicit that the tracer can do - * it. - */ - struct lttng_ctx *ctx; unsigned int enabled:1; }; @@ -431,11 +425,20 @@ struct lttng_bytecode_runtime { uint64_t (*filter)(void *filter_data, const char *filter_stack_data); int link_failed; struct cds_list_head node; /* list of bytecode runtime in event */ - struct lttng_session *session; + /* + * Pointer to a URCU-protected pointer owned by an `struct + * lttng_session`or `struct lttng_trigger_group`. + */ + struct lttng_ctx **ctx; }; /* - * Objects in a linked-list of enablers, owned by an event. + * Objects in a linked-list of enablers, owned by an event or trigger. + * This is used because an event (or a trigger) 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 */ @@ -474,6 +477,19 @@ struct lttng_event { int registered; /* has reg'd tracepoint probe */ }; +struct lttng_trigger { + uint64_t id; + int enabled; + int registered; /* has reg'd tracepoint probe */ + struct cds_list_head 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 triggers */ + struct cds_list_head node; /* Trigger list in session */ + struct lttng_trigger_group *group; /* weak ref */ +}; + struct lttng_enum { const struct lttng_enum_desc *desc; struct lttng_session *session; @@ -575,6 +591,12 @@ struct lttng_ust_event_ht { struct cds_hlist_head table[LTTNG_UST_EVENT_HT_SIZE]; }; +#define LTTNG_UST_TRIGGER_HT_BITS 12 +#define LTTNG_UST_TRIGGER_HT_SIZE (1U << LTTNG_UST_TRIGGER_HT_BITS) +struct lttng_ust_trigger_ht { + struct cds_hlist_head table[LTTNG_UST_TRIGGER_HT_SIZE]; +}; + #define LTTNG_UST_ENUM_HT_BITS 12 #define LTTNG_UST_ENUM_HT_SIZE (1U << LTTNG_UST_ENUM_HT_BITS) @@ -615,6 +637,17 @@ struct lttng_session { struct lttng_ctx *ctx; /* contexts for filters. */ }; +struct lttng_trigger_group { + int objd; + void *owner; + int notification_fd; + struct cds_list_head node; /* Trigger group handle list */ + struct cds_list_head enablers_head; + struct cds_list_head triggers_head; /* list of triggers */ + struct lttng_ust_trigger_ht triggers_ht; /* hashtable of triggers */ + struct lttng_ctx *ctx; /* contexts for filters. */ +}; + struct lttng_transport { char *name; struct cds_list_head node; @@ -628,6 +661,8 @@ int lttng_session_disable(struct lttng_session *session); int lttng_session_statedump(struct lttng_session *session); void lttng_session_destroy(struct lttng_session *session); +void lttng_trigger_send_notification(struct lttng_trigger *trigger); + struct lttng_channel *lttng_channel_create(struct lttng_session *session, const char *transport_name, void *buf_addr, @@ -641,18 +676,6 @@ struct lttng_channel *lttng_channel_create(struct lttng_session *session, int lttng_channel_enable(struct lttng_channel *channel); int lttng_channel_disable(struct lttng_channel *channel); -struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type, - struct lttng_ust_event *event_param, - struct lttng_channel *chan); -int lttng_enabler_enable(struct lttng_enabler *enabler); -int lttng_enabler_disable(struct lttng_enabler *enabler); -int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler, - struct lttng_ust_filter_bytecode_node *bytecode); -int lttng_enabler_attach_context(struct lttng_enabler *enabler, - struct lttng_ust_context *ctx); -int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler, - struct lttng_ust_excluder_node *excluder); - int lttng_attach_context(struct lttng_ust_context *context_param, union ust_args *uargs, struct lttng_ctx **ctx, struct lttng_session *session); @@ -755,8 +778,6 @@ void lttng_probes_prune_field_list(struct lttng_ust_field_list *list); struct lttng_ust_field_iter * lttng_ust_field_list_get_iter_next(struct lttng_ust_field_list *list); -void lttng_enabler_event_link_bytecode(struct lttng_event *event, - struct lttng_enabler *enabler); void lttng_free_event_filter_runtime(struct lttng_event *event); void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime); @@ -778,6 +799,20 @@ extern struct lttng_ctx *lttng_static_ctx; void lttng_context_init(void); void lttng_context_exit(void); void lttng_filter_event_link_bytecode(struct lttng_event *event); +struct lttng_enabler *lttng_enabler_create( + enum lttng_enabler_format_type format_type, + struct lttng_ust_event *event_param, + struct lttng_channel *chan); +int lttng_enabler_enable(struct lttng_enabler *enabler); +int lttng_enabler_disable(struct lttng_enabler *enabler); +int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler, + struct lttng_ust_filter_bytecode_node *bytecode); +int lttng_enabler_attach_context(struct lttng_enabler *enabler, + struct lttng_ust_context *ctx); +int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler, + struct lttng_ust_excluder_node *excluder); +void lttng_enabler_event_link_bytecode(struct lttng_event *event, + struct lttng_enabler *enabler); #ifdef __cplusplus } diff --git a/include/lttng/ust-tracepoint-event.h b/include/lttng/ust-tracepoint-event.h index 0360bb6c..5747b95a 100644 --- a/include/lttng/ust-tracepoint-event.h +++ b/include/lttng/ust-tracepoint-event.h @@ -367,6 +367,24 @@ static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); #include TRACEPOINT_INCLUDE +/* + * Stage 2.1 of tracepoint event generation. + * + * Create probe trigger callback prototypes. + */ + +/* Reset all macros within TRACEPOINT_EVENT */ +#include + +#undef TP_ARGS +#define TP_ARGS(...) __VA_ARGS__ + +#undef TRACEPOINT_EVENT_CLASS +#define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ +static void __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); + +#include TRACEPOINT_INCLUDE + /* * Stage 3.0 of tracepoint event generation. * @@ -857,6 +875,48 @@ static const char __tp_event_signature___##_provider##___##_name[] = \ #undef _TP_EXTRACT_STRING2 +/* + * Stage 5.2 of tracepoint event generation. + * + * Create the trigger probe function. + */ +#undef TRACEPOINT_EVENT_CLASS +#define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ +static lttng_ust_notrace \ +void __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); \ +static \ +void __trigger_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)) \ +{ \ + struct lttng_trigger *__trigger = (struct lttng_trigger *) __tp_data; \ + \ + union { \ + size_t __dynamic_len[_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1]; \ + char __filter_stack_data[2 * sizeof(unsigned long) * (_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name) - 1)]; \ + } __stackvar; \ + if (caa_unlikely(!CMM_ACCESS_ONCE(__trigger->enabled))) \ + return; \ + if (caa_unlikely(!TP_RCU_LINK_TEST())) \ + return; \ + if (caa_unlikely(!cds_list_empty(&__trigger->bytecode_runtime_head))) { \ + struct lttng_bytecode_runtime *bc_runtime; \ + int __filter_record = __trigger->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(bc_runtime, &__trigger->bytecode_runtime_head, node) { \ + if (caa_unlikely(bc_runtime->filter(bc_runtime, \ + __stackvar.__filter_stack_data) & LTTNG_FILTER_RECORD_FLAG)) \ + __filter_record = 1; \ + } \ + if (caa_likely(!__filter_record)) \ + return; \ + } \ + \ + lttng_trigger_send_notification(__trigger); \ +} + +#include TRACEPOINT_INCLUDE + /* * Stage 6 of tracepoint event generation. * @@ -952,6 +1012,7 @@ static const struct lttng_event_desc __event_desc___##_provider##_##_name = { .u = { \ .ext = { \ .model_emf_uri = &__ref_model_emf_uri___##_provider##___##_name, \ + .trigger_callback = (void (*)(void)) &__trigger_probe__##_provider##___##_template,\ }, \ }, \ }; diff --git a/include/ust-comm.h b/include/ust-comm.h index a5e09572..bbea6b14 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -89,6 +89,7 @@ struct ustcomm_ust_msg { uint32_t cmd; char padding[USTCOMM_MSG_PADDING1]; union { + struct lttng_ust_trigger trigger; struct lttng_ust_channel channel; struct lttng_ust_stream stream; struct lttng_ust_event event; @@ -220,6 +221,8 @@ ssize_t ustcomm_recv_channel_from_sessiond(int sock, int ustcomm_recv_stream_from_sessiond(int sock, uint64_t *memory_map_size, int *shm_fd, int *wakeup_fd); +ssize_t ustcomm_recv_trigger_notif_fd_from_sessiond(int sock, + int *trigger_notif_fd); /* * Returns 0 on success, negative error value on error. diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index 5b9cb853..836bb4dc 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -651,6 +651,46 @@ error_check: return len; } +ssize_t ustcomm_recv_trigger_notif_fd_from_sessiond(int sock, + int *_trigger_notif_fd) +{ + ssize_t nr_fd; + int trigger_notif_fd, ret; + + /* Receive trigger notification fd */ + lttng_ust_lock_fd_tracker(); + nr_fd = ustcomm_recv_fds_unix_sock(sock, &trigger_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(trigger_notif_fd); + if (ret < 0) { + ret = close(trigger_notif_fd); + if (ret) { + PERROR("close on trigger notif fd"); + } + ret = -EIO; + lttng_ust_unlock_fd_tracker(); + goto error; + } + + *_trigger_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) diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 914ce94e..405231b2 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -132,6 +132,8 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) break; case LTTNG_UST_OBJECT_TYPE_EVENT: case LTTNG_UST_OBJECT_TYPE_CONTEXT: + case LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP: + case LTTNG_UST_OBJECT_TYPE_TRIGGER: break; default: assert(0); @@ -418,6 +420,91 @@ int ustctl_stop_session(int sock, int handle) return ustctl_disable(sock, &obj); } +int ustctl_create_trigger_group(int sock, int pipe_fd, + struct lttng_ust_object_data **_trigger_group_data) +{ + struct lttng_ust_object_data *trigger_group_data; + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + ssize_t len; + int ret; + + if (!_trigger_group_data) + return -EINVAL; + + trigger_group_data = zmalloc(sizeof(*trigger_group_data)); + if (!trigger_group_data) + return -ENOMEM; + + trigger_group_data->type = LTTNG_UST_OBJECT_TYPE_TRIGGER_GROUP; + + memset(&lum, 0, sizeof(lum)); + lum.handle = LTTNG_UST_ROOT_HANDLE; + lum.cmd = LTTNG_UST_TRIGGER_GROUP_CREATE; + + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) { + return ret; + } + + /* Send trigger notification pipe. */ + len = ustcomm_send_fds_unix_sock(sock, &pipe_fd, 1); + if (len <= 0) { + return ret; + } + + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (ret) { + return ret; + } + + trigger_group_data->handle = lur.ret_val; + DBG("received trigger group handle %d", trigger_group_data->handle); + + *_trigger_group_data = trigger_group_data; + return 0; +} + +int ustctl_create_trigger(int sock, struct lttng_ust_trigger *trigger, + struct lttng_ust_object_data *trigger_group, + struct lttng_ust_object_data **_trigger_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + struct lttng_ust_object_data *trigger_data; + int ret; + + if (!trigger_group || !_trigger_data) + return -EINVAL; + + trigger_data = zmalloc(sizeof(*trigger_data)); + if (!trigger_data) + return -ENOMEM; + + trigger_data->type = LTTNG_UST_OBJECT_TYPE_TRIGGER; + + memset(&lum, 0, sizeof(lum)); + lum.handle = trigger_group->handle; + lum.cmd = LTTNG_UST_TRIGGER_CREATE; + + strncpy(lum.u.trigger.name, trigger->name, + LTTNG_UST_SYM_NAME_LEN); + lum.u.trigger.instrumentation = trigger->instrumentation; + lum.u.trigger.loglevel_type = trigger->loglevel_type; + lum.u.trigger.loglevel = trigger->loglevel; + lum.u.trigger.id = trigger->id; + ret = ustcomm_send_app_cmd(sock, &lum, &lur); + if (ret) { + free(trigger_data); + return ret; + } + trigger_data->handle = lur.ret_val; + DBG("received event handle %u", trigger_data->handle); + *_trigger_data = trigger_data; + + return ret; +} + int ustctl_tracepoint_list(int sock) { struct ustcomm_ust_msg lum; diff --git a/liblttng-ust/context-provider-internal.h b/liblttng-ust/context-provider-internal.h new file mode 100644 index 00000000..62487c33 --- /dev/null +++ b/liblttng-ust/context-provider-internal.h @@ -0,0 +1,37 @@ +#ifndef _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H +#define _LTTNG_UST_CONTEXT_PROVIDER_INTERNAL_H + +/* + * Copyright 2019 - Francis Deslauriers + * + * 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 +#include + +void lttng_ust_context_set_trigger_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 */ diff --git a/liblttng-ust/lttng-context-provider.c b/liblttng-ust/lttng-context-provider.c index 50f73c62..10c95a5e 100644 --- a/liblttng-ust/lttng-context-provider.c +++ b/liblttng-ust/lttng-context-provider.c @@ -27,8 +27,10 @@ #include #include + #include "lttng-tracer-core.h" #include "jhash.h" +#include "context-provider-internal.h" #include #define CONTEXT_PROVIDER_HT_BITS 12 @@ -90,9 +92,14 @@ int lttng_ust_context_provider_register(struct lttng_ust_context_provider *provi 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_trigger_group_provider(provider->name, + provider->get_size, provider->record, + provider->get_value); end: ust_unlock(); return ret; @@ -107,6 +114,11 @@ void lttng_ust_context_provider_unregister(struct lttng_ust_context_provider *pr 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_trigger_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(); diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 9b2d3c64..9dce3530 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -23,10 +23,10 @@ #define _GNU_SOURCE #define _LGPL_SOURCE #include -#include -#include -#include +#include #include +#include +#include #include #include #include @@ -34,13 +34,15 @@ #include #include #include +#include #include -#include "clock.h" #include +#include #include +#include +#include #include -#include #include #include @@ -49,6 +51,7 @@ #include #include #include +#include #include #include #include "error.h" @@ -60,9 +63,12 @@ #include "lttng-tracer.h" #include "lttng-tracer-core.h" #include "lttng-ust-statedump.h" +#include "share.h" +#include "ust-events-internal.h" #include "wait.h" #include "../libringbuffer/shm.h" #include "jhash.h" +#include "ust-abi.h" /* * All operations within this file are called by the communication @@ -70,6 +76,7 @@ */ static CDS_LIST_HEAD(sessions); +static CDS_LIST_HEAD(trigger_groups); struct cds_list_head *_lttng_get_sessions(void) { @@ -77,12 +84,15 @@ struct cds_list_head *_lttng_get_sessions(void) } static void _lttng_event_destroy(struct lttng_event *event); +static void _lttng_trigger_destroy(struct lttng_trigger *trigger); static void _lttng_enum_destroy(struct lttng_enum *_enum); static -void lttng_session_lazy_sync_enablers(struct lttng_session *session); +void lttng_session_lazy_sync_event_enablers(struct lttng_session *session); +static +void lttng_session_sync_event_enablers(struct lttng_session *session); static -void lttng_session_sync_enablers(struct lttng_session *session); +void lttng_trigger_group_sync_enablers(struct lttng_trigger_group *trigger_group); static void lttng_enabler_destroy(struct lttng_enabler *enabler); @@ -159,6 +169,25 @@ struct lttng_session *lttng_session_create(void) return session; } +struct lttng_trigger_group *lttng_trigger_group_create(void) +{ + struct lttng_trigger_group *trigger_group; + int i; + + trigger_group = zmalloc(sizeof(struct lttng_trigger_group)); + if (!trigger_group) + return NULL; + + CDS_INIT_LIST_HEAD(&trigger_group->enablers_head); + CDS_INIT_LIST_HEAD(&trigger_group->triggers_head); + for (i = 0; i < LTTNG_UST_TRIGGER_HT_SIZE; i++) + CDS_INIT_HLIST_HEAD(&trigger_group->triggers_ht.table[i]); + + cds_list_add(&trigger_group->node, &trigger_groups); + + return trigger_group; +} + /* * Only used internally at session destruction. */ @@ -195,6 +224,21 @@ void register_event(struct lttng_event *event) event->registered = 1; } +static +void register_trigger(struct lttng_trigger *trigger) +{ + int ret; + const struct lttng_event_desc *desc; + + assert(trigger->registered == 0); + desc = trigger->desc; + ret = __tracepoint_probe_register_queue_release(desc->name, + desc->u.ext.trigger_callback, trigger, desc->signature); + WARN_ON_ONCE(ret); + if (!ret) + trigger->registered = 1; +} + static void unregister_event(struct lttng_event *event) { @@ -211,6 +255,21 @@ void unregister_event(struct lttng_event *event) event->registered = 0; } +static +void unregister_trigger(struct lttng_trigger *trigger) +{ + int ret; + const struct lttng_event_desc *desc; + + assert(trigger->registered == 1); + desc = trigger->desc; + ret = __tracepoint_probe_unregister_queue_release(desc->name, + desc->u.ext.trigger_callback, trigger); + WARN_ON_ONCE(ret); + if (!ret) + trigger->registered = 0; +} + /* * Only used internally at session destruction. */ @@ -221,12 +280,22 @@ void _lttng_event_unregister(struct lttng_event *event) unregister_event(event); } +/* + * Only used internally at session destruction. + */ +static +void _lttng_trigger_unregister(struct lttng_trigger *trigger) +{ + if (trigger->registered) + unregister_trigger(trigger); +} + void lttng_session_destroy(struct lttng_session *session) { struct lttng_channel *chan, *tmpchan; struct lttng_event *event, *tmpevent; struct lttng_enum *_enum, *tmp_enum; - struct lttng_enabler *enabler, *tmpenabler; + struct lttng_event_enabler *event_enabler, *event_tmpenabler; CMM_ACCESS_ONCE(session->active) = 0; cds_list_for_each_entry(event, &session->events_head, node) { @@ -234,9 +303,9 @@ void lttng_session_destroy(struct lttng_session *session) } synchronize_trace(); /* Wait for in-flight events to complete */ __tracepoint_probe_prune_release_queue(); - cds_list_for_each_entry_safe(enabler, tmpenabler, + cds_list_for_each_entry_safe(event_enabler, event_tmpenabler, &session->enablers_head, node) - lttng_enabler_destroy(enabler); + lttng_event_enabler_destroy(event_enabler); cds_list_for_each_entry_safe(event, tmpevent, &session->events_head, node) _lttng_event_destroy(event); @@ -250,6 +319,83 @@ void lttng_session_destroy(struct lttng_session *session) free(session); } +void lttng_trigger_group_destroy( + struct lttng_trigger_group *trigger_group) +{ + int close_ret; + struct lttng_trigger_enabler *trigger_enabler, *tmptrigger_enabler; + struct lttng_trigger *trigger, *tmptrigger; + + if (!trigger_group) { + return; + } + + cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node) + _lttng_trigger_unregister(trigger); + + synchronize_trace(); + + cds_list_for_each_entry_safe(trigger_enabler, tmptrigger_enabler, + &trigger_group->enablers_head, node) + lttng_trigger_enabler_destroy(trigger_enabler); + + cds_list_for_each_entry_safe(trigger, tmptrigger, + &trigger_group->triggers_head, node) + _lttng_trigger_destroy(trigger); + + /* Close the notification fd to the listener of triggers. */ + + lttng_ust_lock_fd_tracker(); + close_ret = close(trigger_group->notification_fd); + if (!close_ret) { + lttng_ust_delete_fd_from_tracker(trigger_group->notification_fd); + } else { + PERROR("close"); + abort(); + } + lttng_ust_unlock_fd_tracker(); + + cds_list_del(&trigger_group->node); + + free(trigger_group); +} + +static +void lttng_enabler_destroy(struct lttng_enabler *enabler) +{ + struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node; + struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node; + + if (!enabler) { + return; + } + + /* Destroy filter bytecode */ + cds_list_for_each_entry_safe(filter_node, tmp_filter_node, + &enabler->filter_bytecode_head, node) { + free(filter_node); + } + + /* Destroy excluders */ + cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node, + &enabler->excluder_head, node) { + free(excluder_node); + } +} + + void lttng_trigger_enabler_destroy(struct lttng_trigger_enabler *trigger_enabler) +{ + if (!trigger_enabler) { + return; + } + + cds_list_del(&trigger_enabler->node); + + lttng_enabler_destroy(lttng_trigger_enabler_as_enabler(trigger_enabler)); + + free(trigger_enabler); +} + static int lttng_enum_create(const struct lttng_enum_desc *desc, struct lttng_session *session) @@ -416,7 +562,7 @@ int lttng_session_enable(struct lttng_session *session) session->tstate = 1; /* We need to sync enablers with session before activation. */ - lttng_session_sync_enablers(session); + lttng_session_sync_event_enablers(session); /* * Snapshot the number of events per channel to know the type of header @@ -485,7 +631,7 @@ int lttng_session_disable(struct lttng_session *session) /* Set transient enabler state to "disabled" */ session->tstate = 0; - lttng_session_sync_enablers(session); + lttng_session_sync_event_enablers(session); end: return ret; } @@ -500,7 +646,7 @@ int lttng_channel_enable(struct lttng_channel *channel) } /* Set transient enabler state to "enabled" */ channel->tstate = 1; - lttng_session_sync_enablers(channel->session); + lttng_session_sync_event_enablers(channel->session); /* Set atomically the state to "enabled" */ CMM_ACCESS_ONCE(channel->enabled) = 1; end: @@ -519,11 +665,28 @@ int lttng_channel_disable(struct lttng_channel *channel) CMM_ACCESS_ONCE(channel->enabled) = 0; /* Set transient enabler state to "enabled" */ channel->tstate = 0; - lttng_session_sync_enablers(channel->session); + lttng_session_sync_event_enablers(channel->session); end: return ret; } +static inline +struct cds_hlist_head *borrow_hash_table_bucket( + struct cds_hlist_head *hash_table, + unsigned int hash_table_size, + const struct lttng_event_desc *desc) +{ + const char *event_name; + size_t name_len; + uint32_t hash; + + event_name = desc->name; + name_len = strlen(event_name); + + hash = jhash(event_name, name_len, 0); + return &hash_table[hash & (hash_table_size - 1)]; +} + /* * Supports event creation while tracing session is active. */ @@ -531,18 +694,15 @@ static int lttng_event_create(const struct lttng_event_desc *desc, struct lttng_channel *chan) { - const char *event_name = desc->name; struct lttng_event *event; struct lttng_session *session = chan->session; struct cds_hlist_head *head; int ret = 0; - size_t name_len = strlen(event_name); - uint32_t hash; int notify_socket, loglevel; const char *uri; - hash = jhash(event_name, name_len, 0); - head = &chan->session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; + head = borrow_hash_table_bucket(chan->session->events_ht.table, + LTTNG_UST_EVENT_HT_SIZE, desc); notify_socket = lttng_get_notify_socket(session->owner); if (notify_socket < 0) { @@ -588,7 +748,7 @@ int lttng_event_create(const struct lttng_event_desc *desc, session, session->objd, chan->objd, - event_name, + desc->name, loglevel, desc->signature, desc->nr_fields, @@ -612,6 +772,66 @@ socket_error: return ret; } +static +int lttng_trigger_create(const struct lttng_event_desc *desc, + uint64_t id, struct lttng_trigger_group *trigger_group) +{ + struct lttng_trigger *trigger; + struct cds_hlist_head *head; + int ret = 0; + + /* + * Get the hashtable bucket the created lttng_trigger object should be + * inserted. + */ + head = borrow_hash_table_bucket(trigger_group->triggers_ht.table, + LTTNG_UST_TRIGGER_HT_SIZE, desc); + + trigger = zmalloc(sizeof(struct lttng_trigger)); + if (!trigger) { + ret = -ENOMEM; + goto error; + } + + trigger->group = trigger_group; + trigger->id = id; + + /* Trigger will be enabled by enabler sync. */ + trigger->enabled = 0; + trigger->registered = 0; + + CDS_INIT_LIST_HEAD(&trigger->bytecode_runtime_head); + CDS_INIT_LIST_HEAD(&trigger->enablers_ref_head); + trigger->desc = desc; + + cds_list_add(&trigger->node, &trigger_group->triggers_head); + cds_hlist_add_head(&trigger->hlist, head); + + return 0; + +error: + return ret; +} + +static +void _lttng_trigger_destroy(struct lttng_trigger *trigger) +{ + struct lttng_enabler_ref *enabler_ref, *tmp_enabler_ref; + + /* Remove from trigger list. */ + cds_list_del(&trigger->node); + /* Remove from trigger hash table. */ + cds_hlist_del(&trigger->hlist); + + lttng_free_trigger_filter_runtime(trigger); + + /* Free trigger enabler refs */ + cds_list_for_each_entry_safe(enabler_ref, tmp_enabler_ref, + &trigger->enablers_ref_head, node) + free(enabler_ref); + free(trigger); +} + static int lttng_desc_match_star_glob_enabler(const struct lttng_event_desc *desc, struct lttng_enabler *enabler) @@ -619,7 +839,7 @@ int lttng_desc_match_star_glob_enabler(const struct lttng_event_desc *desc, int loglevel = 0; unsigned int has_loglevel = 0; - assert(enabler->type == LTTNG_ENABLER_STAR_GLOB); + assert(enabler->format_type == LTTNG_ENABLER_FORMAT_STAR_GLOB); if (!strutils_star_glob_match(enabler->event_param.name, SIZE_MAX, desc->name, SIZE_MAX)) return 0; @@ -642,7 +862,7 @@ int lttng_desc_match_event_enabler(const struct lttng_event_desc *desc, int loglevel = 0; unsigned int has_loglevel = 0; - assert(enabler->type == LTTNG_ENABLER_EVENT); + assert(enabler->format_type == LTTNG_ENABLER_FORMAT_EVENT); if (strcmp(desc->name, enabler->event_param.name)) return 0; if (desc->loglevel) { @@ -661,8 +881,8 @@ static int lttng_desc_match_enabler(const struct lttng_event_desc *desc, struct lttng_enabler *enabler) { - switch (enabler->type) { - case LTTNG_ENABLER_STAR_GLOB: + switch (enabler->format_type) { + case LTTNG_ENABLER_FORMAT_STAR_GLOB: { struct lttng_ust_excluder_node *excluder; @@ -690,7 +910,7 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, } return 1; } - case LTTNG_ENABLER_EVENT: + case LTTNG_ENABLER_FORMAT_EVENT: return lttng_desc_match_event_enabler(desc, enabler); default: return -EINVAL; @@ -698,24 +918,40 @@ int lttng_desc_match_enabler(const struct lttng_event_desc *desc, } static -int lttng_event_match_enabler(struct lttng_event *event, - struct lttng_enabler *enabler) +int lttng_event_enabler_match_event(struct lttng_event_enabler *event_enabler, + struct lttng_event *event) +{ + if (lttng_desc_match_enabler(event->desc, + lttng_event_enabler_as_enabler(event_enabler)) + && event->chan == event_enabler->chan) + return 1; + else + return 0; +} + +static +int lttng_trigger_enabler_match_trigger( + struct lttng_trigger_enabler *trigger_enabler, + struct lttng_trigger *trigger) { - if (lttng_desc_match_enabler(event->desc, enabler) - && event->chan == enabler->chan) + int desc_matches = lttng_desc_match_enabler(trigger->desc, + lttng_trigger_enabler_as_enabler(trigger_enabler)); + + if (desc_matches && trigger->group == trigger_enabler->group && + trigger->id == trigger_enabler->id) return 1; else return 0; } static -struct lttng_enabler_ref * lttng_event_enabler_ref(struct lttng_event *event, +struct lttng_enabler_ref *lttng_enabler_ref( + struct cds_list_head *enabler_ref_list, struct lttng_enabler *enabler) { struct lttng_enabler_ref *enabler_ref; - cds_list_for_each_entry(enabler_ref, - &event->enablers_ref_head, node) { + cds_list_for_each_entry(enabler_ref, enabler_ref_list, node) { if (enabler_ref->ref == enabler) return enabler_ref; } @@ -727,9 +963,9 @@ struct lttng_enabler_ref * lttng_event_enabler_ref(struct lttng_event *event, * tracepoint probes. */ static -void lttng_create_event_if_missing(struct lttng_enabler *enabler) +void lttng_create_event_if_missing(struct lttng_event_enabler *event_enabler) { - struct lttng_session *session = enabler->chan->session; + struct lttng_session *session = event_enabler->chan->session; struct lttng_probe_desc *probe_desc; const struct lttng_event_desc *desc; struct lttng_event *event; @@ -748,24 +984,19 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) bool found = false; struct cds_hlist_head *head; struct cds_hlist_node *node; - const char *event_name; - size_t name_len; - uint32_t hash; desc = probe_desc->event_desc[i]; - if (!lttng_desc_match_enabler(desc, enabler)) + if (!lttng_desc_match_enabler(desc, + lttng_event_enabler_as_enabler(event_enabler))) continue; - event_name = desc->name; - name_len = strlen(event_name); - /* - * Check if already created. - */ - hash = jhash(event_name, name_len, 0); - head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; + head = borrow_hash_table_bucket( + session->events_ht.table, + LTTNG_UST_EVENT_HT_SIZE, desc); + cds_hlist_for_each_entry(event, node, head, hlist) { if (event->desc == desc - && event->chan == enabler->chan) { + && event->chan == event_enabler->chan) { found = true; break; } @@ -778,7 +1009,7 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) * event probe. */ ret = lttng_event_create(probe_desc->event_desc[i], - enabler->chan); + event_enabler->chan); if (ret) { DBG("Unable to create event %s, error %d\n", probe_desc->event_desc[i]->name, ret); @@ -787,54 +1018,127 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) } } -/* - * Iterate over all the UST sessions to unregister and destroy all probes from - * the probe provider descriptor received as argument. Must me called with the - * ust_lock held. - */ -void lttng_probe_provider_unregister_events(struct lttng_probe_desc *provider_desc) +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 (*trigger_func)(struct lttng_trigger *trigger)) { struct cds_hlist_node *node, *tmp_node; struct cds_list_head *sessionsp; - struct lttng_session *session; - struct cds_hlist_head *head; - struct lttng_event *event; - unsigned int i, j; + unsigned int i; /* Get handle on list of sessions. */ sessionsp = _lttng_get_sessions(); /* - * Iterate over all events in the probe provider descriptions and sessions - * to queue the unregistration of the events. + * Iterate over all events in the probe provider descriptions and + * sessions to queue the unregistration of the events. */ for (i = 0; i < provider_desc->nr_events; i++) { const struct lttng_event_desc *event_desc; - const char *event_name; - size_t name_len; - uint32_t hash; + struct lttng_trigger_group *trigger_group; + struct lttng_trigger *trigger; + struct lttng_session *session; + struct cds_hlist_head *head; + struct lttng_event *event; event_desc = provider_desc->event_desc[i]; - event_name = event_desc->name; - name_len = strlen(event_name); - hash = jhash(event_name, name_len, 0); - /* Iterate over all session to find the current event description. */ + /* + * Iterate over all session to find the current event + * description. + */ cds_list_for_each_entry(session, sessionsp, node) { /* - * Get the list of events in the hashtable bucket and iterate to - * find the event matching this descriptor. + * Get the list of events in the hashtable bucket and + * iterate to find the event matching this descriptor. */ - head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; - cds_hlist_for_each_entry(event, node, head, hlist) { + head = borrow_hash_table_bucket( + session->events_ht.table, + LTTNG_UST_EVENT_HT_SIZE, event_desc); + + cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) { if (event_desc == event->desc) { - /* Queue the unregistration of this event. */ - _lttng_event_unregister(event); + event_func(session, event); + break; + } + } + } + + /* + * Iterate over all trigger groups to find the current event + * description. + */ + cds_list_for_each_entry(trigger_group, &trigger_groups, node) { + /* + * Get the list of triggers in the hashtable bucket and + * iterate to find the trigger matching this + * descriptor. + */ + head = borrow_hash_table_bucket( + trigger_group->triggers_ht.table, + LTTNG_UST_TRIGGER_HT_SIZE, event_desc); + + cds_hlist_for_each_entry_safe(trigger, node, tmp_node, head, hlist) { + if (event_desc == trigger->desc) { + trigger_func(trigger); break; } } } } +} + +static +void _unregister_event(struct lttng_session *session, + struct lttng_event *event) +{ + _lttng_event_unregister(event); +} + +static +void _event_enum_destroy(struct lttng_session *session, + struct lttng_event *event) +{ + unsigned int i; + + /* Destroy enums of the current event. */ + for (i = 0; i < event->desc->nr_fields; i++) { + const struct lttng_enum_desc *enum_desc; + const struct lttng_event_field *field; + struct lttng_enum *curr_enum; + + field = &(event->desc->fields[i]); + if (field->type.atype != atype_enum) { + continue; + } + + enum_desc = field->type.u.basic.enumeration.desc; + curr_enum = lttng_ust_enum_get_from_desc(session, enum_desc); + if (curr_enum) { + _lttng_enum_destroy(curr_enum); + } + } + + /* Destroy event. */ + _lttng_event_destroy(event); +} + +/* + * Iterate over all the UST sessions to unregister and destroy all probes from + * the probe provider descriptor received as argument. Must me called with the + * ust_lock held. + */ +void lttng_probe_provider_unregister_events( + struct lttng_probe_desc *provider_desc) +{ + /* + * 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, + _lttng_trigger_unregister); /* Wait for grace period. */ synchronize_trace(); @@ -845,74 +1149,32 @@ void lttng_probe_provider_unregister_events(struct lttng_probe_desc *provider_de * It is now safe to destroy the events and remove them from the event list * and hashtables. */ - for (i = 0; i < provider_desc->nr_events; i++) { - const struct lttng_event_desc *event_desc; - const char *event_name; - size_t name_len; - uint32_t hash; - - event_desc = provider_desc->event_desc[i]; - event_name = event_desc->name; - name_len = strlen(event_name); - hash = jhash(event_name, name_len, 0); - - /* Iterate over all sessions to find the current event description. */ - cds_list_for_each_entry(session, sessionsp, node) { - /* - * Get the list of events in the hashtable bucket and iterate to - * find the event matching this descriptor. - */ - head = &session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; - cds_hlist_for_each_entry_safe(event, node, tmp_node, head, hlist) { - if (event_desc == event->desc) { - /* Destroy enums of the current event. */ - for (j = 0; j < event->desc->nr_fields; j++) { - const struct lttng_enum_desc *enum_desc; - const struct lttng_event_field *field; - struct lttng_enum *curr_enum; - - field = &(event->desc->fields[j]); - if (field->type.atype != atype_enum) { - continue; - } - - enum_desc = field->type.u.basic.enumeration.desc; - curr_enum = lttng_ust_enum_get_from_desc(session, enum_desc); - if (curr_enum) { - _lttng_enum_destroy(curr_enum); - } - } - - /* Destroy event. */ - _lttng_event_destroy(event); - break; - } - } - } - } + probe_provider_event_for_each(provider_desc, _event_enum_destroy, + _lttng_trigger_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 -int lttng_enabler_ref_events(struct lttng_enabler *enabler) +int lttng_event_enabler_ref_events(struct lttng_event_enabler *event_enabler) { - struct lttng_session *session = enabler->chan->session; + struct lttng_session *session = event_enabler->chan->session; struct lttng_event *event; /* First ensure that probe events are created for this enabler. */ - lttng_create_event_if_missing(enabler); + lttng_create_event_if_missing(event_enabler); /* For each event matching enabler in session event list. */ cds_list_for_each_entry(event, &session->events_head, node) { struct lttng_enabler_ref *enabler_ref; - if (!lttng_event_match_enabler(event, enabler)) + if (!lttng_event_enabler_match_event(event_enabler, event)) continue; - enabler_ref = lttng_event_enabler_ref(event, enabler); + enabler_ref = lttng_enabler_ref(&event->enablers_ref_head, + lttng_event_enabler_as_enabler(event_enabler)); if (!enabler_ref) { /* * If no backward ref, create it. @@ -921,7 +1183,7 @@ int lttng_enabler_ref_events(struct lttng_enabler *enabler) enabler_ref = zmalloc(sizeof(*enabler_ref)); if (!enabler_ref) return -ENOMEM; - enabler_ref->ref = enabler; + enabler_ref->ref = lttng_event_enabler_as_enabler(event_enabler); cds_list_add(&enabler_ref->node, &event->enablers_ref_head); } @@ -929,7 +1191,10 @@ int lttng_enabler_ref_events(struct lttng_enabler *enabler) /* * Link filter bytecodes if not linked yet. */ - lttng_enabler_event_link_bytecode(event, enabler); + lttng_enabler_link_bytecode(event->desc, + &session->ctx, + &event->bytecode_runtime_head, + lttng_event_enabler_as_enabler(event_enabler)); /* TODO: merge event context. */ } @@ -946,7 +1211,17 @@ int lttng_fix_pending_events(void) struct lttng_session *session; cds_list_for_each_entry(session, &sessions, node) { - lttng_session_lazy_sync_enablers(session); + lttng_session_lazy_sync_event_enablers(session); + } + return 0; +} + +int lttng_fix_pending_triggers(void) +{ + struct lttng_trigger_group *trigger_group; + + cds_list_for_each_entry(trigger_group, &trigger_groups, node) { + lttng_trigger_group_sync_enablers(trigger_group); } return 0; } @@ -1020,57 +1295,148 @@ void lttng_ust_events_exit(void) /* * Enabler management. */ -struct lttng_enabler *lttng_enabler_create(enum lttng_enabler_type type, +struct lttng_event_enabler *lttng_event_enabler_create( + enum lttng_enabler_format_type format_type, struct lttng_ust_event *event_param, struct lttng_channel *chan) { - struct lttng_enabler *enabler; + struct lttng_event_enabler *event_enabler; - enabler = zmalloc(sizeof(*enabler)); - if (!enabler) + event_enabler = zmalloc(sizeof(*event_enabler)); + if (!event_enabler) return NULL; - enabler->type = type; - CDS_INIT_LIST_HEAD(&enabler->filter_bytecode_head); - CDS_INIT_LIST_HEAD(&enabler->excluder_head); - memcpy(&enabler->event_param, event_param, - sizeof(enabler->event_param)); - enabler->chan = chan; + event_enabler->base.format_type = format_type; + CDS_INIT_LIST_HEAD(&event_enabler->base.filter_bytecode_head); + CDS_INIT_LIST_HEAD(&event_enabler->base.excluder_head); + memcpy(&event_enabler->base.event_param, event_param, + sizeof(event_enabler->base.event_param)); + event_enabler->chan = chan; /* ctx left NULL */ - enabler->enabled = 0; - cds_list_add(&enabler->node, &enabler->chan->session->enablers_head); - lttng_session_lazy_sync_enablers(enabler->chan->session); - return enabler; + event_enabler->base.enabled = 0; + cds_list_add(&event_enabler->node, &event_enabler->chan->session->enablers_head); + lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + + return event_enabler; } -int lttng_enabler_enable(struct lttng_enabler *enabler) +struct lttng_trigger_enabler *lttng_trigger_enabler_create( + struct lttng_trigger_group *trigger_group, + enum lttng_enabler_format_type format_type, + struct lttng_ust_trigger *trigger_param) { - enabler->enabled = 1; - lttng_session_lazy_sync_enablers(enabler->chan->session); + struct lttng_trigger_enabler *trigger_enabler; + + trigger_enabler = zmalloc(sizeof(*trigger_enabler)); + if (!trigger_enabler) + return NULL; + trigger_enabler->base.format_type = format_type; + CDS_INIT_LIST_HEAD(&trigger_enabler->base.filter_bytecode_head); + CDS_INIT_LIST_HEAD(&trigger_enabler->base.excluder_head); + + trigger_enabler->id = trigger_param->id; + + memcpy(&trigger_enabler->base.event_param.name, trigger_param->name, + sizeof(trigger_enabler->base.event_param.name)); + trigger_enabler->base.event_param.instrumentation = trigger_param->instrumentation; + trigger_enabler->base.event_param.loglevel = trigger_param->loglevel; + trigger_enabler->base.event_param.loglevel_type = trigger_param->loglevel_type; + + trigger_enabler->base.enabled = 0; + trigger_enabler->group = trigger_group; + + cds_list_add(&trigger_enabler->node, &trigger_group->enablers_head); + + lttng_trigger_group_sync_enablers(trigger_group); + + return trigger_enabler; +} + +int lttng_event_enabler_enable(struct lttng_event_enabler *event_enabler) +{ + lttng_event_enabler_as_enabler(event_enabler)->enabled = 1; + lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + return 0; } -int lttng_enabler_disable(struct lttng_enabler *enabler) +int lttng_event_enabler_disable(struct lttng_event_enabler *event_enabler) { - enabler->enabled = 0; - lttng_session_lazy_sync_enablers(enabler->chan->session); + lttng_event_enabler_as_enabler(event_enabler)->enabled = 0; + lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + return 0; } -int lttng_enabler_attach_bytecode(struct lttng_enabler *enabler, +static +void _lttng_enabler_attach_bytecode(struct lttng_enabler *enabler, struct lttng_ust_filter_bytecode_node *bytecode) { bytecode->enabler = enabler; cds_list_add_tail(&bytecode->node, &enabler->filter_bytecode_head); - lttng_session_lazy_sync_enablers(enabler->chan->session); +} + +int lttng_event_enabler_attach_bytecode(struct lttng_event_enabler *event_enabler, + struct lttng_ust_filter_bytecode_node *bytecode) +{ + _lttng_enabler_attach_bytecode( + lttng_event_enabler_as_enabler(event_enabler), bytecode); + + lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); return 0; } -int lttng_enabler_attach_exclusion(struct lttng_enabler *enabler, +static +void _lttng_enabler_attach_exclusion(struct lttng_enabler *enabler, struct lttng_ust_excluder_node *excluder) { excluder->enabler = enabler; cds_list_add_tail(&excluder->node, &enabler->excluder_head); - lttng_session_lazy_sync_enablers(enabler->chan->session); +} + +int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *event_enabler, + struct lttng_ust_excluder_node *excluder) +{ + _lttng_enabler_attach_exclusion( + lttng_event_enabler_as_enabler(event_enabler), excluder); + + lttng_session_lazy_sync_event_enablers(event_enabler->chan->session); + return 0; +} + +int lttng_trigger_enabler_enable(struct lttng_trigger_enabler *trigger_enabler) +{ + lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled = 1; + lttng_trigger_group_sync_enablers(trigger_enabler->group); + + return 0; +} + +int lttng_trigger_enabler_disable(struct lttng_trigger_enabler *trigger_enabler) +{ + lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled = 0; + lttng_trigger_group_sync_enablers(trigger_enabler->group); + + return 0; +} + +int lttng_trigger_enabler_attach_bytecode( struct lttng_trigger_enabler *trigger_enabler, + struct lttng_ust_filter_bytecode_node *bytecode) +{ + _lttng_enabler_attach_bytecode( + lttng_trigger_enabler_as_enabler(trigger_enabler), bytecode); + + lttng_trigger_group_sync_enablers(trigger_enabler->group); + return 0; +} + +int lttng_trigger_enabler_attach_exclusion( + struct lttng_trigger_enabler *trigger_enabler, + struct lttng_ust_excluder_node *excluder) +{ + _lttng_enabler_attach_exclusion( + lttng_trigger_enabler_as_enabler(trigger_enabler), excluder); + + lttng_trigger_group_sync_enablers(trigger_enabler->group); return 0; } @@ -1144,59 +1510,37 @@ int lttng_attach_context(struct lttng_ust_context *context_param, } } -int lttng_enabler_attach_context(struct lttng_enabler *enabler, +int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler, struct lttng_ust_context *context_param) { -#if 0 // disabled for now. - struct lttng_session *session = enabler->chan->session; - int ret; - - ret = lttng_attach_context(context_param, &enabler->ctx, - session); - if (ret) - return ret; - lttng_session_lazy_sync_enablers(enabler->chan->session); -#endif return -ENOSYS; } -static -void lttng_enabler_destroy(struct lttng_enabler *enabler) +void lttng_event_enabler_destroy(struct lttng_event_enabler *event_enabler) { - struct lttng_ust_filter_bytecode_node *filter_node, *tmp_filter_node; - struct lttng_ust_excluder_node *excluder_node, *tmp_excluder_node; - - /* Destroy filter bytecode */ - cds_list_for_each_entry_safe(filter_node, tmp_filter_node, - &enabler->filter_bytecode_head, node) { - free(filter_node); - } - - /* Destroy excluders */ - cds_list_for_each_entry_safe(excluder_node, tmp_excluder_node, - &enabler->excluder_head, node) { - free(excluder_node); + if (!event_enabler) { + return; } + cds_list_del(&event_enabler->node); - /* Destroy contexts */ - lttng_destroy_context(enabler->ctx); + lttng_enabler_destroy(lttng_event_enabler_as_enabler(event_enabler)); - cds_list_del(&enabler->node); - free(enabler); + lttng_destroy_context(event_enabler->ctx); + free(event_enabler); } /* - * lttng_session_sync_enablers should be called just before starting a + * lttng_session_sync_event_enablers should be called just before starting a * session. */ static -void lttng_session_sync_enablers(struct lttng_session *session) +void lttng_session_sync_event_enablers(struct lttng_session *session) { - struct lttng_enabler *enabler; + struct lttng_event_enabler *event_enabler; struct lttng_event *event; - cds_list_for_each_entry(enabler, &session->enablers_head, node) - lttng_enabler_ref_events(enabler); + cds_list_for_each_entry(event_enabler, &session->enablers_head, node) + lttng_event_enabler_ref_events(event_enabler); /* * For each event, if at least one of its enablers is enabled, * and its channel and session transient states are enabled, we @@ -1256,6 +1600,216 @@ void lttng_session_sync_enablers(struct lttng_session *session) __tracepoint_probe_prune_release_queue(); } +static +void lttng_create_trigger_if_missing(struct lttng_trigger_enabler *trigger_enabler) +{ + struct lttng_trigger_group *trigger_group = trigger_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_trigger *trigger; + struct cds_hlist_head *head; + struct cds_hlist_node *node; + + desc = probe_desc->event_desc[i]; + if (!lttng_desc_match_enabler(desc, + lttng_trigger_enabler_as_enabler(trigger_enabler))) + continue; + + /* + * Given the current trigger group, get the bucket that + * the target trigger would be if it was already + * created. + */ + head = borrow_hash_table_bucket( + trigger_group->triggers_ht.table, + LTTNG_UST_TRIGGER_HT_SIZE, desc); + + cds_hlist_for_each_entry(trigger, node, head, hlist) { + /* + * Check if trigger already exists by checking + * if the trigger and enabler share the same + * description and id. + */ + if (trigger->desc == desc && + trigger->id == trigger_enabler->id) { + found = true; + break; + } + } + + if (found) + continue; + + /* + * We need to create a trigger for this event probe. + */ + ret = lttng_trigger_create(desc, trigger_enabler->id, + trigger_group); + if (ret) { + DBG("Unable to create trigger %s, error %d\n", + probe_desc->event_desc[i]->name, ret); + } + } + } +} + +void lttng_trigger_send_notification(struct lttng_trigger *trigger) +{ + /* + * 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_trigger_notification notif; + ssize_t ret; + + assert(trigger); + assert(trigger->group); + assert(sizeof(notif) <= PIPE_BUF); + + notif.id = trigger->id; + + ret = patient_write(trigger->group->notification_fd, ¬if, + sizeof(notif)); + if (ret == -1) { + if (errno == EAGAIN) { + DBG("Cannot send trigger notification without blocking: %s", + strerror(errno)); + } else { + DBG("Error to sending trigger notification: %s", + strerror(errno)); + abort(); + } + } +} + +/* + * Create triggers associated with a trigger enabler (if not already present). + */ +static +int lttng_trigger_enabler_ref_triggers(struct lttng_trigger_enabler *trigger_enabler) +{ + struct lttng_trigger_group *trigger_group = trigger_enabler->group; + struct lttng_trigger *trigger; + + /* First, ensure that probe triggers are created for this enabler. */ + lttng_create_trigger_if_missing(trigger_enabler); + + /* Link the created trigger with its associated enabler. */ + cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node) { + struct lttng_enabler_ref *enabler_ref; + + if (!lttng_trigger_enabler_match_trigger(trigger_enabler, trigger)) + continue; + + enabler_ref = lttng_enabler_ref(&trigger->enablers_ref_head, + lttng_trigger_enabler_as_enabler(trigger_enabler)); + if (!enabler_ref) { + /* + * If no backward ref, create it. + * Add backward ref from trigger to enabler. + */ + enabler_ref = zmalloc(sizeof(*enabler_ref)); + if (!enabler_ref) + return -ENOMEM; + + enabler_ref->ref = lttng_trigger_enabler_as_enabler( + trigger_enabler); + cds_list_add(&enabler_ref->node, + &trigger->enablers_ref_head); + } + + /* + * Link filter bytecodes if not linked yet. + */ + lttng_enabler_link_bytecode(trigger->desc, + &trigger_group->ctx, &trigger->bytecode_runtime_head, + lttng_trigger_enabler_as_enabler(trigger_enabler)); + } + return 0; +} + +static +void lttng_trigger_group_sync_enablers(struct lttng_trigger_group *trigger_group) +{ + struct lttng_trigger_enabler *trigger_enabler; + struct lttng_trigger *trigger; + + cds_list_for_each_entry(trigger_enabler, &trigger_group->enablers_head, node) { + /* + * Only link enablers that are enabled to triggers, the user + * might still be attaching filter or exclusion to the + * trigger_enabler. + */ + if (!lttng_trigger_enabler_as_enabler(trigger_enabler)->enabled) + continue; + + lttng_trigger_enabler_ref_triggers(trigger_enabler); + } + + /* + * For each trigger, if at least one of its enablers is enabled, + * we enable the trigger, else we disable it. + */ + cds_list_for_each_entry(trigger, &trigger_group->triggers_head, node) { + struct lttng_enabler_ref *enabler_ref; + struct lttng_bytecode_runtime *runtime; + int enabled = 0, has_enablers_without_bytecode = 0; + + /* Enable triggers */ + cds_list_for_each_entry(enabler_ref, + &trigger->enablers_ref_head, node) { + if (enabler_ref->ref->enabled) { + enabled = 1; + break; + } + } + + CMM_STORE_SHARED(trigger->enabled, enabled); + /* + * Sync tracepoint registration with trigger enabled + * state. + */ + if (enabled) { + if (!trigger->registered) + register_trigger(trigger); + } else { + if (trigger->registered) + unregister_trigger(trigger); + } + + /* Check if has enablers without bytecode enabled */ + cds_list_for_each_entry(enabler_ref, + &trigger->enablers_ref_head, node) { + if (enabler_ref->ref->enabled + && cds_list_empty(&enabler_ref->ref->filter_bytecode_head)) { + has_enablers_without_bytecode = 1; + break; + } + } + trigger->has_enablers_without_bytecode = + has_enablers_without_bytecode; + + /* Enable filters */ + cds_list_for_each_entry(runtime, + &trigger->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 @@ -1263,12 +1817,12 @@ void lttng_session_sync_enablers(struct lttng_session *session) * "lazy" sync means we only sync if required. */ static -void lttng_session_lazy_sync_enablers(struct lttng_session *session) +void lttng_session_lazy_sync_event_enablers(struct lttng_session *session) { /* We can skip if session is not active */ if (!session->active) return; - lttng_session_sync_enablers(session); + lttng_session_sync_event_enablers(session); } /* @@ -1311,3 +1865,30 @@ void lttng_ust_context_set_session_provider(const char *name, } } } + +/* + * Update all trigger 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_trigger_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_trigger_group *trigger_group; + + cds_list_for_each_entry(trigger_group, &trigger_groups, node) { + int ret; + + ret = lttng_ust_context_set_provider_rcu(&trigger_group->ctx, + name, get_size, record, get_value); + if (ret) + abort(); + } +} diff --git a/liblttng-ust/lttng-filter-interpreter.c b/liblttng-ust/lttng-filter-interpreter.c index f246ce2a..04d0c073 100644 --- a/liblttng-ust/lttng-filter-interpreter.c +++ b/liblttng-ust/lttng-filter-interpreter.c @@ -338,7 +338,7 @@ static int context_get_index(struct lttng_ctx *ctx, return 0; } -static int dynamic_get_index(struct lttng_session *session, +static int dynamic_get_index(struct lttng_ctx *ctx, struct bytecode_runtime *runtime, uint64_t index, struct estack_entry *stack_top) { @@ -405,9 +405,6 @@ static int dynamic_get_index(struct lttng_session *session, case LOAD_ROOT_CONTEXT: case LOAD_ROOT_APP_CONTEXT: /* Fall-through */ { - struct lttng_ctx *ctx; - - ctx = rcu_dereference(session->ctx); ret = context_get_index(ctx, &stack_top->u.ptr, gid->ctx_index); @@ -602,7 +599,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, const char *filter_stack_data) { struct bytecode_runtime *bytecode = filter_data; - struct lttng_session *session = bytecode->p.session; + struct lttng_ctx *ctx = rcu_dereference(*bytecode->p.ctx); void *pc, *next_pc, *start_pc; int ret = -EINVAL; uint64_t retval = 0; @@ -1981,13 +1978,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx *ctx; struct lttng_ctx_field *ctx_field; struct lttng_ctx_value v; dbg_printf("get context ref offset %u type dynamic\n", ref->offset); - ctx = rcu_dereference(session->ctx); ctx_field = &ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); @@ -2031,13 +2026,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx *ctx; struct lttng_ctx_field *ctx_field; struct lttng_ctx_value v; dbg_printf("get context ref offset %u type string\n", ref->offset); - ctx = rcu_dereference(session->ctx); ctx_field = &ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); @@ -2060,13 +2053,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx *ctx; struct lttng_ctx_field *ctx_field; struct lttng_ctx_value v; dbg_printf("get context ref offset %u type s64\n", ref->offset); - ctx = rcu_dereference(session->ctx); ctx_field = &ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); @@ -2081,13 +2072,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx *ctx; struct lttng_ctx_field *ctx_field; struct lttng_ctx_value v; dbg_printf("get context ref offset %u type double\n", ref->offset); - ctx = rcu_dereference(session->ctx); ctx_field = &ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); @@ -2173,7 +2162,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, struct get_index_u16 *index = (struct get_index_u16 *) insn->data; dbg_printf("op get index u16\n"); - ret = dynamic_get_index(session, bytecode, index->index, estack_ax(stack, top)); + ret = dynamic_get_index(ctx, bytecode, index->index, estack_ax(stack, top)); if (ret) goto end; estack_ax_v = estack_ax(stack, top)->u.v; @@ -2188,7 +2177,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, struct get_index_u64 *index = (struct get_index_u64 *) insn->data; dbg_printf("op get index u64\n"); - ret = dynamic_get_index(session, bytecode, index->index, estack_ax(stack, top)); + ret = dynamic_get_index(ctx, bytecode, index->index, estack_ax(stack, top)); if (ret) goto end; estack_ax_v = estack_ax(stack, top)->u.v; diff --git a/liblttng-ust/lttng-filter-specialize.c b/liblttng-ust/lttng-filter-specialize.c index 39730f8c..9b38fa69 100644 --- a/liblttng-ust/lttng-filter-specialize.c +++ b/liblttng-ust/lttng-filter-specialize.c @@ -436,7 +436,7 @@ static int specialize_load_object(const struct lttng_event_field *field, return 0; } -static int specialize_context_lookup(struct lttng_session *session, +static int specialize_context_lookup(struct lttng_ctx *ctx, struct bytecode_runtime *runtime, struct load_op *insn, struct vstack_load *load) @@ -447,11 +447,11 @@ static int specialize_context_lookup(struct lttng_session *session, struct filter_get_index_data gid; ssize_t data_offset; - idx = specialize_context_lookup_name(session->ctx, runtime, insn); + idx = specialize_context_lookup_name(ctx, runtime, insn); if (idx < 0) { return -ENOENT; } - ctx_field = &session->ctx->fields[idx]; + ctx_field = &ctx->fields[idx]; field = &ctx_field->event_field; ret = specialize_load_object(field, load, true); if (ret) @@ -470,7 +470,7 @@ static int specialize_context_lookup(struct lttng_session *session, return 0; } -static int specialize_app_context_lookup(struct lttng_session *session, +static int specialize_app_context_lookup(struct lttng_ctx *ctx, struct bytecode_runtime *runtime, struct load_op *insn, struct vstack_load *load) @@ -493,19 +493,18 @@ static int specialize_app_context_lookup(struct lttng_session *session, } strcpy(name, "$app."); strcat(name, orig_name); - idx = lttng_get_context_index(session->ctx, name); + idx = lttng_get_context_index(ctx, name); if (idx < 0) { assert(lttng_context_is_app(name)); ret = lttng_ust_add_app_context_to_ctx_rcu(name, - &session->ctx); + &ctx); if (ret) return ret; - idx = lttng_get_context_index(session->ctx, - name); + idx = lttng_get_context_index(ctx, name); if (idx < 0) return -ENOENT; } - ctx_field = &session->ctx->fields[idx]; + ctx_field = &ctx->fields[idx]; field = &ctx_field->event_field; ret = specialize_load_object(field, load, true); if (ret) @@ -528,14 +527,13 @@ end: return ret; } -static int specialize_event_payload_lookup(struct lttng_event *event, +static int specialize_payload_lookup(const struct lttng_event_desc *event_desc, struct bytecode_runtime *runtime, struct load_op *insn, struct vstack_load *load) { const char *name; uint16_t offset; - const struct lttng_event_desc *desc = event->desc; unsigned int i, nr_fields; bool found = false; uint32_t field_offset = 0; @@ -544,11 +542,11 @@ static int specialize_event_payload_lookup(struct lttng_event *event, struct filter_get_index_data gid; ssize_t data_offset; - nr_fields = desc->nr_fields; + nr_fields = event_desc->nr_fields; offset = ((struct get_symbol *) insn->data)->offset; name = runtime->p.bc->bc.data + runtime->p.bc->bc.reloc_offset + offset; for (i = 0; i < nr_fields; i++) { - field = &desc->fields[i]; + field = &event_desc->fields[i]; if (!strcmp(field->name, name)) { found = true; break; @@ -601,14 +599,14 @@ end: return ret; } -int lttng_filter_specialize_bytecode(struct lttng_event *event, +int lttng_filter_specialize_bytecode(const struct lttng_event_desc *event_desc, struct bytecode_runtime *bytecode) { void *pc, *next_pc, *start_pc; int ret = -EINVAL; struct vstack _stack; struct vstack *stack = &_stack; - struct lttng_session *session = bytecode->p.session; + struct lttng_ctx *ctx = *bytecode->p.ctx; vstack_init(stack); @@ -1335,7 +1333,7 @@ int lttng_filter_specialize_bytecode(struct lttng_event *event, goto end; case LOAD_ROOT_CONTEXT: /* Lookup context field. */ - ret = specialize_context_lookup(session, + ret = specialize_context_lookup(ctx, bytecode, insn, &vstack_ax(stack)->load); if (ret) @@ -1343,7 +1341,7 @@ int lttng_filter_specialize_bytecode(struct lttng_event *event, break; case LOAD_ROOT_APP_CONTEXT: /* Lookup app context field. */ - ret = specialize_app_context_lookup(session, + ret = specialize_app_context_lookup(ctx, bytecode, insn, &vstack_ax(stack)->load); if (ret) @@ -1351,7 +1349,7 @@ int lttng_filter_specialize_bytecode(struct lttng_event *event, break; case LOAD_ROOT_PAYLOAD: /* Lookup event payload field. */ - ret = specialize_event_payload_lookup(event, + ret = specialize_payload_lookup(event_desc, bytecode, insn, &vstack_ax(stack)->load); if (ret) diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index ed41a0ef..6e1a8030 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -31,6 +31,7 @@ #include #include "lttng-filter.h" +#include "ust-events-internal.h" static const char *opnames[] = { [ FILTER_OP_UNKNOWN ] = "UNKNOWN", @@ -187,14 +188,13 @@ const char *print_op(enum filter_op op) } static -int apply_field_reloc(struct lttng_event *event, +int apply_field_reloc(const struct lttng_event_desc *event_desc, struct bytecode_runtime *runtime, uint32_t runtime_len, uint32_t reloc_offset, const char *field_name, enum filter_op filter_op) { - const struct lttng_event_desc *desc; const struct lttng_event_field *fields, *field = NULL; unsigned int nr_fields, i; struct load_op *op; @@ -203,13 +203,12 @@ int apply_field_reloc(struct lttng_event *event, dbg_printf("Apply field reloc: %u %s\n", reloc_offset, field_name); /* Lookup event by name */ - desc = event->desc; - if (!desc) + if (!event_desc) return -EINVAL; - fields = desc->fields; + fields = event_desc->fields; if (!fields) return -EINVAL; - nr_fields = desc->nr_fields; + nr_fields = event_desc->nr_fields; for (i = 0; i < nr_fields; i++) { if (!strcmp(fields[i].name, field_name)) { field = &fields[i]; @@ -281,8 +280,7 @@ int apply_field_reloc(struct lttng_event *event, } static -int apply_context_reloc(struct lttng_event *event, - struct bytecode_runtime *runtime, +int apply_context_reloc(struct bytecode_runtime *runtime, uint32_t runtime_len, uint32_t reloc_offset, const char *context_name, @@ -291,22 +289,21 @@ int apply_context_reloc(struct lttng_event *event, struct load_op *op; struct lttng_ctx_field *ctx_field; int idx; - struct lttng_session *session = runtime->p.session; + struct lttng_ctx *ctx = *runtime->p.ctx; dbg_printf("Apply context reloc: %u %s\n", reloc_offset, context_name); /* Get context index */ - idx = lttng_get_context_index(session->ctx, context_name); + idx = lttng_get_context_index(ctx, context_name); if (idx < 0) { if (lttng_context_is_app(context_name)) { int ret; ret = lttng_ust_add_app_context_to_ctx_rcu(context_name, - &session->ctx); + &ctx); if (ret) return ret; - idx = lttng_get_context_index(session->ctx, - context_name); + idx = lttng_get_context_index(ctx, context_name); if (idx < 0) return -ENOENT; } else { @@ -318,7 +315,7 @@ int apply_context_reloc(struct lttng_event *event, return -EINVAL; /* Get context return type */ - ctx_field = &session->ctx->fields[idx]; + ctx_field = &ctx->fields[idx]; op = (struct load_op *) &runtime->code[reloc_offset]; switch (filter_op) { @@ -358,7 +355,7 @@ int apply_context_reloc(struct lttng_event *event, } static -int apply_reloc(struct lttng_event *event, +int apply_reloc(const struct lttng_event_desc *event_desc, struct bytecode_runtime *runtime, uint32_t runtime_len, uint32_t reloc_offset, @@ -375,10 +372,10 @@ int apply_reloc(struct lttng_event *event, op = (struct load_op *) &runtime->code[reloc_offset]; switch (op->op) { case FILTER_OP_LOAD_FIELD_REF: - return apply_field_reloc(event, runtime, runtime_len, + return apply_field_reloc(event_desc, runtime, runtime_len, reloc_offset, name, op->op); case FILTER_OP_GET_CONTEXT_REF: - return apply_context_reloc(event, runtime, runtime_len, + return apply_context_reloc(runtime, runtime_len, reloc_offset, name, op->op); case FILTER_OP_GET_SYMBOL: case FILTER_OP_GET_SYMBOL_FIELD: @@ -396,12 +393,11 @@ int apply_reloc(struct lttng_event *event, static int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode, - struct lttng_event *event) + struct cds_list_head *bytecode_runtime_head) { struct lttng_bytecode_runtime *bc_runtime; - cds_list_for_each_entry(bc_runtime, - &event->bytecode_runtime_head, node) { + cds_list_for_each_entry(bc_runtime, bytecode_runtime_head, node) { if (bc_runtime->bc == filter_bytecode) return 1; } @@ -413,7 +409,8 @@ int bytecode_is_linked(struct lttng_ust_filter_bytecode_node *filter_bytecode, * bytecode runtime. */ static -int _lttng_filter_event_link_bytecode(struct lttng_event *event, +int _lttng_filter_link_bytecode(const struct lttng_event_desc *event_desc, + struct lttng_ctx **ctx, struct lttng_ust_filter_bytecode_node *filter_bytecode, struct cds_list_head *insert_loc) { @@ -424,7 +421,7 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event, if (!filter_bytecode) return 0; /* Bytecode already linked */ - if (bytecode_is_linked(filter_bytecode, event)) + if (bytecode_is_linked(filter_bytecode, insert_loc)) return 0; dbg_printf("Linking...\n"); @@ -437,7 +434,7 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event, goto alloc_error; } runtime->p.bc = filter_bytecode; - runtime->p.session = event->chan->session; + runtime->p.ctx = ctx; runtime->len = filter_bytecode->bc.reloc_offset; /* copy original bytecode */ memcpy(runtime->code, filter_bytecode->bc.data, runtime->len); @@ -453,7 +450,7 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event, const char *name = (const char *) &filter_bytecode->bc.data[offset + sizeof(uint16_t)]; - ret = apply_reloc(event, runtime, runtime->len, reloc_offset, name); + ret = apply_reloc(event_desc, runtime, runtime->len, reloc_offset, name); if (ret) { goto link_error; } @@ -465,7 +462,7 @@ int _lttng_filter_event_link_bytecode(struct lttng_event *event, goto link_error; } /* Specialize bytecode */ - ret = lttng_filter_specialize_bytecode(event, runtime); + ret = lttng_filter_specialize_bytecode(event_desc, runtime); if (ret) { goto link_error; } @@ -497,14 +494,15 @@ void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime) /* * Link bytecode for all enablers referenced by an event. */ -void lttng_enabler_event_link_bytecode(struct lttng_event *event, +void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc, + struct lttng_ctx **ctx, + struct cds_list_head *bytecode_runtime_head, struct lttng_enabler *enabler) { struct lttng_ust_filter_bytecode_node *bc; struct lttng_bytecode_runtime *runtime; - /* Can only be called for events with desc attached */ - assert(event->desc); + assert(event_desc); /* Link each bytecode. */ cds_list_for_each_entry(bc, &enabler->filter_bytecode_head, node) { @@ -512,7 +510,7 @@ void lttng_enabler_event_link_bytecode(struct lttng_event *event, struct cds_list_head *insert_loc; cds_list_for_each_entry(runtime, - &event->bytecode_runtime_head, node) { + bytecode_runtime_head, node) { if (runtime->bc == bc) { found = 1; break; @@ -527,19 +525,20 @@ void lttng_enabler_event_link_bytecode(struct lttng_event *event, * order. */ cds_list_for_each_entry_reverse(runtime, - &event->bytecode_runtime_head, node) { + bytecode_runtime_head, node) { if (runtime->bc->bc.seqnum < bc->bc.seqnum) { /* insert here */ insert_loc = &runtime->node; goto add_within; } } + /* Add to head to list */ - insert_loc = &event->bytecode_runtime_head; + insert_loc = bytecode_runtime_head; add_within: dbg_printf("linking bytecode\n"); - ret = _lttng_filter_event_link_bytecode(event, bc, - insert_loc); + ret = _lttng_filter_link_bytecode(event_desc, ctx, bc, + insert_loc); if (ret) { dbg_printf("[lttng filter] warning: cannot link event bytecode\n"); } @@ -556,13 +555,24 @@ int lttng_filter_enabler_attach_bytecode(struct lttng_enabler *enabler, return 0; } -void lttng_free_event_filter_runtime(struct lttng_event *event) +static +void free_filter_runtime(struct cds_list_head *bytecode_runtime_head) { struct bytecode_runtime *runtime, *tmp; - cds_list_for_each_entry_safe(runtime, tmp, - &event->bytecode_runtime_head, p.node) { + cds_list_for_each_entry_safe(runtime, tmp, bytecode_runtime_head, + p.node) { free(runtime->data); free(runtime); } } + +void lttng_free_event_filter_runtime(struct lttng_event *event) +{ + free_filter_runtime(&event->bytecode_runtime_head); +} + +void lttng_free_trigger_filter_runtime(struct lttng_trigger *trigger) +{ + free_filter_runtime(&trigger->bytecode_runtime_head); +} diff --git a/liblttng-ust/lttng-filter.h b/liblttng-ust/lttng-filter.h index cc15c154..f8e11293 100644 --- a/liblttng-ust/lttng-filter.h +++ b/liblttng-ust/lttng-filter.h @@ -291,7 +291,7 @@ struct estack { const char *print_op(enum filter_op op); int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode); -int lttng_filter_specialize_bytecode(struct lttng_event *event, +int lttng_filter_specialize_bytecode(const struct lttng_event_desc *event_desc, struct bytecode_runtime *bytecode); uint64_t lttng_filter_false(void *filter_data, diff --git a/liblttng-ust/lttng-probes.c b/liblttng-ust/lttng-probes.c index 862b19e7..522b80a1 100644 --- a/liblttng-ust/lttng-probes.c +++ b/liblttng-ust/lttng-probes.c @@ -35,6 +35,7 @@ #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(). @@ -204,6 +205,8 @@ int lttng_probe_register(struct lttng_probe_desc *desc) if (lttng_session_active()) fixup_lazy_probes(); + lttng_fix_pending_triggers(); + ust_unlock(); return ret; } diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index c060e2d9..9a607cf2 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -38,6 +38,7 @@ */ #define _LGPL_SOURCE +#include #include #include @@ -57,6 +58,7 @@ #include "../libringbuffer/shm.h" #include "lttng-tracer.h" #include "string-utils.h" +#include "ust-events-internal.h" #define OBJ_NAME_LEN 16 @@ -279,9 +281,11 @@ void lttng_ust_objd_table_owner_cleanup(void *owner) */ static const struct lttng_ust_objd_ops lttng_ops; +static const struct lttng_ust_objd_ops lttng_trigger_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_enabler_ops; +static const struct lttng_ust_objd_ops lttng_event_enabler_ops; +static const struct lttng_ust_objd_ops lttng_trigger_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; @@ -339,6 +343,53 @@ long lttng_abi_tracer_version(int objd, return 0; } +static +int lttng_abi_trigger_send_fd(void *owner, int trigger_notif_fd) +{ + struct lttng_trigger_group *trigger_group; + int trigger_group_objd, ret, fd_flag, close_ret; + + trigger_group = lttng_trigger_group_create(); + if (!trigger_group) + return -ENOMEM; + + /* + * Set this file descriptor as NON-BLOCKING. + */ + fd_flag = fcntl(trigger_notif_fd, F_GETFL); + + fd_flag |= O_NONBLOCK; + + ret = fcntl(trigger_notif_fd, F_SETFL, fd_flag); + if (ret) { + ret = -errno; + goto fd_error; + } + + trigger_group_objd = objd_alloc(trigger_group, + <tng_trigger_group_ops, owner, "trigger_group"); + if (trigger_group_objd < 0) { + ret = trigger_group_objd; + goto objd_error; + } + + trigger_group->objd = trigger_group_objd; + trigger_group->owner = owner; + trigger_group->notification_fd = trigger_notif_fd; + + return trigger_group_objd; + +objd_error: + lttng_trigger_group_destroy(trigger_group); +fd_error: + close_ret = close(trigger_notif_fd); + if (close_ret) { + PERROR("close"); + } + + return ret; +} + static long lttng_abi_add_context(int objd, struct lttng_ust_context *context_param, @@ -388,6 +439,9 @@ long lttng_cmd(int objd, unsigned int cmd, unsigned long arg, case LTTNG_UST_WAIT_QUIESCENT: synchronize_trace(); return 0; + case LTTNG_UST_TRIGGER_GROUP_CREATE: + return lttng_abi_trigger_send_fd(owner, + uargs->trigger_handle.trigger_notif_fd); default: return -EINVAL; } @@ -614,6 +668,127 @@ static const struct lttng_ust_objd_ops lttng_session_ops = { .cmd = lttng_session_cmd, }; +static int lttng_ust_trigger_enabler_create(int trigger_group_obj, void *owner, + struct lttng_ust_trigger *trigger_param, + enum lttng_enabler_format_type type) +{ + struct lttng_trigger_group *trigger_group = + objd_private(trigger_group_obj); + struct lttng_trigger_enabler *trigger_enabler; + int trigger_objd, ret; + + trigger_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + trigger_objd = objd_alloc(NULL, <tng_trigger_enabler_ops, owner, + "trigger enabler"); + if (trigger_objd < 0) { + ret = trigger_objd; + goto objd_error; + } + + trigger_enabler = lttng_trigger_enabler_create(trigger_group, type, + trigger_param); + if (!trigger_enabler) { + ret = -ENOMEM; + goto trigger_error; + } + + objd_set_private(trigger_objd, trigger_enabler); + /* The trigger holds a reference on the trigger group. */ + objd_ref(trigger_enabler->group->objd); + + return trigger_objd; + +trigger_error: + { + int err; + + err = lttng_ust_objd_unref(trigger_objd, 1); + assert(!err); + } +objd_error: + return ret; +} + +static +long lttng_trigger_enabler_cmd(int objd, unsigned int cmd, unsigned long arg, + union ust_args *uargs, void *owner) +{ + struct lttng_trigger_enabler *trigger_enabler = objd_private(objd); + switch (cmd) { + case LTTNG_UST_FILTER: + return lttng_trigger_enabler_attach_bytecode(trigger_enabler, + (struct lttng_ust_filter_bytecode_node *) arg); + case LTTNG_UST_EXCLUSION: + return lttng_trigger_enabler_attach_exclusion(trigger_enabler, + (struct lttng_ust_excluder_node *) arg); + case LTTNG_UST_ENABLE: + return lttng_trigger_enabler_enable(trigger_enabler); + case LTTNG_UST_DISABLE: + return lttng_trigger_enabler_disable(trigger_enabler); + default: + return -EINVAL; + } +} + +static +long lttng_trigger_group_cmd(int objd, unsigned int cmd, unsigned long arg, + union ust_args *uargs, void *owner) +{ + switch (cmd) { + case LTTNG_UST_TRIGGER_CREATE: + { + struct lttng_ust_trigger *trigger_param = + (struct lttng_ust_trigger *) arg; + if (strutils_is_star_glob_pattern(trigger_param->name)) { + /* + * If the event name is a star globbing pattern, + * we create the special star globbing enabler. + */ + return lttng_ust_trigger_enabler_create(objd, owner, + trigger_param, LTTNG_ENABLER_FORMAT_STAR_GLOB); + } else { + return lttng_ust_trigger_enabler_create(objd, owner, + trigger_param, LTTNG_ENABLER_FORMAT_EVENT); + } + } + default: + return -EINVAL; + } +} + +static +int lttng_trigger_enabler_release(int objd) +{ + struct lttng_trigger_enabler *trigger_enabler = objd_private(objd); + + if (trigger_enabler) + return lttng_ust_objd_unref(trigger_enabler->group->objd, 0); + return 0; +} + +static const struct lttng_ust_objd_ops lttng_trigger_enabler_ops = { + .release = lttng_trigger_enabler_release, + .cmd = lttng_trigger_enabler_cmd, +}; + +static +int lttng_release_trigger_group(int objd) +{ + struct lttng_trigger_group *trigger_group = objd_private(objd); + + if (trigger_group) { + lttng_trigger_group_destroy(trigger_group); + return 0; + } else { + return -EINVAL; + } +} + +static const struct lttng_ust_objd_ops lttng_trigger_group_ops = { + .release = lttng_release_trigger_group, + .cmd = lttng_trigger_group_cmd, +}; + static long lttng_tracepoint_list_cmd(int objd, unsigned int cmd, unsigned long arg, union ust_args *uargs, void *owner) @@ -794,17 +969,18 @@ error_add_stream: } static -int lttng_abi_create_enabler(int channel_objd, +int lttng_abi_create_event_enabler(int channel_objd, struct lttng_ust_event *event_param, void *owner, - enum lttng_enabler_type type) + enum lttng_enabler_format_type format_type) { struct lttng_channel *channel = objd_private(channel_objd); - struct lttng_enabler *enabler; + struct lttng_event_enabler *enabler; int event_objd, ret; event_param->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; - event_objd = objd_alloc(NULL, <tng_enabler_ops, owner, "enabler"); + event_objd = objd_alloc(NULL, <tng_event_enabler_ops, owner, + "event enabler"); if (event_objd < 0) { ret = event_objd; goto objd_error; @@ -813,7 +989,7 @@ int lttng_abi_create_enabler(int channel_objd, * We tolerate no failure path after event creation. It will stay * invariant for the rest of the session. */ - enabler = lttng_enabler_create(type, event_param, channel); + enabler = lttng_event_enabler_create(format_type, event_param, channel); if (!enabler) { ret = -ENOMEM; goto event_error; @@ -891,11 +1067,11 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, * If the event name is a star globbing pattern, * we create the special star globbing enabler. */ - return lttng_abi_create_enabler(objd, event_param, - owner, LTTNG_ENABLER_STAR_GLOB); + return lttng_abi_create_event_enabler(objd, event_param, + owner, LTTNG_ENABLER_FORMAT_STAR_GLOB); } else { - return lttng_abi_create_enabler(objd, event_param, - owner, LTTNG_ENABLER_EVENT); + return lttng_abi_create_event_enabler(objd, event_param, + owner, LTTNG_ENABLER_FORMAT_EVENT); } } case LTTNG_UST_CONTEXT: @@ -951,24 +1127,24 @@ static const struct lttng_ust_objd_ops lttng_channel_ops = { * Attach exclusions to an enabler. */ static -long lttng_enabler_cmd(int objd, unsigned int cmd, unsigned long arg, +long lttng_event_enabler_cmd(int objd, unsigned int cmd, unsigned long arg, union ust_args *uargs, void *owner) { - struct lttng_enabler *enabler = objd_private(objd); + struct lttng_event_enabler *enabler = objd_private(objd); switch (cmd) { case LTTNG_UST_CONTEXT: - return lttng_enabler_attach_context(enabler, + return lttng_event_enabler_attach_context(enabler, (struct lttng_ust_context *) arg); case LTTNG_UST_ENABLE: - return lttng_enabler_enable(enabler); + return lttng_event_enabler_enable(enabler); case LTTNG_UST_DISABLE: - return lttng_enabler_disable(enabler); + return lttng_event_enabler_disable(enabler); case LTTNG_UST_FILTER: { int ret; - ret = lttng_enabler_attach_bytecode(enabler, + ret = lttng_event_enabler_attach_bytecode(enabler, (struct lttng_ust_filter_bytecode_node *) arg); if (ret) return ret; @@ -976,7 +1152,7 @@ long lttng_enabler_cmd(int objd, unsigned int cmd, unsigned long arg, } case LTTNG_UST_EXCLUSION: { - return lttng_enabler_attach_exclusion(enabler, + return lttng_event_enabler_attach_exclusion(enabler, (struct lttng_ust_excluder_node *) arg); } default: @@ -985,18 +1161,19 @@ long lttng_enabler_cmd(int objd, unsigned int cmd, unsigned long arg, } static -int lttng_enabler_release(int objd) +int lttng_event_enabler_release(int objd) { - struct lttng_enabler *enabler = objd_private(objd); + struct lttng_event_enabler *event_enabler = objd_private(objd); + + if (event_enabler) + return lttng_ust_objd_unref(event_enabler->chan->objd, 0); - if (enabler) - return lttng_ust_objd_unref(enabler->chan->objd, 0); return 0; } -static const struct lttng_ust_objd_ops lttng_enabler_ops = { - .release = lttng_enabler_release, - .cmd = lttng_enabler_cmd, +static const struct lttng_ust_objd_ops lttng_event_enabler_ops = { + .release = lttng_event_enabler_release, + .cmd = lttng_event_enabler_cmd, }; void lttng_ust_abi_exit(void) diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index 900a0e84..d125dd59 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -320,6 +320,9 @@ static const char *cmd_name_mapping[] = { [ LTTNG_UST_REGISTER_DONE ] = "Registration Done", [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List", + [ LTTNG_UST_TRIGGER_GROUP_CREATE ] = "Create trigger group", + [ LTTNG_UST_TRIGGER_CREATE ] = "Create trigger", + /* Session FD commands */ [ LTTNG_UST_CHANNEL ] = "Create Channel", [ LTTNG_UST_SESSION_START ] = "Start Session", @@ -906,6 +909,43 @@ int handle_message(struct sock_info *sock_info, } break; } + case LTTNG_UST_TRIGGER_GROUP_CREATE: + { + int trigger_notif_fd; + + len = ustcomm_recv_trigger_notif_fd_from_sessiond(sock, + &trigger_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 trigger fd message size: %zd", len); + ret = -EINVAL; + goto error; + } + } + args.trigger_handle.trigger_notif_fd = trigger_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; diff --git a/liblttng-ust/ust-events-internal.h b/liblttng-ust/ust-events-internal.h new file mode 100644 index 00000000..0a580bad --- /dev/null +++ b/liblttng-ust/ust-events-internal.h @@ -0,0 +1,157 @@ +#ifndef _LTTNG_UST_EVENTS_INTERNAL_H +#define _LTTNG_UST_EVENTS_INTERNAL_H + +/* + * ust-events-internal.h + * + * Copyright 2019 (c) - Francis Deslauriers + * + * 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 + +#include +#include + +#include +#include + +struct lttng_event_enabler { + struct lttng_enabler base; + struct cds_list_head node; /* per-session list of enablers */ + struct lttng_channel *chan; + /* + * Unused, but kept around to make it explicit that the tracer can do + * it. + */ + struct lttng_ctx *ctx; +}; + +struct lttng_trigger_enabler { + struct lttng_enabler base; + uint64_t id; + struct cds_list_head node; /* per-app list of trigger enablers */ + struct lttng_trigger_group *group; /* weak ref */ +}; + +static inline +struct lttng_enabler *lttng_event_enabler_as_enabler( + struct lttng_event_enabler *event_enabler) +{ + return &event_enabler->base; +} + +static inline +struct lttng_enabler *lttng_trigger_enabler_as_enabler( + struct lttng_trigger_enabler *trigger_enabler) +{ + return &trigger_enabler->base; +} + +/* TODO doc */ +LTTNG_HIDDEN +struct lttng_event_enabler *lttng_event_enabler_create( + enum lttng_enabler_format_type format_type, + struct lttng_ust_event *event_param, + struct lttng_channel *chan); + +/* TODO doc */ +LTTNG_HIDDEN +void lttng_event_enabler_destroy(struct lttng_event_enabler *enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_event_enabler_enable(struct lttng_event_enabler *enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_event_enabler_disable(struct lttng_event_enabler *enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_event_enabler_attach_bytecode(struct lttng_event_enabler *enabler, + struct lttng_ust_filter_bytecode_node *bytecode); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_event_enabler_attach_context(struct lttng_event_enabler *enabler, + struct lttng_ust_context *ctx); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_event_enabler_attach_exclusion(struct lttng_event_enabler *enabler, + struct lttng_ust_excluder_node *excluder); + +/* TODO doc */ +LTTNG_HIDDEN +void lttng_enabler_link_bytecode(const struct lttng_event_desc *event_desc, + struct lttng_ctx **ctx, + struct cds_list_head *bytecode_runtime_head, + struct lttng_enabler *enabler); + +/* TODO doc */ +LTTNG_HIDDEN +struct lttng_trigger_group *lttng_trigger_group_create(void); + +/* TODO doc */ +LTTNG_HIDDEN +void lttng_trigger_group_destroy( + struct lttng_trigger_group *trigger_group); + +/* TODO doc */ +LTTNG_HIDDEN +struct lttng_trigger_enabler *lttng_trigger_enabler_create( + struct lttng_trigger_group *trigger_group, + enum lttng_enabler_format_type format_type, + struct lttng_ust_trigger *trigger_param); + +/* TODO doc */ +LTTNG_HIDDEN +void lttng_trigger_enabler_destroy(struct lttng_trigger_enabler *trigger_enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_trigger_enabler_enable(struct lttng_trigger_enabler *trigger_enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_trigger_enabler_disable(struct lttng_trigger_enabler *trigger_enabler); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_trigger_enabler_attach_bytecode( + struct lttng_trigger_enabler *trigger_enabler, + struct lttng_ust_filter_bytecode_node *bytecode); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_trigger_enabler_attach_exclusion( + struct lttng_trigger_enabler *trigger_enabler, + struct lttng_ust_excluder_node *excluder); + +/* TODO doc */ +LTTNG_HIDDEN +void lttng_free_trigger_filter_runtime(struct lttng_trigger *trigger); + +/* TODO doc */ +LTTNG_HIDDEN +int lttng_fix_pending_triggers(void); + +#endif /* _LTTNG_UST_EVENTS_INTERNAL_H */