X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=ltt-events.c;h=40e8e459183efacae2744fcc6a6071bd9625e5b1;hb=24cedcfefbfe781af5430e07a327030cc7caddfc;hp=29d0ed749b78db62258e22506231452c0397bf19;hpb=f17701fb89c69c3950c22a0c20d0233092e7d6ed;p=lttng-modules.git diff --git a/ltt-events.c b/ltt-events.c index 29d0ed74..40e8e459 100644 --- a/ltt-events.c +++ b/ltt-events.c @@ -4,6 +4,8 @@ * Copyright 2010 (c) - Mathieu Desnoyers * * Holds LTTng per-session event registry. + * + * Dual LGPL v2.1/GPL v2 license. */ #include @@ -23,6 +25,7 @@ static DEFINE_MUTEX(sessions_mutex); static struct kmem_cache *event_cache; static void _ltt_event_destroy(struct ltt_event *event); +static void _ltt_channel_destroy(struct ltt_channel *chan); static int _ltt_event_unregister(struct ltt_event *event); static int _ltt_event_metadata_statedump(struct ltt_session *session, @@ -104,6 +107,7 @@ int ltt_session_start(struct ltt_session *session) } ACCESS_ONCE(session->active) = 1; + ACCESS_ONCE(session->been_active) = 1; synchronize_trace(); /* Wait for in-flight events to complete */ ret = _ltt_session_metadata_statedump(session); if (ret) { @@ -153,10 +157,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, struct ltt_transport *transport; mutex_lock(&sessions_mutex); - if (session->active) { - printk(KERN_WARNING "LTTng refusing to add channel to active session\n"); + if (session->been_active) goto active; /* Refuse to add channel to active session */ - } transport = ltt_transport_find(transport_name); if (!transport) { printk(KERN_WARNING "LTTng transport %s not found\n", @@ -167,13 +169,17 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, if (!chan) goto nomem; chan->session = session; - init_waitqueue_head(&chan->notify_wait); + chan->id = session->free_chan_id++; + /* + * Note: the channel creation op already writes into the packet + * headers. Therefore the "chan" information used as input + * should be already accessible. + */ chan->chan = transport->ops.channel_create("[lttng]", chan, buf_addr, subbuf_size, num_subbuf, switch_timer_interval, read_timer_interval); if (!chan->chan) goto create_error; - chan->id = session->free_chan_id++; chan->ops = &transport->ops; list_add(&chan->list, &session->chan); mutex_unlock(&sessions_mutex); @@ -191,19 +197,20 @@ active: /* * Only used internally at session destruction. */ +static void _ltt_channel_destroy(struct ltt_channel *chan) { chan->ops->channel_destroy(chan->chan); list_del(&chan->list); + lttng_destroy_context(chan->ctx); kfree(chan); } /* * Supports event creation while tracing session is active. */ -struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, +struct ltt_event *ltt_event_create(struct ltt_channel *chan, struct lttng_kernel_event *event_param, - const struct lttng_event_desc *event_desc, void *filter) { struct ltt_event *event; @@ -217,33 +224,47 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, * creation). Might require a hash if we have lots of events. */ list_for_each_entry(event, &chan->session->events, list) - if (!strcmp(event->desc->name, name)) + if (!strcmp(event->desc->name, event_param->name)) goto exist; event = kmem_cache_zalloc(event_cache, GFP_KERNEL); if (!event) goto cache_error; event->chan = chan; - event->desc = event_desc; event->filter = filter; event->id = chan->free_event_id++; event->instrumentation = event_param->instrumentation; /* Populate ltt_event structure before tracepoint registration. */ smp_wmb(); switch (event_param->instrumentation) { - case LTTNG_KERNEL_TRACEPOINTS: - ret = tracepoint_probe_register(name, event_desc->probe_callback, - event); + case LTTNG_KERNEL_TRACEPOINT: + event->desc = ltt_event_get(event_param->name); + if (!event->desc) + goto register_error; + ret = tracepoint_probe_register(event_param->name, + event->desc->probe_callback, + event); if (ret) goto register_error; break; - case LTTNG_KERNEL_KPROBES: - ret = lttng_kprobes_register(name, + case LTTNG_KERNEL_KPROBE: + ret = lttng_kprobes_register(event_param->name, event_param->u.kprobe.symbol_name, event_param->u.kprobe.offset, event_param->u.kprobe.addr, event); if (ret) goto register_error; + ret = try_module_get(event->desc->owner); + WARN_ON_ONCE(!ret); + break; + case LTTNG_KERNEL_FUNCTION: + ret = lttng_ftrace_register(event_param->name, + event_param->u.ftrace.symbol_name, + event); + if (ret) + goto register_error; + ret = try_module_get(event->desc->owner); + WARN_ON_ONCE(!ret); break; default: WARN_ON_ONCE(1); @@ -256,8 +277,10 @@ struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, return event; statedump_error: - WARN_ON_ONCE(tracepoint_probe_unregister(name, event_desc->probe_callback, - event)); + WARN_ON_ONCE(tracepoint_probe_unregister(event_param->name, + event->desc->probe_callback, + event)); + ltt_event_put(event->desc); register_error: kmem_cache_free(event_cache, event); cache_error: @@ -275,44 +298,50 @@ int _ltt_event_unregister(struct ltt_event *event) int ret = -EINVAL; switch (event->instrumentation) { - case LTTNG_KERNEL_TRACEPOINTS: + case LTTNG_KERNEL_TRACEPOINT: ret = tracepoint_probe_unregister(event->desc->name, event->desc->probe_callback, event); if (ret) return ret; break; - case LTTNG_KERNEL_KPROBES: + case LTTNG_KERNEL_KPROBE: lttng_kprobes_unregister(event); ret = 0; break; + case LTTNG_KERNEL_FUNCTION: + lttng_ftrace_unregister(event); + ret = 0; + break; default: WARN_ON_ONCE(1); } return ret; } -/* - * Used when an event FD is released. - */ -int ltt_event_unregister(struct ltt_event *event) -{ - int ret; - - mutex_lock(&sessions_mutex); - ret = ltt_event_unregister(event); - mutex_unlock(&sessions_mutex); - return ret; -} - /* * Only used internally at session destruction. */ static void _ltt_event_destroy(struct ltt_event *event) { - ltt_event_put(event->desc); + switch (event->instrumentation) { + case LTTNG_KERNEL_TRACEPOINT: + ltt_event_put(event->desc); + break; + case LTTNG_KERNEL_KPROBE: + module_put(event->desc->owner); + lttng_kprobes_destroy_private(event); + break; + case LTTNG_KERNEL_FUNCTION: + module_put(event->desc->owner); + lttng_ftrace_destroy_private(event); + break; + default: + WARN_ON_ONCE(1); + } list_del(&event->list); + lttng_destroy_context(event->ctx); kmem_cache_free(event_cache, event); } @@ -355,9 +384,9 @@ int lttng_metadata_printf(struct ltt_session *session, * we need to bail out after timeout or being * interrupted. */ - waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan), + waitret = wait_event_interruptible_timeout(*chan->ops->get_reader_wait_queue(chan->chan), ({ - ret = chan->ops->event_reserve(&ctx); + ret = chan->ops->event_reserve(&ctx, 0); ret != -ENOBUFS || !ret; }), msecs_to_jiffies(LTTNG_METADATA_TIMEOUT_MSEC)); @@ -369,7 +398,7 @@ int lttng_metadata_printf(struct ltt_session *session, ret = waitret; goto end; } - chan->ops->event_write(&ctx, &str[pos], len); + chan->ops->event_write(&ctx, &str[pos], reserve_len); chan->ops->event_commit(&ctx); } end: @@ -378,95 +407,157 @@ end: } static -int _ltt_fields_metadata_statedump(struct ltt_session *session, - struct ltt_event *event) +int _ltt_field_statedump(struct ltt_session *session, + const struct lttng_event_field *field) { - const struct lttng_event_desc *desc = event->desc; int ret = 0; - int i; - - for (i = 0; i < desc->nr_fields; i++) { - const struct lttng_event_field *field = &desc->fields[i]; - switch (field->type.atype) { - case atype_integer: - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u;%s } %s;\n", - field->type.u.basic.integer.size, - field->type.u.basic.integer.alignment, - field->type.u.basic.integer.signedness, + switch (field->type.atype) { + case atype_integer: + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s;\n", + field->type.u.basic.integer.size, + field->type.u.basic.integer.alignment, + field->type.u.basic.integer.signedness, + (field->type.u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (field->type.u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + field->type.u.basic.integer.base, #ifdef __BIG_ENDIAN - field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + field->type.u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + field->type.u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name); - break; - case atype_enum: - ret = lttng_metadata_printf(session, - " %s %s;\n", - field->type.u.basic.enumeration.name, - field->name); - break; - case atype_array: - { - const struct lttng_basic_type *elem_type; - - elem_type = &field->type.u.array.elem_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u;%s } %s[%u];\n", - elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, + field->name); + break; + case atype_enum: + ret = lttng_metadata_printf(session, + " %s %s;\n", + field->type.u.basic.enumeration.name, + field->name); + break; + case atype_array: + { + const struct lttng_basic_type *elem_type; + + elem_type = &field->type.u.array.elem_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[%u];\n", + elem_type->u.basic.integer.size, + elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : (elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + elem_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, field->type.u.array.length); - break; - } - case atype_sequence: - { - const struct lttng_basic_type *elem_type; - const struct lttng_basic_type *length_type; - - elem_type = &field->type.u.sequence.elem_type; - length_type = &field->type.u.sequence.length_type; - ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u;%s } %s[ integer { size = %u; align = %u; signed = %u;%s } ];\n", - elem_type->u.basic.integer.size, - elem_type->u.basic.integer.alignment, - elem_type->u.basic.integer.signedness, + field->name, field->type.u.array.length); + break; + } + case atype_sequence: + { + const struct lttng_basic_type *elem_type; + const struct lttng_basic_type *length_type; + + elem_type = &field->type.u.sequence.elem_type; + length_type = &field->type.u.sequence.length_type; + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", + length_type->u.basic.integer.size, + (unsigned int) length_type->u.basic.integer.alignment, + length_type->u.basic.integer.signedness, + (length_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : ((length_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII"), + length_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", + length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - field->name, - length_type->u.basic.integer.size, - length_type->u.basic.integer.alignment, - length_type->u.basic.integer.signedness, + field->name); + if (ret) + return ret; + + ret = lttng_metadata_printf(session, + " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } %s[ __%s_length ];\n", + elem_type->u.basic.integer.size, + (unsigned int) elem_type->u.basic.integer.alignment, + elem_type->u.basic.integer.signedness, + (elem_type->u.basic.integer.encoding == lttng_encode_none) + ? "none" + : ((elem_type->u.basic.integer.encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII"), + elem_type->u.basic.integer.base, #ifdef __BIG_ENDIAN - length_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = le;" : "", #else - length_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "" + elem_type->u.basic.integer.reverse_byte_order ? " byte_order = be;" : "", #endif - ); - break; - } + field->name, + field->name); + break; + } - case atype_string: - ret = lttng_metadata_printf(session, - " string%s %s;\n", - field->type.u.basic.string.encoding == lttng_encode_ASCII ? - " { encoding = ASCII; }" : "", - field->name); - break; - default: - WARN_ON_ONCE(1); - return -EINVAL; - } + case atype_string: + /* Default encoding is UTF8 */ + ret = lttng_metadata_printf(session, + " string%s %s;\n", + field->type.u.basic.string.encoding == lttng_encode_ASCII ? + " { encoding = ASCII; }" : "", + field->name); + break; + default: + WARN_ON_ONCE(1); + return -EINVAL; + } + return ret; +} + +static +int _ltt_context_metadata_statedump(struct ltt_session *session, + struct lttng_ctx *ctx) +{ + int ret = 0; + int i; + + if (!ctx) + return 0; + for (i = 0; i < ctx->nr_fields; i++) { + const struct lttng_ctx_field *field = &ctx->fields[i]; + + ret = _ltt_field_statedump(session, &field->event_field); + if (ret) + return ret; + } + return ret; +} + +static +int _ltt_fields_metadata_statedump(struct ltt_session *session, + struct ltt_event *event) +{ + const struct lttng_event_desc *desc = event->desc; + int ret = 0; + int i; + + for (i = 0; i < desc->nr_fields; i++) { + const struct lttng_event_field *field = &desc->fields[i]; + + ret = _ltt_field_statedump(session, field); + if (ret) + return ret; } return ret; } @@ -487,14 +578,35 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, "event {\n" " name = %s;\n" " id = %u;\n" - " stream_id = %u;\n" - " event.fields := struct {\n", + " stream_id = %u;\n", event->desc->name, event->id, event->chan->id); if (ret) goto end; + if (event->ctx) { + ret = lttng_metadata_printf(session, + " context := struct {\n"); + if (ret) + goto end; + } + ret = _ltt_context_metadata_statedump(session, event->ctx); + if (ret) + goto end; + if (event->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } + + ret = lttng_metadata_printf(session, + " fields := struct {\n" + ); + if (ret) + goto end; + ret = _ltt_fields_metadata_statedump(session, event); if (ret) goto end; @@ -509,9 +621,6 @@ int _ltt_event_metadata_statedump(struct ltt_session *session, if (ret) goto end; - - - event->metadata_dumped = 1; end: return ret; @@ -534,14 +643,32 @@ int _ltt_channel_metadata_statedump(struct ltt_session *session, "stream {\n" " id = %u;\n" " event.header := %s;\n" - " packet.context := struct packet_context;\n" - "};\n\n", + " packet.context := struct packet_context;\n", chan->id, chan->header_type == 1 ? "struct event_header_compact" : "struct event_header_large"); if (ret) goto end; + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " event.context := struct {\n"); + if (ret) + goto end; + } + ret = _ltt_context_metadata_statedump(session, chan->ctx); + if (ret) + goto end; + if (chan->ctx) { + ret = lttng_metadata_printf(session, + " };\n"); + if (ret) + goto end; + } + + ret = lttng_metadata_printf(session, + "};\n\n"); + chan->metadata_dumped = 1; end: return ret; @@ -558,7 +685,7 @@ int _ltt_stream_packet_context_declare(struct ltt_session *session) " uint32_t content_size;\n" " uint32_t packet_size;\n" " uint32_t cpu_id;\n" - "};\n" + "};\n\n" ); } @@ -611,7 +738,8 @@ int _ltt_event_header_declare(struct ltt_session *session) static int _ltt_session_metadata_statedump(struct ltt_session *session) { - char uuid_s[37]; + unsigned char *uuid_c = session->uuid.b; + unsigned char uuid_s[37]; struct ltt_channel *chan; struct ltt_event *event; int ret = 0; @@ -626,11 +754,11 @@ int _ltt_session_metadata_statedump(struct ltt_session *session) } snprintf(uuid_s, sizeof(uuid_s), - "%x%x%x%x-%x%x-%x%x-%x%x-%x%x%x%x%x%x", - uuid_s[0], uuid_s[1], uuid_s[2], uuid_s[3], - uuid_s[4], uuid_s[5], uuid_s[6], uuid_s[7], - uuid_s[8], uuid_s[9], uuid_s[10], uuid_s[11], - uuid_s[12], uuid_s[13], uuid_s[14], uuid_s[15]); + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid_c[0], uuid_c[1], uuid_c[2], uuid_c[3], + uuid_c[4], uuid_c[5], uuid_c[6], uuid_c[7], + uuid_c[8], uuid_c[9], uuid_c[10], uuid_c[11], + uuid_c[12], uuid_c[13], uuid_c[14], uuid_c[15]); ret = lttng_metadata_printf(session, "typealias integer { size = 8; align = %u; signed = false; } := uint8_t;\n" @@ -643,15 +771,16 @@ int _ltt_session_metadata_statedump(struct ltt_session *session) "trace {\n" " major = %u;\n" " minor = %u;\n" - " uuid = %s;\n" + " uuid = \"%s\";\n" " byte_order = %s;\n" " packet.header := struct {\n" " uint32_t magic;\n" " uint8_t uuid[16];\n" " uint32_t stream_id;\n" - " };\n", + " };\n" "};\n\n", ltt_alignof(uint8_t) * CHAR_BIT, + ltt_alignof(uint16_t) * CHAR_BIT, ltt_alignof(uint32_t) * CHAR_BIT, ltt_alignof(uint64_t) * CHAR_BIT, CTF_VERSION_MAJOR, @@ -682,7 +811,7 @@ skip_session: } list_for_each_entry(event, &session->events, list) { - ret = _ltt_event_metadata_statedump(session, chan, event); + ret = _ltt_event_metadata_statedump(session, event->chan, event); if (ret) goto end; }