X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=lttng-events.c;h=455b790f45fbe06dd37da01b7b79be7477f77df5;hb=7c559490ad4f9ab909493b17bb09a7495568fdcd;hp=9c8cde8f976adbf38fbccfb360675dc8a73bca59;hpb=5214fa509791fcb97f7c2713d7f3930c6c49d7de;p=lttng-modules.git diff --git a/lttng-events.c b/lttng-events.c index 9c8cde8f..455b790f 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include #define METADATA_CACHE_DEFAULT_SIZE 4096 @@ -78,6 +80,10 @@ static int _lttng_session_metadata_statedump(struct lttng_session *session); static void _lttng_metadata_channel_hangup(struct lttng_metadata_stream *stream); +static +int _lttng_field_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting); void synchronize_trace(void) { @@ -207,6 +213,16 @@ void lttng_session_destroy(struct lttng_session *session) kfree(session); } +int lttng_session_statedump(struct lttng_session *session) +{ + int ret; + + mutex_lock(&sessions_mutex); + ret = lttng_statedump_start(session); + mutex_unlock(&sessions_mutex); + return ret; +} + int lttng_session_enable(struct lttng_session *session) { int ret = 0; @@ -237,6 +253,12 @@ int lttng_session_enable(struct lttng_session *session) /* We need to sync enablers with session before activation. */ lttng_session_sync_enablers(session); + /* Clear each stream's quiescent state. */ + list_for_each_entry(chan, &session->chan, list) { + if (chan->channel_type != METADATA_CHANNEL) + lib_ring_buffer_clear_quiescent_channel(chan->chan); + } + ACCESS_ONCE(session->active) = 1; ACCESS_ONCE(session->been_active) = 1; ret = _lttng_session_metadata_statedump(session); @@ -255,6 +277,7 @@ end: int lttng_session_disable(struct lttng_session *session) { int ret = 0; + struct lttng_channel *chan; mutex_lock(&sessions_mutex); if (!session->active) { @@ -266,6 +289,12 @@ int lttng_session_disable(struct lttng_session *session) /* Set transient enabler state to "disabled" */ session->tstate = 0; lttng_session_sync_enablers(session); + + /* Set each stream's quiescent state. */ + list_for_each_entry(chan, &session->chan, list) { + if (chan->channel_type != METADATA_CHANNEL) + lib_ring_buffer_set_quiescent_channel(chan->chan); + } end: mutex_unlock(&sessions_mutex); return ret; @@ -1661,19 +1690,338 @@ err: return -ENOMEM; } +static +int print_tabs(struct lttng_session *session, size_t nesting) +{ + size_t i; + + for (i = 0; i < nesting; i++) { + int ret; + + ret = lttng_metadata_printf(session, " "); + if (ret) { + return ret; + } + } + return 0; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_struct_type_statedump(struct lttng_session *session, + const struct lttng_type *type, + size_t nesting) +{ + int ret; + uint32_t i, nr_fields; + + ret = print_tabs(session, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "struct {\n"); + if (ret) + return ret; + nr_fields = type->u._struct.nr_fields; + for (i = 0; i < nr_fields; i++) { + const struct lttng_event_field *iter_field; + + iter_field = &type->u._struct.fields[i]; + ret = _lttng_field_statedump(session, iter_field, nesting + 1); + if (ret) + return ret; + } + ret = print_tabs(session, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "}"); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_struct_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting) +{ + int ret; + + ret = _lttng_struct_type_statedump(session, + &field->type, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "_%s;\n", + field->name); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_variant_type_statedump(struct lttng_session *session, + const struct lttng_type *type, + size_t nesting) +{ + int ret; + uint32_t i, nr_choices; + + ret = print_tabs(session, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "variant <_%s> {\n", + type->u.variant.tag_name); + if (ret) + return ret; + nr_choices = type->u.variant.nr_choices; + for (i = 0; i < nr_choices; i++) { + const struct lttng_event_field *iter_field; + + iter_field = &type->u.variant.choices[i]; + ret = _lttng_field_statedump(session, iter_field, nesting + 1); + if (ret) + return ret; + } + ret = print_tabs(session, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "}"); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_variant_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting) +{ + int ret; + + ret = _lttng_variant_type_statedump(session, + &field->type, nesting); + if (ret) + return ret; + ret = lttng_metadata_printf(session, + "_%s;\n", + field->name); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_array_compound_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting) +{ + int ret; + const struct lttng_type *elem_type; + + /* Only array of structures and variants are currently supported. */ + elem_type = field->type.u.array_compound.elem_type; + switch (elem_type->atype) { + case atype_struct: + ret = _lttng_struct_type_statedump(session, elem_type, nesting); + if (ret) + return ret; + break; + case atype_variant: + ret = _lttng_variant_type_statedump(session, elem_type, nesting); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + ret = lttng_metadata_printf(session, + " _%s[%u];\n", + field->name, + field->type.u.array_compound.length); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_sequence_compound_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting) +{ + int ret; + const char *length_name; + const struct lttng_type *elem_type; + + length_name = field->type.u.sequence_compound.length_name; + + /* Only array of structures and variants are currently supported. */ + elem_type = field->type.u.sequence_compound.elem_type; + switch (elem_type->atype) { + case atype_struct: + ret = _lttng_struct_type_statedump(session, elem_type, nesting); + if (ret) + return ret; + break; + case atype_variant: + ret = _lttng_variant_type_statedump(session, elem_type, nesting); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + ret = lttng_metadata_printf(session, + " _%s[ _%s ];\n", + field->name, + length_name); + return ret; +} + +/* + * Must be called with sessions_mutex held. + */ +static +int _lttng_enum_statedump(struct lttng_session *session, + const struct lttng_event_field *field, + size_t nesting) +{ + const struct lttng_enum_desc *enum_desc; + const struct lttng_integer_type *container_type; + int ret; + unsigned int i, nr_entries; + + enum_desc = field->type.u.basic.enumeration.desc; + container_type = &field->type.u.basic.enumeration.container_type; + nr_entries = enum_desc->nr_entries; + + ret = print_tabs(session, nesting); + if (ret) + goto end; + ret = lttng_metadata_printf(session, + "enum : integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u; } {\n", + container_type->size, + container_type->alignment, + container_type->signedness, + (container_type->encoding == lttng_encode_none) + ? "none" + : (container_type->encoding == lttng_encode_UTF8) + ? "UTF8" + : "ASCII", + container_type->base); + if (ret) + goto end; + /* Dump all entries */ + for (i = 0; i < nr_entries; i++) { + const struct lttng_enum_entry *entry = &enum_desc->entries[i]; + int j, len; + + ret = print_tabs(session, nesting + 1); + if (ret) + goto end; + ret = lttng_metadata_printf(session, + "\""); + if (ret) + goto end; + len = strlen(entry->string); + /* Escape the character '"' */ + for (j = 0; j < len; j++) { + char c = entry->string[j]; + + switch (c) { + case '"': + ret = lttng_metadata_printf(session, + "\\\""); + break; + case '\\': + ret = lttng_metadata_printf(session, + "\\\\"); + break; + default: + ret = lttng_metadata_printf(session, + "%c", c); + break; + } + if (ret) + goto end; + } + ret = lttng_metadata_printf(session, "\""); + if (ret) + goto end; + + if (entry->options.is_auto) { + ret = lttng_metadata_printf(session, ",\n"); + if (ret) + goto end; + } else { + ret = lttng_metadata_printf(session, + " = "); + if (ret) + goto end; + if (entry->start.signedness) + ret = lttng_metadata_printf(session, + "%lld", (long long) entry->start.value); + else + ret = lttng_metadata_printf(session, + "%llu", entry->start.value); + if (ret) + goto end; + if (entry->start.signedness == entry->end.signedness && + entry->start.value + == entry->end.value) { + ret = lttng_metadata_printf(session, + ",\n"); + } else { + if (entry->end.signedness) { + ret = lttng_metadata_printf(session, + " ... %lld,\n", + (long long) entry->end.value); + } else { + ret = lttng_metadata_printf(session, + " ... %llu,\n", + entry->end.value); + } + } + if (ret) + goto end; + } + } + ret = print_tabs(session, nesting); + if (ret) + goto end; + ret = lttng_metadata_printf(session, "} _%s;\n", + field->name); +end: + return ret; +} + /* * Must be called with sessions_mutex held. */ static int _lttng_field_statedump(struct lttng_session *session, - const struct lttng_event_field *field) + const struct lttng_event_field *field, + size_t nesting) { int ret = 0; switch (field->type.atype) { case atype_integer: + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s;\n", + "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, @@ -1691,10 +2039,7 @@ int _lttng_field_statedump(struct lttng_session *session, field->name); break; case atype_enum: - ret = lttng_metadata_printf(session, - " %s _%s;\n", - field->type.u.basic.enumeration.name, - field->name); + ret = _lttng_enum_statedump(session, field, nesting); break; case atype_array: { @@ -1702,15 +2047,21 @@ int _lttng_field_statedump(struct lttng_session *session, elem_type = &field->type.u.array.elem_type; if (field->type.u.array.elem_alignment) { + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " struct { } align(%u) _%s_padding;\n", + "struct { } align(%u) _%s_padding;\n", field->type.u.array.elem_alignment * CHAR_BIT, field->name); if (ret) return ret; } + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } _%s[%u];\n", + "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, @@ -1735,8 +2086,11 @@ int _lttng_field_statedump(struct lttng_session *session, elem_type = &field->type.u.sequence.elem_type; length_type = &field->type.u.sequence.length_type; + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " integer { size = %u; align = %u; signed = %u; encoding = %s; base = %u;%s } __%s_length;\n", + "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, @@ -1756,15 +2110,21 @@ int _lttng_field_statedump(struct lttng_session *session, return ret; if (field->type.u.sequence.elem_alignment) { + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " struct { } align(%u) _%s_padding;\n", + "struct { } align(%u) _%s_padding;\n", field->type.u.sequence.elem_alignment * CHAR_BIT, field->name); if (ret) return ret; } + ret = print_tabs(session, nesting); + 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", + "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, @@ -1786,12 +2146,28 @@ int _lttng_field_statedump(struct lttng_session *session, case atype_string: /* Default encoding is UTF8 */ + ret = print_tabs(session, nesting); + if (ret) + return ret; ret = lttng_metadata_printf(session, - " string%s _%s;\n", + "string%s _%s;\n", field->type.u.basic.string.encoding == lttng_encode_ASCII ? " { encoding = ASCII; }" : "", field->name); break; + case atype_struct: + ret = _lttng_struct_statedump(session, field, nesting); + break; + case atype_array_compound: + ret = _lttng_array_compound_statedump(session, field, nesting); + break; + case atype_sequence_compound: + ret = _lttng_sequence_compound_statedump(session, field, nesting); + break; + case atype_variant: + ret = _lttng_variant_statedump(session, field, nesting); + break; + default: WARN_ON_ONCE(1); return -EINVAL; @@ -1811,7 +2187,7 @@ int _lttng_context_metadata_statedump(struct lttng_session *session, for (i = 0; i < ctx->nr_fields; i++) { const struct lttng_ctx_field *field = &ctx->fields[i]; - ret = _lttng_field_statedump(session, &field->event_field); + ret = _lttng_field_statedump(session, &field->event_field, 2); if (ret) return ret; } @@ -1829,7 +2205,7 @@ int _lttng_fields_metadata_statedump(struct lttng_session *session, for (i = 0; i < desc->nr_fields; i++) { const struct lttng_event_field *field = &desc->fields[i]; - ret = _lttng_field_statedump(session, field); + ret = _lttng_field_statedump(session, field, 2); if (ret) return ret; } @@ -2039,7 +2415,7 @@ int64_t measure_clock_offset(void) /* Disable interrupts to increase correlation precision. */ local_irq_save(flags); monotonic[0] = trace_clock_read64(); - getnstimeofday(&rts); + getnstimeofday(&rts); monotonic[1] = trace_clock_read64(); local_irq_restore(flags); @@ -2273,6 +2649,9 @@ static int __init lttng_events_init(void) if (ret) return ret; ret = wrapper_get_pageblock_flags_mask_init(); + if (ret) + return ret; + ret = lttng_probes_init(); if (ret) return ret; ret = lttng_context_init();