From: Julien Desfossez Date: Thu, 30 Jan 2014 04:20:25 +0000 (-0500) Subject: Big cleanup of network live X-Git-Tag: v0.3~66 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=12a91e9dd6c9cc18989351762d19ed1e69fe627c;p=lttngtop.git Big cleanup of network live Sync with the babeltrace tree to use the same code base for network live streaming. Use : $ lttngtop -r net://localhost to list the sessions on localhost and then $ lttngtop -r net://localhost/42 to attach to session 42 on localhost for example. Signed-off-by: Julien Desfossez --- diff --git a/lib/babeltrace/ctf-writer/clock-internal.h b/lib/babeltrace/ctf-writer/clock-internal.h new file mode 100644 index 0000000..c60e5c0 --- /dev/null +++ b/lib/babeltrace/ctf-writer/clock-internal.h @@ -0,0 +1,65 @@ +#ifndef BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H +#define BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Clock internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 +#include + +struct bt_ctf_clock { + struct bt_ctf_ref ref_count; + GString *name; + GString *description; + uint64_t frequency; + uint64_t precision; + uint64_t offset_s; /* Offset in seconds */ + uint64_t offset; /* Offset in ticks */ + uint64_t time; /* Current clock value */ + uuid_t uuid; + int absolute; + /* + * A clock's properties can't be modified once it is added to a stream + * class. + */ + int frozen; +}; + +BT_HIDDEN +void bt_ctf_clock_freeze(struct bt_ctf_clock *clock); + +BT_HIDDEN +void bt_ctf_clock_serialize(struct bt_ctf_clock *clock, + struct metadata_context *context); + +BT_HIDDEN +uint64_t bt_ctf_clock_get_time(struct bt_ctf_clock *clock); + +#endif /* BABELTRACE_CTF_WRITER_CLOCK_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/clock.h b/lib/babeltrace/ctf-writer/clock.h new file mode 100644 index 0000000..7cfc073 --- /dev/null +++ b/lib/babeltrace/ctf-writer/clock.h @@ -0,0 +1,166 @@ +#ifndef BABELTRACE_CTF_WRITER_CLOCK_H +#define BABELTRACE_CTF_WRITER_CLOCK_H + +/* + * BabelTrace - CTF Writer: Clock + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_clock; + +/* + * bt_ctf_clock_create: create a clock. + * + * Allocate a new clock setting its reference count to 1. + * + * @param name Name of the clock (will be copied). + * + * Returns an allocated clock on success, NULL on error. + */ +extern struct bt_ctf_clock *bt_ctf_clock_create(const char *name); + +/* + * bt_ctf_clock_set_description: set a clock's description. + * + * Set the clock's description. The description appears in the clock's TSDL + * meta-data. + * + * @param clock Clock instance. + * @param desc Description of the clock. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_description(struct bt_ctf_clock *clock, + const char *desc); + +/* + * bt_ctf_clock_set_frequency: set a clock's frequency. + * + * Set the clock's frequency (Hz). + * + * @param clock Clock instance. + * @param freq Clock's frequency in Hz, defaults to 1 000 000 000 Hz (1ns). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_frequency(struct bt_ctf_clock *clock, + uint64_t freq); + +/* + * bt_ctf_clock_set_precision: set a clock's precision. + * + * Set the clock's precision. + * + * @param clock Clock instance. + * @param precision Clock's precision in clock ticks, defaults to 1. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_precision(struct bt_ctf_clock *clock, + uint64_t precision); + +/* + * bt_ctf_clock_set_offset_s: set a clock's offset in seconds. + * + * Set the clock's offset in seconds from POSIX.1 Epoch, 1970-01-01, + * defaults to 0. + * + * @param clock Clock instance. + * @param offset_s Clock's offset in seconds, defaults to 0. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_offset_s(struct bt_ctf_clock *clock, + uint64_t offset_s); + + +/* + * bt_ctf_clock_set_offset: set a clock's offset in ticks. + * + * Set the clock's offset in ticks from Epoch + offset_s. + * + * @param clock Clock instance. + * @param offset Clock's offset in ticks from Epoch + offset_s, defaults to 0. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_offset(struct bt_ctf_clock *clock, + uint64_t offset); + +/* + * bt_ctf_clock_set_is_absolute: set a clock's absolute attribute. + * + * A clock is absolute if the clock is a global reference across the trace's + * other clocks. + * + * @param clock Clock instance. + * @param is_absolute Clock's absolute attribute, defaults to FALSE. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_is_absolute(struct bt_ctf_clock *clock, + int is_absolute); + +/* + * bt_ctf_clock_set_time: set a clock's current time value. + * + * Set the current time in nanoseconds since the clock's origin (offset and + * offset_s attributes). The clock's value will be sampled as events are + * appended to a stream. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_clock_set_time(struct bt_ctf_clock *clock, uint64_t time); + +/* + * bt_ctf_clock_get and bt_ctf_clock_put: increment and decrement the + * refcount of the clock + * + * These functions ensure that the clock won't be destroyed when it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) has to be done to + * destroy a clock. + * + * When the clock refcount is decremented to 0 by a bt_ctf_clock_put, + * the clock is freed. + * + * @param clock Clock instance. + */ +extern void bt_ctf_clock_get(struct bt_ctf_clock *clock); +extern void bt_ctf_clock_put(struct bt_ctf_clock *clock); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_CLOCK_H */ diff --git a/lib/babeltrace/ctf-writer/event-fields-internal.h b/lib/babeltrace/ctf-writer/event-fields-internal.h new file mode 100644 index 0000000..9f2670d --- /dev/null +++ b/lib/babeltrace/ctf-writer/event-fields-internal.h @@ -0,0 +1,100 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H +#define BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Event Fields internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 bt_ctf_field { + struct bt_ctf_ref ref_count; + struct bt_ctf_field_type *type; + int payload_set; +}; + +struct bt_ctf_field_integer { + struct bt_ctf_field parent; + struct definition_integer definition; +}; + +struct bt_ctf_field_enumeration { + struct bt_ctf_field parent; + struct bt_ctf_field *payload; +}; + +struct bt_ctf_field_floating_point { + struct bt_ctf_field parent; + struct definition_float definition; + struct definition_integer sign, mantissa, exp; +}; + +struct bt_ctf_field_structure { + struct bt_ctf_field parent; + GHashTable *field_name_to_index; + GPtrArray *fields; /* Array of pointers to struct bt_ctf_field */ +}; + +struct bt_ctf_field_variant { + struct bt_ctf_field parent; + struct bt_ctf_field *tag; + struct bt_ctf_field *payload; +}; + +struct bt_ctf_field_array { + struct bt_ctf_field parent; + GPtrArray *elements; /* Array of pointers to struct bt_ctf_field */ +}; + +struct bt_ctf_field_sequence { + struct bt_ctf_field parent; + struct bt_ctf_field *length; + GPtrArray *elements; /* Array of pointers to struct bt_ctf_field */ +}; + +struct bt_ctf_field_string { + struct bt_ctf_field parent; + GString *payload; +}; + +/* + * Set a field's value with an already allocated field instance. + */ +BT_HIDDEN +int bt_ctf_field_structure_set_field(struct bt_ctf_field *structure, + const char *name, struct bt_ctf_field *value); + +BT_HIDDEN +int bt_ctf_field_validate(struct bt_ctf_field *field); + +BT_HIDDEN +int bt_ctf_field_serialize(struct bt_ctf_field *field, + struct ctf_stream_pos *pos); + +#endif /* BABELTRACE_CTF_WRITER_EVENT_FIELDS_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/event-fields.h b/lib/babeltrace/ctf-writer/event-fields.h new file mode 100644 index 0000000..8d3190b --- /dev/null +++ b/lib/babeltrace/ctf-writer/event-fields.h @@ -0,0 +1,218 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_FIELDS_H +#define BABELTRACE_CTF_WRITER_EVENT_FIELDS_H + +/* + * BabelTrace - CTF Writer: Event Fields + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field; +struct bt_ctf_field_type; + +/* + * bt_ctf_field_create: create an instance of a field. + * + * Allocate a new field of the type described by the bt_ctf_field_type + * structure.The creation of a field sets its reference count to 1. + * + * @param type Field type to be instanciated. + * + * Returns an allocated field on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_create( + struct bt_ctf_field_type *type); + +/* + * bt_ctf_field_structure_get_field: get a structure's field. + * + * Get the structure's field corresponding to the provided field name. + * bt_ctf_field_put() must be called on the returned value. + * + * @param structure Structure field instance. + * @param name Name of the field in the provided structure. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_structure_get_field( + struct bt_ctf_field *structure, const char *name); + +/* + * bt_ctf_field_array_get_field: get an array's field at position "index". + * + * Return the array's field at position "index". bt_ctf_field_put() must be + * called on the returned value. + * + * @param array Array field instance. + * @param index Position of the array's desired element. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_array_get_field( + struct bt_ctf_field *array, uint64_t index); + +/* + * bt_ctf_field_sequence_set_length: set a sequence's length. + * + * Set the sequence's length field. + * + * @param sequence Sequence field instance. + * @param length_field Integer field instance indicating the sequence's length. + * + * Returns a field instance on success, NULL on error. + */ +extern int bt_ctf_field_sequence_set_length(struct bt_ctf_field *sequence, + struct bt_ctf_field *length_field); + +/* + * bt_ctf_field_sequence_get_field: get a sequence's field at position "index". + * + * Return the sequence's field at position "index". The sequence's length must + * have been set prior to calling this function using + * bt_ctf_field_sequence_set_length(). + * bt_ctf_field_put() must be called on the returned value. + * + * @param array Sequence field instance. + * @param index Position of the sequence's desired element. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_sequence_get_field( + struct bt_ctf_field *sequence, uint64_t index); + +/* + * bt_ctf_field_variant_get_field: get a variant's selected field. + * + * Return the variant's selected field. The "tag" field is the selector enum + * field. bt_ctf_field_put() must be called on the returned value. + * + * @param variant Variant field instance. + * @param tag Selector enumeration field. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_variant_get_field( + struct bt_ctf_field *variant, struct bt_ctf_field *tag); + +/* + * bt_ctf_field_enumeration_get_container: get an enumeration field's container. + * + * Return the enumeration's underlying container field (an integer). + * bt_ctf_field_put() must be called on the returned value. + * + * @param enumeration Enumeration field instance. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_field_enumeration_get_container( + struct bt_ctf_field *enumeration); + +/* + * bt_ctf_field_signed_integer_set_value: set a signed integer field's value + * + * Set a signed integer field's value. The value is checked to make sure it + * can be stored in the underlying field. + * + * @param integer Signed integer field instance. + * @param value Signed integer field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_signed_integer_set_value(struct bt_ctf_field *integer, + int64_t value); + +/* + * bt_ctf_field_unsigned_integer_set_value: set unsigned integer field's value + * + * Set an unsigned integer field's value. The value is checked to make sure it + * can be stored in the underlying field. + * + * @param integer Unsigned integer field instance. + * @param value Unsigned integer field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_unsigned_integer_set_value(struct bt_ctf_field *integer, + uint64_t value); + +/* + * bt_ctf_field_floating_point_set_value: set a floating point field's value + * + * Set a floating point field's value. The underlying type may not support the + * double's full precision. + * + * @param floating_point Floating point field instance. + * @param value Floating point field value. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_floating_point_set_value( + struct bt_ctf_field *floating_point, + double value); + +/* + * bt_ctf_field_string_set_value: set a string field's value + * + * Set a string field's value. + * + * @param string String field instance. + * @param value String field value (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_string_set_value(struct bt_ctf_field *string, + const char *value); + +/* + * bt_ctf_field_get and bt_ctf_field_put: increment and decrement the + * field's reference count. + * + * These functions ensure that the field won't be destroyed when it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a field. + * + * When the field's reference count is decremented to 0 by a bt_ctf_field_put, + * the field is freed. + * + * @param field Field instance. + */ +extern void bt_ctf_field_get(struct bt_ctf_field *field); +extern void bt_ctf_field_put(struct bt_ctf_field *field); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_EVENT_FIELDS_H */ diff --git a/lib/babeltrace/ctf-writer/event-internal.h b/lib/babeltrace/ctf-writer/event-internal.h new file mode 100644 index 0000000..b84c3dd --- /dev/null +++ b/lib/babeltrace/ctf-writer/event-internal.h @@ -0,0 +1,90 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H +#define BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Event internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 +#include + +struct bt_ctf_event_class { + struct bt_ctf_ref ref_count; + GQuark name; + int id_set; + uint32_t id; + int stream_id_set; + uint32_t stream_id; + /* Structure type containing the event's context */ + struct bt_ctf_field_type *context; + /* Structure type containing the event's fields */ + struct bt_ctf_field_type *fields; + int frozen; +}; + +struct bt_ctf_event { + struct bt_ctf_ref ref_count; + uint64_t timestamp; + struct bt_ctf_event_class *event_class; + struct bt_ctf_field *context_payload; + struct bt_ctf_field *fields_payload; +}; + +BT_HIDDEN +void bt_ctf_event_class_freeze(struct bt_ctf_event_class *event_class); + +BT_HIDDEN +int bt_ctf_event_class_set_id(struct bt_ctf_event_class *event_class, + uint32_t id); + +BT_HIDDEN +uint32_t bt_ctf_event_class_get_id(struct bt_ctf_event_class *event_class); + +BT_HIDDEN +int bt_ctf_event_class_set_stream_id(struct bt_ctf_event_class *event_class, + uint32_t id); + +BT_HIDDEN +int bt_ctf_event_class_serialize(struct bt_ctf_event_class *event_class, + struct metadata_context *context); + +BT_HIDDEN +int bt_ctf_event_validate(struct bt_ctf_event *event); + +BT_HIDDEN +int bt_ctf_event_serialize(struct bt_ctf_event *event, + struct ctf_stream_pos *pos); + +BT_HIDDEN +int bt_ctf_event_set_timestamp(struct bt_ctf_event *event, uint64_t timestamp); + +BT_HIDDEN +uint64_t bt_ctf_event_get_timestamp(struct bt_ctf_event *event); + +#endif /* BABELTRACE_CTF_WRITER_EVENT_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/event-types-internal.h b/lib/babeltrace/ctf-writer/event-types-internal.h new file mode 100644 index 0000000..a937c78 --- /dev/null +++ b/lib/babeltrace/ctf-writer/event-types-internal.h @@ -0,0 +1,153 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H +#define BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Event types internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 +#include +#include +#include +#include + +typedef void(*type_freeze_func)(struct bt_ctf_field_type *); +typedef int(*type_serialize_func)(struct bt_ctf_field_type *, + struct metadata_context *); + +struct bt_ctf_field_type { + struct bt_ctf_ref ref_count; + struct bt_declaration *declaration; + type_freeze_func freeze; + type_serialize_func serialize; + /* + * A type can't be modified once it is added to an event or after a + * a field has been instanciated from it. + */ + int frozen; +}; + +struct bt_ctf_field_type_integer { + struct bt_ctf_field_type parent; + struct declaration_integer declaration; +}; + +struct enumeration_mapping { + int64_t range_start; + int64_t range_end; + GQuark string; +}; + +struct bt_ctf_field_type_enumeration { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *container; + GPtrArray *entries; /* Array of pointers to struct enum_mapping */ + struct declaration_enum declaration; +}; + +struct bt_ctf_field_type_floating_point { + struct bt_ctf_field_type parent; + struct declaration_float declaration; + struct declaration_integer sign; + struct declaration_integer mantissa; + struct declaration_integer exp; +}; + +struct structure_field { + GQuark name; + struct bt_ctf_field_type *type; +}; + +struct bt_ctf_field_type_structure { + struct bt_ctf_field_type parent; + GHashTable *field_name_to_index; + GPtrArray *fields; /* Array of pointers to struct structure_field */ + struct declaration_enum declaration; +}; + +struct bt_ctf_field_type_variant { + struct bt_ctf_field_type parent; + GString *tag_name; + struct bt_ctf_field_type_enumeration *tag; + GHashTable *field_name_to_index; + GPtrArray *fields; /* Array of pointers to struct structure_field */ + struct declaration_variant declaration; +}; + +struct bt_ctf_field_type_array { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *element_type; + unsigned int length; /* Number of elements */ + struct declaration_array declaration; +}; + +struct bt_ctf_field_type_sequence { + struct bt_ctf_field_type parent; + struct bt_ctf_field_type *element_type; + GString *length_field_name; + struct declaration_sequence declaration; +}; + +struct bt_ctf_field_type_string { + struct bt_ctf_field_type parent; + struct declaration_string declaration; +}; + +BT_HIDDEN +void bt_ctf_field_type_freeze(struct bt_ctf_field_type *type); + +BT_HIDDEN +enum ctf_type_id bt_ctf_field_type_get_type_id( + struct bt_ctf_field_type *type); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_structure_get_type( + struct bt_ctf_field_type_structure *structure, + const char *name); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_array_get_element_type( + struct bt_ctf_field_type_array *array); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_sequence_get_element_type( + struct bt_ctf_field_type_sequence *sequence); + +BT_HIDDEN +struct bt_ctf_field_type *bt_ctf_field_type_variant_get_field_type( + struct bt_ctf_field_type_variant *variant, int64_t tag_value); + +BT_HIDDEN +int bt_ctf_field_type_serialize(struct bt_ctf_field_type *type, + struct metadata_context *context); + +BT_HIDDEN +int bt_ctf_field_type_validate(struct bt_ctf_field_type *type); + +#endif /* BABELTRACE_CTF_WRITER_EVENT_TYPES_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/event-types.h b/lib/babeltrace/ctf-writer/event-types.h new file mode 100644 index 0000000..cf43ed6 --- /dev/null +++ b/lib/babeltrace/ctf-writer/event-types.h @@ -0,0 +1,353 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_TYPES_H +#define BABELTRACE_CTF_WRITER_EVENT_TYPES_H + +/* + * BabelTrace - CTF Writer: Event Types + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field_type; + +enum bt_ctf_integer_base { + BT_CTF_INTEGER_BASE_UNKNOWN = -1, + BT_CTF_INTEGER_BASE_BINARY = 2, + BT_CTF_INTEGER_BASE_OCTAL = 8, + BT_CTF_INTEGER_BASE_DECIMAL = 10, + BT_CTF_INTEGER_BASE_HEXADECIMAL = 16, +}; + +/* + * bt_ctf_field_type_integer_create: create an integer field type. + * + * Allocate a new integer field type of the given size. The creation of a field + * type sets its reference count to 1. + * + * @param size Integer field type size/length in bits. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_integer_create( + unsigned int size); + +/* + * bt_ctf_field_type_integer_set_signed: set an integer type's signedness. + * + * Set an integer type's signedness attribute. + * + * @param integer Integer type. + * @param is_signed Integer's signedness, defaults to FALSE. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_signed( + struct bt_ctf_field_type *integer, int is_signed); + +/* + * bt_ctf_field_type_integer_set_base: set an integer type's base. + * + * Set an integer type's base used to pretty-print the resulting trace. + * + * @param integer Integer type. + * @param base Integer base, defaults to BT_CTF_INTEGER_BASE_DECIMAL. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_base( + struct bt_ctf_field_type *integer, + enum bt_ctf_integer_base base); + +/* + * bt_ctf_field_type_integer_set_encoding: set an integer type's encoding. + * + * An integer encoding may be set to signal that the integer must be printed as + * a text character. + * + * @param integer Integer type. + * @param encoding Integer output encoding, defaults to CTF_STRING_ENCODING_NONE + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_integer_set_encoding( + struct bt_ctf_field_type *integer, + enum ctf_string_encoding encoding); + +/* + * bt_ctf_field_type_enumeration_create: create an enumeration field type. + * + * Allocate a new enumeration field type with the given underlying type. The + * creation of a field type sets its reference count to 1. + * The resulting enumeration will share the integer_container_type's ownership + * by increasing its reference count. + * + * @param integer_container_type Underlying integer type of the enumeration + * type. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_enumeration_create( + struct bt_ctf_field_type *integer_container_type); + +/* + * bt_ctf_field_type_enumeration_add_mapping: add an enumeration mapping. + * + * Add a mapping to the enumeration. The range's values are inclusive. + * + * @param enumeration Enumeration type. + * @param string Enumeration mapping name (will be copied). + * @param range_start Enumeration mapping range start. + * @param range_end Enumeration mapping range end. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_enumeration_add_mapping( + struct bt_ctf_field_type *enumeration, const char *string, + int64_t range_start, int64_t range_end); + +/* + * bt_ctf_field_type_floating_point_create: create a floating point field type. + * + * Allocate a new floating point field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_floating_point_create(void); + +/* + * bt_ctf_field_type_floating_point_set_exponent_digits: set exponent digit + * count. + * + * Set the number of exponent digits to use to store the floating point field. + * The only values currently supported are FLT_EXP_DIG and DBL_EXP_DIG. + * + * @param floating_point Floating point type. + * @param exponent_digits Number of digits to allocate to the exponent (defaults + * to FLT_EXP_DIG). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_set_exponent_digits( + struct bt_ctf_field_type *floating_point, + unsigned int exponent_digits); + +/* + * bt_ctf_field_type_floating_point_set_mantissa_digits: set mantissa digit + * count. + * + * Set the number of mantissa digits to use to store the floating point field. + * The only values currently supported are FLT_MANT_DIG and DBL_MANT_DIG. + * + * @param floating_point Floating point type. + * @param mantissa_digits Number of digits to allocate to the mantissa (defaults + * to FLT_MANT_DIG). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_floating_point_set_mantissa_digits( + struct bt_ctf_field_type *floating_point, + unsigned int mantissa_digits); + +/* + * bt_ctf_field_type_structure_create: create a structure field type. + * + * Allocate a new structure field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_structure_create(void); + +/* + * bt_ctf_field_type_structure_add_field: add a field to a structure. + * + * Add a field of type "field_type" to the structure. The structure will share + * field_type's ownership by increasing its reference count. + * + * @param structure Structure type. + * @param field_type Type of the field to add to the structure type. + * @param field_name Name of the structure's new field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_structure_add_field( + struct bt_ctf_field_type *structure, + struct bt_ctf_field_type *field_type, + const char *field_name); + +/* + * bt_ctf_field_type_variant_create: create a variant field type. + * + * Allocate a new variant field type. The creation of a field type sets + * its reference count to 1. tag_name must be the name of an enumeration + * field declared in the same scope as this variant. + * + * @param enum_tag Type of the variant's tag/selector (must be an enumeration). + * @param tag_name Name of the variant's tag/selector field (will be copied). + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_variant_create( + struct bt_ctf_field_type *enum_tag, + const char *tag_name); + +/* + * bt_ctf_field_type_variant_add_field: add a field to a variant. + * + * Add a field of type "field_type" to the variant.The variant will share + * field_type's ownership by increasing its reference count. The "field_name" + * will be copied. field_name must match a mapping in the tag/selector + * enumeration. + * + * @param variant Variant type. + * @param field_type Type of the variant type's new field. + * @param field_name Name of the variant type's new field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_variant_add_field( + struct bt_ctf_field_type *variant, + struct bt_ctf_field_type *field_type, + const char *field_name); + +/* + * bt_ctf_field_type_array_create: create an array field type. + * + * Allocate a new array field type. The creation of a field type sets + * its reference count to 1. + * + * @param element_type Array's element type. + * @oaram length Array type's length. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_array_create( + struct bt_ctf_field_type *element_type, + unsigned int length); + +/* + * bt_ctf_field_type_sequence_create: create a sequence field type. + * + * Allocate a new sequence field type. The creation of a field type sets + * its reference count to 1. "length_field_name" must match an integer field + * declared in the same scope. + * + * @param element_type Sequence's element type. + * @param length_field_name Name of the sequence's length field (will be + * copied). + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_sequence_create( + struct bt_ctf_field_type *element_type, + const char *length_field_name); + +/* + * bt_ctf_field_type_string_create: create a string field type. + * + * Allocate a new string field type. The creation of a field type sets + * its reference count to 1. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_field_type *bt_ctf_field_type_string_create(void); + +/* + * bt_ctf_field_type_string_set_encoding: set a string type's encoding. + * + * Set the string type's encoding. + * + * @param string String type. + * @param encoding String field encoding, default CTF_STRING_ENCODING_ASCII. + * Valid values are CTF_STRING_ENCODING_ASCII and CTF_STRING_ENCODING_UTF8. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_string_set_encoding( + struct bt_ctf_field_type *string, + enum ctf_string_encoding encoding); + +/* + * bt_ctf_field_type_set_alignment: set a field type's alignment. + * + * Set the field type's alignment. + * + * @param type Field type. + * @param alignment Type's alignment. Defaults to 1 (bit-aligned). However, + * some types, such as structures and string, may impose other alignment + * constraints. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_set_alignment(struct bt_ctf_field_type *type, + unsigned int alignment); + +/* + * bt_ctf_field_type_set_byte_order: set a field type's byte order. + * + * Set the field type's byte order. + * + * @param type Field type. + * @param byte_order Field type's byte order. Defaults to + * BT_CTF_BYTE_ORDER_NATIVE, the host machine's endianness. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_field_type_set_byte_order(struct bt_ctf_field_type *type, + enum bt_ctf_byte_order byte_order); + +/* + * bt_ctf_field_type_get and bt_ctf_field_type_put: increment and decrement + * the field type's reference count. + * + * These functions ensure that the field type won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a field type. + * + * When the field type's reference count is decremented to 0 by a + * bt_ctf_field_type_put, the field type is freed. + * + * @param type Field type. + */ +extern void bt_ctf_field_type_get(struct bt_ctf_field_type *type); +extern void bt_ctf_field_type_put(struct bt_ctf_field_type *type); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_EVENT_TYPES_H */ diff --git a/lib/babeltrace/ctf-writer/event.h b/lib/babeltrace/ctf-writer/event.h new file mode 100644 index 0000000..d8ef9d9 --- /dev/null +++ b/lib/babeltrace/ctf-writer/event.h @@ -0,0 +1,154 @@ +#ifndef BABELTRACE_CTF_WRITER_EVENT_H +#define BABELTRACE_CTF_WRITER_EVENT_H + +/* + * BabelTrace - CTF Writer: Event + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event_class; +struct bt_ctf_event; +struct bt_ctf_field; +struct bt_ctf_field_type; + +/* + * bt_ctf_event_class_create: create an event class. + * + * Allocate a new event class of the given name. The creation of an event class + * sets its reference count to 1. + * + * @param name Event class name (will be copied). + * + * Returns an allocated event class on success, NULL on error. + */ +extern struct bt_ctf_event_class *bt_ctf_event_class_create(const char *name); + +/* + * bt_ctf_event_class_add_field: add a field to an event class. + * + * Add a field of type "type" to the event class. The event class will share + * type's ownership by increasing its reference count. The "name" will be + * copied. + * + * @param event_class Event class. + * @param type Field type to add to the event class. + * @param name Name of the new field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_class_add_field(struct bt_ctf_event_class *event_class, + struct bt_ctf_field_type *type, + const char *name); + +/* + * bt_ctf_event_class__get and bt_ctf_event_class_put: increment and decrement + * the event class' reference count. + * + * These functions ensure that the event class won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy an event class. + * + * When the event class' reference count is decremented to 0 by a + * bt_ctf_event_class_put, the event class is freed. + * + * @param event_class Event class. + */ +extern void bt_ctf_event_class_get(struct bt_ctf_event_class *event_class); +extern void bt_ctf_event_class_put(struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_create: instanciate an event. + * + * Allocate a new event of the given event class. The creation of an event + * sets its reference count to 1. Each instance shares the ownership of the + * event class using its reference count. + * + * @param event_class Event class. + * + * Returns an allocated field type on success, NULL on error. + */ +extern struct bt_ctf_event *bt_ctf_event_create( + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_event_set_payload: set an event's field. + * + * Set a manually allocated field as an event's payload. The event will share + * the field's ownership by using its reference count. + * bt_ctf_field_put() must be called on the returned value. + * + * @param event Event instance. + * @param name Event field name. + * @param value Instance of a field whose type corresponds to the event's field. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_event_set_payload(struct bt_ctf_event *event, + const char *name, + struct bt_ctf_field *value); + +/* + * bt_ctf_event_get_payload: get an event's field. + * + * Returns the field matching "name". bt_ctf_field_put() must be called on the + * returned value. + * + * @param event Event instance. + * @param name Event field name. + * + * Returns a field instance on success, NULL on error. + */ +extern struct bt_ctf_field *bt_ctf_event_get_payload(struct bt_ctf_event *event, + const char *name); + +/* + * bt_ctf_event_get and bt_ctf_event_put: increment and decrement + * the event's reference count. + * + * These functions ensure that the event won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy an event. + * + * When the event's reference count is decremented to 0 by a + * bt_ctf_event_put, the event is freed. + * + * @param event Event instance. + */ +extern void bt_ctf_event_get(struct bt_ctf_event *event); +extern void bt_ctf_event_put(struct bt_ctf_event *event); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_EVENT_H */ diff --git a/lib/babeltrace/ctf-writer/functor-internal.h b/lib/babeltrace/ctf-writer/functor-internal.h new file mode 100644 index 0000000..66d3fcf --- /dev/null +++ b/lib/babeltrace/ctf-writer/functor-internal.h @@ -0,0 +1,41 @@ +#ifndef BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H +#define BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Functors for use with glib data structures + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 + +struct search_query { + gpointer value; + int found; +}; + +BT_HIDDEN +void value_exists(gpointer element, gpointer search_query); + +#endif /* BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/ref-internal.h b/lib/babeltrace/ctf-writer/ref-internal.h new file mode 100644 index 0000000..486e243 --- /dev/null +++ b/lib/babeltrace/ctf-writer/ref-internal.h @@ -0,0 +1,61 @@ +#ifndef BABELTRACE_CTF_WRITER_REF_INTERNAL_H +#define BABELTRACE_CTF_WRITER_REF_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Reference count + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 + +struct bt_ctf_ref { + long refcount; +}; + +static inline +void bt_ctf_ref_init(struct bt_ctf_ref *ref) +{ + assert(ref); + ref->refcount = 1; +} + +static inline +void bt_ctf_ref_get(struct bt_ctf_ref *ref) +{ + assert(ref); + ref->refcount++; +} + +static inline +void bt_ctf_ref_put(struct bt_ctf_ref *ref, + void (*release)(struct bt_ctf_ref *)) +{ + assert(ref); + assert(release); + if ((--ref->refcount) == 0) { + release(ref); + } +} + +#endif /* BABELTRACE_CTF_WRITER_REF_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/stream-internal.h b/lib/babeltrace/ctf-writer/stream-internal.h new file mode 100644 index 0000000..57dd992 --- /dev/null +++ b/lib/babeltrace/ctf-writer/stream-internal.h @@ -0,0 +1,101 @@ +#ifndef BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H +#define BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Stream internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 +#include +#include + +typedef void(*flush_func)(struct bt_ctf_stream *, void *); + +struct bt_ctf_stream_class { + struct bt_ctf_ref ref_count; + GString *name; + struct bt_ctf_clock *clock; + GPtrArray *event_classes; /* Array of pointers to bt_ctf_event_class */ + int id_set; + uint32_t id; + uint32_t next_event_id; + uint32_t next_stream_id; + struct bt_ctf_field_type *event_header_type; + struct bt_ctf_field *event_header; + struct bt_ctf_field_type *packet_context_type; + struct bt_ctf_field *packet_context; + struct bt_ctf_field_type *event_context_type; + struct bt_ctf_field *event_context; + int frozen; +}; + +struct flush_callback { + flush_func func; + void *data; +}; + +struct bt_ctf_stream { + struct bt_ctf_ref ref_count; + uint32_t id; + struct bt_ctf_stream_class *stream_class; + struct flush_callback flush; + /* Array of pointers to bt_ctf_event for the current packet */ + GPtrArray *events; + struct ctf_stream_pos pos; + unsigned int flushed_packet_count; + uint64_t events_discarded; +}; + +BT_HIDDEN +void bt_ctf_stream_class_freeze(struct bt_ctf_stream_class *stream_class); + +BT_HIDDEN +int bt_ctf_stream_class_set_id(struct bt_ctf_stream_class *stream_class, + uint32_t id); + +BT_HIDDEN +int bt_ctf_stream_class_serialize(struct bt_ctf_stream_class *stream_class, + struct metadata_context *context); + +BT_HIDDEN +int bt_ctf_stream_class_set_byte_order(struct bt_ctf_stream_class *stream_class, + enum bt_ctf_byte_order byte_order); + +BT_HIDDEN +struct bt_ctf_stream *bt_ctf_stream_create( + struct bt_ctf_stream_class *stream_class); + +BT_HIDDEN +int bt_ctf_stream_set_flush_callback(struct bt_ctf_stream *stream, + flush_func callback, void *data); + +BT_HIDDEN +int bt_ctf_stream_set_fd(struct bt_ctf_stream *stream, int fd); + +#endif /* BABELTRACE_CTF_WRITER_STREAM_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/stream.h b/lib/babeltrace/ctf-writer/stream.h new file mode 100644 index 0000000..9229f77 --- /dev/null +++ b/lib/babeltrace/ctf-writer/stream.h @@ -0,0 +1,169 @@ +#ifndef BABELTRACE_CTF_WRITER_STREAM_H +#define BABELTRACE_CTF_WRITER_STREAM_H + +/* + * BabelTrace - CTF Writer: Stream + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_event; +struct bt_ctf_event_class; +struct bt_ctf_stream_class; +struct bt_ctf_stream; +struct bt_ctf_clock; + +/* + * bt_ctf_stream_class_create: create a stream class. + * + * Allocate a new stream class of the given name. The creation of an event class + * sets its reference count to 1. + * + * @param name Stream name. + * + * Returns an allocated stream class on success, NULL on error. + */ +extern struct bt_ctf_stream_class *bt_ctf_stream_class_create(const char *name); + +/* + * bt_ctf_stream_class_set_clock: assign a clock to a stream class. + * + * Assign a clock to a stream class. This clock will be sampled each time an + * event is appended to an instance of this stream class. + * + * @param stream_class Stream class. + * @param clock Clock to assign to the provided stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_set_clock( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_clock *clock); + +/* + * bt_ctf_stream_class_set_clock: assign a clock to a stream class. + * + * Add an event class to a stream class. New events can be added even after a + * stream has beem instanciated and events have been appended. However, a stream + * will not accept events of a class that has not been registered beforehand. + * The stream class will share the ownership of "event_class" by incrementing + * its reference count. + * + * @param stream_class Stream class. + * @param event_class Event class to add to the provided stream class. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_class_add_event_class( + struct bt_ctf_stream_class *stream_class, + struct bt_ctf_event_class *event_class); + +/* + * bt_ctf_stream_class_get and bt_ctf_stream_class_put: increment and + * decrement the stream class' reference count. + * + * These functions ensure that the stream class won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a stream class. + * + * When the stream class' reference count is decremented to 0 by a + * bt_ctf_stream_class_put, the stream class is freed. + * + * @param stream_class Stream class. + */ +extern void bt_ctf_stream_class_get(struct bt_ctf_stream_class *stream_class); +extern void bt_ctf_stream_class_put(struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_stream_append_discarded_events: increment discarded events count. + * + * Increase the current packet's discarded event count. + * + * @param stream Stream instance. + * @param event_count Number of discarded events to add to the stream's current + * packet. + * + * Returns 0 on success, a negative value on error. + */ +extern void bt_ctf_stream_append_discarded_events(struct bt_ctf_stream *stream, + uint64_t event_count); + +/* + * bt_ctf_stream_append_event: append an event to the stream. + * + * Append "event" to the stream's current packet. The stream's associated clock + * will be sampled during this call. The event shall not be modified after + * being appended to a stream. The stream will share the event's ownership by + * incrementing its reference count. The current packet is not flushed to disk + * until the next call to bt_ctf_stream_flush. + * + * @param stream Stream instance. + * @param event Event instance to append to the stream's current packet. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_append_event(struct bt_ctf_stream *stream, + struct bt_ctf_event *event); + +/* + * bt_ctf_stream_flush: flush a stream. + * + * The stream's current packet's events will be flushed to disk. Events + * subsequently appended to the stream will be added to a new packet. + * + * @param stream Stream instance. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_stream_flush(struct bt_ctf_stream *stream); + +/* + * bt_ctf_stream_get and bt_ctf_stream_put: increment and decrement the + * stream's reference count. + * + * These functions ensure that the stream won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a stream. + * + * When the stream's reference count is decremented to 0 by a + * bt_ctf_stream_put, the stream is freed. + * + * @param stream Stream instance. + */ +extern void bt_ctf_stream_get(struct bt_ctf_stream *stream); +extern void bt_ctf_stream_put(struct bt_ctf_stream *stream); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_STREAM_H */ diff --git a/lib/babeltrace/ctf-writer/writer-internal.h b/lib/babeltrace/ctf-writer/writer-internal.h new file mode 100644 index 0000000..5c682dd --- /dev/null +++ b/lib/babeltrace/ctf-writer/writer-internal.h @@ -0,0 +1,87 @@ +#ifndef BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H +#define BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H + +/* + * BabelTrace - CTF Writer: Writer internal + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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 +#include +#include +#include +#include + +enum field_type_alias { + FIELD_TYPE_ALIAS_UINT5_T = 0, + FIELD_TYPE_ALIAS_UINT8_T, + FIELD_TYPE_ALIAS_UINT16_T, + FIELD_TYPE_ALIAS_UINT27_T, + FIELD_TYPE_ALIAS_UINT32_T, + FIELD_TYPE_ALIAS_UINT64_T, + NR_FIELD_TYPE_ALIAS, +}; + +struct bt_ctf_writer { + struct bt_ctf_ref ref_count; + int frozen; /* Protects attributes that can't be changed mid-trace */ + GString *path; + uuid_t uuid; + int byte_order; + int trace_dir_fd; + int metadata_fd; + GPtrArray *environment; /* Array of pointers to environment_variable */ + GPtrArray *clocks; /* Array of pointers to bt_ctf_clock */ + GPtrArray *stream_classes; /* Array of pointers to bt_ctf_stream_class */ + GPtrArray *streams; /* Array of pointers to bt_ctf_stream */ + struct bt_ctf_field_type *trace_packet_header_type; + struct bt_ctf_field *trace_packet_header; + uint32_t next_stream_id; +}; + +struct environment_variable { + GString *name, *value; +}; + +struct metadata_context { + GString *string; + GString *field_name; + unsigned int current_indentation_level; +}; + +/* Checks that the string does not contain a reserved keyword */ +BT_HIDDEN +int validate_identifier(const char *string); + +BT_HIDDEN +const char *get_byte_order_string(int byte_order); + +BT_HIDDEN +struct bt_ctf_field_type *get_field_type(enum field_type_alias alias); + +#endif /* BABELTRACE_CTF_WRITER_WRITER_INTERNAL_H */ diff --git a/lib/babeltrace/ctf-writer/writer.h b/lib/babeltrace/ctf-writer/writer.h new file mode 100644 index 0000000..68031ac --- /dev/null +++ b/lib/babeltrace/ctf-writer/writer.h @@ -0,0 +1,164 @@ +#ifndef BABELTRACE_CTF_WRITER_WRITER_H +#define BABELTRACE_CTF_WRITER_WRITER_H + +/* + * BabelTrace - CTF Writer: Writer + * + * Copyright 2013 EfficiOS Inc. + * + * Author: Jérémie Galarneau + * + * 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. + * + * The Common Trace Format (CTF) Specification is available at + * http://www.efficios.com/ctf + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bt_ctf_writer; +struct bt_ctf_stream; +struct bt_ctf_stream_class; +struct bt_ctf_clock; + +enum bt_ctf_byte_order { + BT_CTF_BYTE_ORDER_NATIVE = 0, + BT_CTF_BYTE_ORDER_LITTLE_ENDIAN, + BT_CTF_BYTE_ORDER_BIG_ENDIAN, + BT_CTF_BYTE_ORDER_NETWORK, +}; + +/* + * bt_ctf_writer_create: create a writer instance. + * + * Allocate a new writer that will produce a trace in the given path. + * The creation of a writer sets its reference count to 1. + * + * @param path Path to the trace's containing folder (string is copied). + * + * Returns an allocated writer on success, NULL on error. + */ +extern struct bt_ctf_writer *bt_ctf_writer_create(const char *path); + +/* + * bt_ctf_writer_create_stream: create a stream instance. + * + * Allocate a new stream instance and register it to the writer. The creation of + * a stream sets its reference count to 1. + * + * @param writer Writer instance. + * @param stream_class Stream class to instantiate. + * + * Returns an allocated writer on success, NULL on error. + */ +extern struct bt_ctf_stream *bt_ctf_writer_create_stream( + struct bt_ctf_writer *writer, + struct bt_ctf_stream_class *stream_class); + +/* + * bt_ctf_writer_add_environment_field: add an environment field to the trace. + * + * Add an environment field to the trace. The name and value parameters are + * copied. + * + * @param writer Writer instance. + * @param name Name of the environment field (will be copied). + * @param value Value of the environment field (will be copied). + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_writer_add_environment_field(struct bt_ctf_writer *writer, + const char *name, + const char *value); + +/* + * bt_ctf_writer_add_clock: add a clock to the trace. + * + * Add a clock to the trace. Clocks assigned to stream classes must be + * registered to the writer. + * + * @param writer Writer instance. + * @param clock Clock to add to the trace. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_writer_add_clock(struct bt_ctf_writer *writer, + struct bt_ctf_clock *clock); + +/* + * bt_ctf_writer_get_metadata_string: get meta-data string. + * + * Get the trace's TSDL meta-data. The caller assumes the ownership of the + * returned string. + * + * @param writer Writer instance. + * + * Returns the metadata string on success, NULL on error. + */ +extern char *bt_ctf_writer_get_metadata_string(struct bt_ctf_writer *writer); + +/* + * bt_ctf_writer_flush_metadata: flush the trace's metadata to disk. + * + * Flush the trace's metadata to the metadata file. Note that the metadata will + * be flushed automatically when the Writer instance is released (last call to + * bt_ctf_writer_put). + * + * @param writer Writer instance. + */ +extern void bt_ctf_writer_flush_metadata(struct bt_ctf_writer *writer); + +/* + * bt_ctf_writer_set_byte_order: set a field type's byte order. + * + * Set the trace's byte order. Defaults to BT_CTF_BYTE_ORDER_NATIVE, + * the host machine's endianness. + * + * @param writer Writer instance. + * @param byte_order Trace's byte order. + * + * Returns 0 on success, a negative value on error. + */ +extern int bt_ctf_writer_set_byte_order(struct bt_ctf_writer *writer, + enum bt_ctf_byte_order byte_order); + +/* + * bt_ctf_writer_get and bt_ctf_writer_put: increment and decrement the + * writer's reference count. + * + * These functions ensure that the writer won't be destroyed while it + * is in use. The same number of get and put (plus one extra put to + * release the initial reference done at creation) have to be done to + * destroy a writer. + * + * When the writer's reference count is decremented to 0 by a + * bt_ctf_writer_put, the writer is freed. + * + * @param writer Writer instance. + */ +extern void bt_ctf_writer_get(struct bt_ctf_writer *writer); +extern void bt_ctf_writer_put(struct bt_ctf_writer *writer); + +#ifdef __cplusplus +} +#endif + +#endif /* BABELTRACE_CTF_WRITER_WRITER_H */ diff --git a/lib/babeltrace/ctf/ctf-index.h b/lib/babeltrace/ctf/ctf-index.h new file mode 100644 index 0000000..0efa888 --- /dev/null +++ b/lib/babeltrace/ctf/ctf-index.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * David Goulet + * + * 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. + */ + +#ifndef LTTNG_INDEX_H +#define LTTNG_INDEX_H + +#include + +#define CTF_INDEX_MAGIC 0xC1F1DCC1 +#define CTF_INDEX_MAJOR 1 +#define CTF_INDEX_MINOR 0 + +/* + * Header at the beginning of each index file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index_file_hdr { + uint32_t magic; + uint32_t index_major; + uint32_t index_minor; + /* struct packet_index_len, in bytes */ + uint32_t packet_index_len; +} __attribute__((__packed__)); + +/* + * Packet index generated for each trace packet store in a trace file. + * All integer fields are stored in big endian. + */ +struct ctf_packet_index { + uint64_t offset; /* offset of the packet in the file, in bytes */ + uint64_t packet_size; /* packet size, in bits */ + uint64_t content_size; /* content size, in bits */ + uint64_t timestamp_begin; + uint64_t timestamp_end; + uint64_t events_discarded; + uint64_t stream_id; +} __attribute__((__packed__)); + +#endif /* LTTNG_INDEX_H */ diff --git a/lib/babeltrace/ctf/events-internal.h b/lib/babeltrace/ctf/events-internal.h index be111c1..acc7562 100644 --- a/lib/babeltrace/ctf/events-internal.h +++ b/lib/babeltrace/ctf/events-internal.h @@ -38,6 +38,7 @@ #include struct ctf_stream_definition; +struct ctf_file_stream; /* * These structures are public mappings to internal ctf_event structures. @@ -81,5 +82,7 @@ struct bt_ctf_iter { void ctf_print_discarded(FILE *fp, struct ctf_stream_definition *stream, int end_stream); +void compute_discarded_events(struct ctf_file_stream *file_stream, + struct ctf_stream_pos *pos); #endif /*_BABELTRACE_CTF_EVENTS_INTERNAL_H */ diff --git a/lib/babeltrace/ctf/events.h b/lib/babeltrace/ctf/events.h index c92470c..c81d885 100644 --- a/lib/babeltrace/ctf/events.h +++ b/lib/babeltrace/ctf/events.h @@ -211,6 +211,12 @@ enum ctf_string_encoding bt_ctf_get_encoding(const struct bt_declaration *decl); */ int bt_ctf_get_array_len(const struct bt_declaration *decl); +/* + * bt_ctf_get_struct_field_count: return the number of fields in a structure. + * Returns a negative value on error. + */ +uint64_t bt_ctf_get_struct_field_count(const struct bt_definition *field); + /* * Field access functions * @@ -231,6 +237,10 @@ const struct bt_definition *bt_ctf_get_enum_int(const struct bt_definition *fiel const char *bt_ctf_get_enum_str(const struct bt_definition *field); char *bt_ctf_get_char_array(const struct bt_definition *field); char *bt_ctf_get_string(const struct bt_definition *field); +double bt_ctf_get_float(const struct bt_definition *field); +const struct bt_definition *bt_ctf_get_variant(const struct bt_definition *field); +const struct bt_definition *bt_ctf_get_struct_field_index( + const struct bt_definition *field, uint64_t i); /* * bt_ctf_field_get_error: returns the last error code encountered while diff --git a/lib/babeltrace/ctf/types.h b/lib/babeltrace/ctf/types.h index c64b8d2..338dad1 100644 --- a/lib/babeltrace/ctf/types.h +++ b/lib/babeltrace/ctf/types.h @@ -61,7 +61,7 @@ struct packet_index { struct ctf_stream_pos { struct bt_stream_pos parent; int fd; /* backing file fd. -1 if unset. */ - int index_fd; /* backing index file fd. -1 if unset. */ + FILE *index_fp; /* backing index file fp. NULL if unset. */ GArray *packet_cycles_index; /* contains struct packet_index in cycles */ GArray *packet_real_index; /* contains struct packet_index in ns */ int prot; /* mmap protection */ @@ -76,6 +76,7 @@ struct ctf_stream_pos { struct mmap_align *base_mma;/* mmap base address */ int64_t offset; /* offset from base, in bits. EOF for end of file. */ int64_t last_offset; /* offset before the last read_event */ + int64_t data_offset; /* offset of data in current packet */ uint64_t cur_index; /* current index in packet index */ uint64_t last_events_discarded; /* last known amount of event discarded */ void (*packet_seek)(struct bt_stream_pos *pos, size_t index, @@ -83,6 +84,7 @@ struct ctf_stream_pos { int dummy; /* dummy position, for length calculation */ struct bt_stream_callbacks *cb; /* Callbacks registered for iterator. */ + void *priv; }; static inline @@ -129,45 +131,41 @@ int ctf_fini_pos(struct ctf_stream_pos *pos); /* * move_pos - move position of a relative bit offset * + * Return 1 if OK, 0 if out-of-bound. + * * TODO: allow larger files by updating base too. */ static inline -void ctf_move_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +int ctf_move_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) { + uint64_t max_len; + printf_debug("ctf_move_pos test EOF: %" PRId64 "\n", pos->offset); if (unlikely(pos->offset == EOF)) - return; - - if (pos->fd >= 0) { - /* - * PROT_READ ctf_packet_seek is called from within - * ctf_pos_get_event so end of packet does not change - * the packet context on for the last event of the - * packet. - */ - if ((pos->prot == PROT_WRITE) - && (unlikely(pos->offset + bit_offset >= pos->packet_size))) { - printf_debug("ctf_packet_seek (before call): %" PRId64 "\n", - pos->offset); - ctf_packet_seek(&pos->parent, 0, SEEK_CUR); - printf_debug("ctf_packet_seek (after call): %" PRId64 "\n", - pos->offset); - return; - } - } + return 0; + if (pos->prot == PROT_READ) + max_len = pos->content_size; + else + max_len = pos->packet_size; + if (unlikely(pos->offset + bit_offset > max_len)) + return 0; + pos->offset += bit_offset; printf_debug("ctf_move_pos after increment: %" PRId64 "\n", pos->offset); + return 1; } /* * align_pos - align position on a bit offset (> 0) * + * Return 1 if OK, 0 if out-of-bound. + * * TODO: allow larger files by updating base too. */ static inline -void ctf_align_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) +int ctf_align_pos(struct ctf_stream_pos *pos, uint64_t bit_offset) { - ctf_move_pos(pos, offset_align(pos->offset, bit_offset)); + return ctf_move_pos(pos, offset_align(pos->offset, bit_offset)); } static inline @@ -202,21 +200,27 @@ int ctf_pos_packet(struct ctf_stream_pos *dummy) static inline void ctf_pos_pad_packet(struct ctf_stream_pos *pos) { - ctf_move_pos(pos, pos->packet_size - pos->offset); + ctf_packet_seek(&pos->parent, 0, SEEK_CUR); } static inline int ctf_pos_access_ok(struct ctf_stream_pos *pos, uint64_t bit_len) { + uint64_t max_len; + if (unlikely(pos->offset == EOF)) return 0; - if (unlikely(pos->offset + bit_len > pos->packet_size)) + if (pos->prot == PROT_READ) + max_len = pos->content_size; + else + max_len = pos->packet_size; + if (unlikely(pos->offset + bit_len > max_len)) return 0; return 1; } /* - * Update the stream position for to the current event. This moves to + * Update the stream position to the current event. This moves to * the next packet if we are located at the end of the current packet. */ static inline diff --git a/lib/babeltrace/format.h b/lib/babeltrace/format.h index 07e854f..dea8e0e 100644 --- a/lib/babeltrace/format.h +++ b/lib/babeltrace/format.h @@ -49,6 +49,7 @@ struct bt_trace_descriptor; struct bt_mmap_stream { int fd; struct bt_list_head list; + void *priv; }; struct bt_mmap_stream_list { diff --git a/lib/babeltrace/iterator.h b/lib/babeltrace/iterator.h index 50232a9..5c3939c 100644 --- a/lib/babeltrace/iterator.h +++ b/lib/babeltrace/iterator.h @@ -35,6 +35,7 @@ extern "C" { /* Flags for the iterator read_event */ enum { BT_ITER_FLAG_LOST_EVENTS = (1 << 0), + BT_ITER_FLAG_RETRY = (1 << 1), }; /* Forward declarations */ diff --git a/lib/babeltrace/types.h b/lib/babeltrace/types.h index 8d660be..677818b 100644 --- a/lib/babeltrace/types.h +++ b/lib/babeltrace/types.h @@ -435,6 +435,10 @@ struct declaration_string * char *bt_get_string(const struct bt_definition *field); enum ctf_string_encoding bt_get_string_encoding(const struct bt_definition *field); +double bt_get_float(const struct bt_definition *field); + +const struct bt_definition *bt_get_variant_field(struct bt_definition *definition); + struct declaration_struct * bt_struct_declaration_new(struct declaration_scope *parent_scope, uint64_t min_align); @@ -453,10 +457,10 @@ struct declaration_field * bt_struct_declaration_get_field_from_index(struct declaration_struct *struct_declaration, int index); struct bt_definition * -bt_struct_definition_get_field_from_index(struct definition_struct *struct_definition, +bt_struct_definition_get_field_from_index(const struct definition_struct *struct_definition, int index); int bt_struct_rw(struct bt_stream_pos *pos, struct bt_definition *definition); -uint64_t bt_struct_declaration_len(struct declaration_struct *struct_declaration); +uint64_t bt_struct_declaration_len(const struct declaration_struct *struct_declaration); /* * The tag enumeration is validated to ensure that it contains only mappings diff --git a/src/Makefile.am b/src/Makefile.am index 6d60e64..f199ca1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,10 @@ AM_CFLAGS = $(PACKAGE_CFLAGS) -I$(top_srcdir)/lib -DBABELTRACE_HAVE_LIBUUID +lib_LTLIBRARIES = libbabeltrace-lttng-live.la + +libbabeltrace_lttng_live_la_SOURCES = \ + network-live.c lttng-live-functions.c + bin_PROGRAMS = lttngtop noinst_HEADERS = \ @@ -9,7 +14,9 @@ noinst_HEADERS = \ cursesdisplay.h \ iostreamtop.h \ mmap-live.h \ - network-live.h + network-live.h \ + lttng-live-functions.h \ + lttngtop.h lttngtop_SOURCES = \ lttngtop.c \ @@ -17,8 +24,11 @@ lttngtop_SOURCES = \ cursesdisplay.c \ cputop.c \ iostreamtop.c \ - mmap-live.c \ - network-live.c + mmap-live.c + +lttngtop_LDFLAGS = -Wl,--no-as-needed #lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttngtop-helper -llttng-ctl -lurcu -llttngtopmmappacketseek -llttng-ust-ctl -lcurses -lpanel -lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttng-ctl -lurcu -llttng-ust-ctl -lcurses -lpanel +lttngtop_LDADD = -lbabeltrace -lbabeltrace-ctf -llttng-ctl -lurcu -llttng-ust-ctl -lcurses -lpanel \ + $(top_builddir)/src/libbabeltrace-lttng-live.la + diff --git a/src/lttng-live-functions.c b/src/lttng-live-functions.c new file mode 100644 index 0000000..67e7aba --- /dev/null +++ b/src/lttng-live-functions.c @@ -0,0 +1,1013 @@ +/* + * Copyright (C) 2013 - Julien Desfossez + * Mathieu Desnoyers + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* for packet_index */ +#include + +#include +#include +#include +/* +#include +replaced with +*/ +#include "network-live.h" + +#include "lttng-live-functions.h" +#include "lttng-viewer.h" +#include "lttngtop.h" + +/* + * Memory allocation zeroed + */ +#define zmalloc(x) calloc(1, x) + +#ifndef max_t +#define max_t(type, a, b) \ + ((type) (a) > (type) (b) ? (type) (a) : (type) (b)) +#endif + +int lttng_live_connect_viewer(struct lttng_live_ctx *ctx, char *hostname, + int port) +{ + struct hostent *host; + struct sockaddr_in server_addr; + int ret; + + host = gethostbyname(hostname); + if (!host) { + ret = -1; + goto end; + } + + if ((ctx->control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + perror("Socket"); + ret = -1; + goto end; + } + + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(port); + server_addr.sin_addr = *((struct in_addr *) host->h_addr); + bzero(&(server_addr.sin_zero), 8); + + if (connect(ctx->control_sock, (struct sockaddr *) &server_addr, + sizeof(struct sockaddr)) == -1) { + perror("Connect"); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + +int lttng_live_establish_connection(struct lttng_live_ctx *ctx) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_connect connect; + int ret; + ssize_t ret_len; + + cmd.cmd = htobe32(LTTNG_VIEWER_CONNECT); + cmd.data_size = sizeof(connect); + cmd.cmd_version = 0; + + connect.viewer_session_id = -1ULL; /* will be set on recv */ + connect.major = htobe32(LTTNG_LIVE_MAJOR); + connect.minor = htobe32(LTTNG_LIVE_MINOR); + connect.type = htobe32(LTTNG_VIEWER_CLIENT_COMMAND); + + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = send(ctx->control_sock, &connect, sizeof(connect), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending version\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(connect)); + + do { + ret_len = recv(ctx->control_sock, &connect, sizeof(connect), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving version\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(connect)); + + printf_verbose("Received viewer session ID : %" PRIu64 "\n", + be64toh(connect.viewer_session_id)); + printf_verbose("Relayd version : %u.%u\n", be32toh(connect.major), + be32toh(connect.minor)); + + ret = 0; + +error: + return ret; +} + +int lttng_live_list_sessions(struct lttng_live_ctx *ctx, const char *path) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_list_sessions list; + struct lttng_viewer_session lsession; + int i, ret; + ssize_t ret_len; + int sessions_count; + + cmd.cmd = htobe32(LTTNG_VIEWER_LIST_SESSIONS); + cmd.data_size = 0; + cmd.cmd_version = 0; + + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = recv(ctx->control_sock, &list, sizeof(list), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving session list\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(list)); + + sessions_count = be32toh(list.sessions_count); + fprintf(stdout, "%u active session(s)%c\n", sessions_count, + sessions_count > 0 ? ':' : ' '); + for (i = 0; i < sessions_count; i++) { + do { + ret_len = recv(ctx->control_sock, &lsession, sizeof(lsession), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving session\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(lsession)); + lsession.hostname[LTTNG_VIEWER_HOST_NAME_MAX - 1] = '\0'; + lsession.session_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0'; + + fprintf(stdout, "%s/%" PRIu64 " : %s on host %s (timer = %u, " + "%u stream(s), %u client(s) connected)\n", + path, be64toh(lsession.id), + lsession.session_name, lsession.hostname, + be32toh(lsession.live_timer), + be32toh(lsession.streams), + be32toh(lsession.clients)); + } + + ret = 0; + +error: + return ret; +} + +int lttng_live_ctf_trace_assign(struct lttng_live_viewer_stream *stream, + uint64_t ctf_trace_id) +{ + struct lttng_live_ctf_trace *trace; + int ret = 0; + + trace = g_hash_table_lookup(stream->session->ctf_traces, + (gpointer) ctf_trace_id); + if (!trace) { + trace = g_new0(struct lttng_live_ctf_trace, 1); + trace->ctf_trace_id = ctf_trace_id; + trace->streams = g_ptr_array_new(); + g_hash_table_insert(stream->session->ctf_traces, + (gpointer) ctf_trace_id, + trace); + } + if (stream->metadata_flag) + trace->metadata_stream = stream; + + stream->ctf_trace = trace; + g_ptr_array_add(trace->streams, stream); + + return ret; +} + +int lttng_live_attach_session(struct lttng_live_ctx *ctx, uint64_t id) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_attach_session_request rq; + struct lttng_viewer_attach_session_response rp; + struct lttng_viewer_stream stream; + int ret, i; + ssize_t ret_len; + + cmd.cmd = htobe32(LTTNG_VIEWER_ATTACH_SESSION); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + memset(&rq, 0, sizeof(rq)); + rq.session_id = htobe64(id); + // TODO: add cmd line parameter to select seek beginning + // rq.seek = htobe32(LTTNG_VIEWER_SEEK_BEGINNING); + rq.seek = htobe32(LTTNG_VIEWER_SEEK_LAST); + + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = send(ctx->control_sock, &rq, sizeof(rq), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending attach request\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rq)); + + do { + ret_len = recv(ctx->control_sock, &rp, sizeof(rp), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving attach response\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rp)); + + switch(be32toh(rp.status)) { + case LTTNG_VIEWER_ATTACH_OK: + break; + case LTTNG_VIEWER_ATTACH_UNK: + ret = -LTTNG_VIEWER_ATTACH_UNK; + goto end; + case LTTNG_VIEWER_ATTACH_ALREADY: + fprintf(stderr, "[error] Already a viewer attached\n"); + ret = -1; + goto end; + case LTTNG_VIEWER_ATTACH_NOT_LIVE: + fprintf(stderr, "[error] Not a live session\n"); + ret = -1; + goto end; + case LTTNG_VIEWER_ATTACH_SEEK_ERR: + fprintf(stderr, "[error] Wrong seek parameter\n"); + ret = -1; + goto end; + default: + fprintf(stderr, "[error] Unknown attach return code %u\n", + be32toh(rp.status)); + ret = -1; + goto end; + } + if (be32toh(rp.status) != LTTNG_VIEWER_ATTACH_OK) { + ret = -1; + goto end; + } + + ctx->session->stream_count = be32toh(rp.streams_count); + /* + * When the session is created but not started, we do an active wait + * until it starts. It allows the viewer to start processing the trace + * as soon as the session starts. + */ + if (ctx->session->stream_count == 0) { + ret = 0; + goto end; + } + printf_verbose("Waiting for %" PRIu64 " streams:\n", + ctx->session->stream_count); + ctx->session->streams = g_new0(struct lttng_live_viewer_stream, + ctx->session->stream_count); + for (i = 0; i < be32toh(rp.streams_count); i++) { + do { + ret_len = recv(ctx->control_sock, &stream, sizeof(stream), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving stream\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(stream)); + stream.path_name[LTTNG_VIEWER_PATH_MAX - 1] = '\0'; + stream.channel_name[LTTNG_VIEWER_NAME_MAX - 1] = '\0'; + + printf_verbose(" stream %" PRIu64 " : %s/%s\n", + be64toh(stream.id), stream.path_name, + stream.channel_name); + ctx->session->streams[i].id = be64toh(stream.id); + ctx->session->streams[i].session = ctx->session; + + ctx->session->streams[i].first_read = 1; + ctx->session->streams[i].mmap_size = 0; + + if (be32toh(stream.metadata_flag)) { + char *path; + + path = strdup(LTTNG_METADATA_PATH_TEMPLATE); + if (!path) { + perror("strdup"); + ret = -1; + goto error; + } + if (!mkdtemp(path)) { + perror("mkdtemp"); + free(path); + ret = -1; + goto error; + } + ctx->session->streams[i].metadata_flag = 1; + snprintf(ctx->session->streams[i].path, + sizeof(ctx->session->streams[i].path), + "%s/%s", path, + stream.channel_name); + ret = open(ctx->session->streams[i].path, + O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (ret < 0) { + perror("open"); + free(path); + goto error; + } + ctx->session->streams[i].fd = ret; + free(path); + } + ret = lttng_live_ctf_trace_assign(&ctx->session->streams[i], + be64toh(stream.ctf_trace_id)); + if (ret < 0) { + goto error; + } + + } + ret = 0; + +end: +error: + return ret; +} + +static +int get_data_packet(struct lttng_live_ctx *ctx, + struct ctf_stream_pos *pos, + struct lttng_live_viewer_stream *stream, uint64_t offset, + uint64_t len) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_packet rq; + struct lttng_viewer_trace_packet rp; + ssize_t ret_len; + int ret; + + cmd.cmd = htobe32(LTTNG_VIEWER_GET_PACKET); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + memset(&rq, 0, sizeof(rq)); + rq.stream_id = htobe64(stream->id); + /* Already in big endian. */ + rq.offset = offset; + rq.len = htobe32(len); + + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = send(ctx->control_sock, &rq, sizeof(rq), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending get_data_packet request\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rq)); + + do { + ret_len = recv(ctx->control_sock, &rp, sizeof(rp), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving data response\n"); + ret = ret_len; + goto error; + } + if (ret_len != sizeof(rp)) { + fprintf(stderr, "[error] get_data_packet: expected %" PRId64 + ", received %" PRId64 "\n", ret_len, + sizeof(rp)); + ret = -1; + goto error; + } + + rp.flags = be32toh(rp.flags); + + switch (be32toh(rp.status)) { + case LTTNG_VIEWER_GET_PACKET_OK: + len = be32toh(rp.len); + printf_verbose("get_data_packet: Ok, packet size : %" PRIu64 + "\n", len); + break; + case LTTNG_VIEWER_GET_PACKET_RETRY: + printf_verbose("get_data_packet: retry\n"); + ret = -1; + goto end; + case LTTNG_VIEWER_GET_PACKET_ERR: + if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { + printf_verbose("get_data_packet: new metadata needed\n"); + ret = 0; + goto end; + } + fprintf(stderr, "[error] get_data_packet: error\n"); + ret = -1; + goto end; + case LTTNG_VIEWER_GET_PACKET_EOF: + ret = -2; + goto error; + default: + printf_verbose("get_data_packet: unknown\n"); + assert(0); + ret = -1; + goto end; + } + + if (len <= 0) { + ret = -1; + goto end; + } + + if (len > stream->mmap_size) { + uint64_t new_size; + + new_size = max_t(uint64_t, len, stream->mmap_size << 1); + if (pos->base_mma) { + /* unmap old base */ + ret = munmap_align(pos->base_mma); + if (ret) { + fprintf(stderr, "[error] Unable to unmap old base: %s.\n", + strerror(errno)); + ret = -1; + goto error; + } + pos->base_mma = NULL; + } + pos->base_mma = mmap_align(new_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (pos->base_mma == MAP_FAILED) { + fprintf(stderr, "[error] mmap error %s.\n", + strerror(errno)); + pos->base_mma = NULL; + ret = -1; + goto error; + } + + stream->mmap_size = new_size; + printf_verbose("Expanding stream mmap size to %" PRIu64 " bytes\n", + stream->mmap_size); + } + + do { + ret_len = recv(ctx->control_sock, + mmap_align_addr(pos->base_mma), len, + MSG_WAITALL); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving trace packet\n"); + ret = ret_len; + goto error; + } + assert(ret_len == len); + +end: +error: + return ret; +} + +/* + * Return number of metadata bytes written or a negative value on error. + */ +static +int get_new_metadata(struct lttng_live_ctx *ctx, + struct lttng_live_viewer_stream *viewer_stream, + uint64_t *metadata_len) +{ + uint64_t len = 0; + int ret; + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_metadata rq; + struct lttng_viewer_metadata_packet rp; + struct lttng_live_viewer_stream *metadata_stream; + char *data = NULL; + ssize_t ret_len; + + cmd.cmd = htobe32(LTTNG_VIEWER_GET_METADATA); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + metadata_stream = viewer_stream->ctf_trace->metadata_stream; + rq.stream_id = htobe64(metadata_stream->id); + + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = send(ctx->control_sock, &rq, sizeof(rq), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending get_metadata request\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rq)); + + do { + ret_len = recv(ctx->control_sock, &rp, sizeof(rp), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving metadata response\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rp)); + + switch (be32toh(rp.status)) { + case LTTNG_VIEWER_METADATA_OK: + printf_verbose("get_metadata : OK\n"); + break; + case LTTNG_VIEWER_NO_NEW_METADATA: + printf_verbose("get_metadata : NO NEW\n"); + ret = -1; + goto end; + case LTTNG_VIEWER_METADATA_ERR: + printf_verbose("get_metadata : ERR\n"); + ret = -1; + goto end; + default: + printf_verbose("get_metadata : UNKNOWN\n"); + ret = -1; + goto end; + } + + len = be64toh(rp.len); + printf_verbose("Writing %" PRIu64" bytes to metadata\n", len); + if (len <= 0) { + ret = -1; + goto end; + } + + data = zmalloc(len); + if (!data) { + perror("relay data zmalloc"); + ret = -1; + goto error; + } + do { + ret_len = recv(ctx->control_sock, data, len, MSG_WAITALL); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving trace packet\n"); + ret = ret_len; + free(data); + goto error; + } + assert(ret_len == len); + + do { + ret_len = write(metadata_stream->fd, data, len); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + free(data); + ret = ret_len; + goto error; + } + assert(ret_len == len); + + free(data); + + *metadata_len = len; + ret = 0; +end: +error: + return ret; +} + +/* + * Get one index for a stream. + * + * Returns 0 on success or a negative value on error. + */ +static +int get_next_index(struct lttng_live_ctx *ctx, + struct lttng_live_viewer_stream *viewer_stream, + struct packet_index *index) +{ + struct lttng_viewer_cmd cmd; + struct lttng_viewer_get_next_index rq; + struct lttng_viewer_index rp; + int ret; + uint64_t metadata_len; + ssize_t ret_len; + + cmd.cmd = htobe32(LTTNG_VIEWER_GET_NEXT_INDEX); + cmd.data_size = sizeof(rq); + cmd.cmd_version = 0; + + memset(&rq, 0, sizeof(rq)); + rq.stream_id = htobe64(viewer_stream->id); + +retry: + do { + ret_len = send(ctx->control_sock, &cmd, sizeof(cmd), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending cmd\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(cmd)); + + do { + ret_len = send(ctx->control_sock, &rq, sizeof(rq), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error sending get_next_index request\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rq)); + + do { + ret_len = recv(ctx->control_sock, &rp, sizeof(rp), 0); + } while (ret_len < 0 && errno == EINTR); + if (ret_len < 0) { + fprintf(stderr, "[error] Error receiving index response\n"); + ret = ret_len; + goto error; + } + assert(ret_len == sizeof(rp)); + + rp.flags = be32toh(rp.flags); + + switch (be32toh(rp.status)) { + case LTTNG_VIEWER_INDEX_INACTIVE: + printf_verbose("get_next_index: inactive\n"); + memset(index, 0, sizeof(struct packet_index)); + index->timestamp_end = be64toh(rp.timestamp_end); + break; + case LTTNG_VIEWER_INDEX_OK: + printf_verbose("get_next_index: Ok, need metadata update : %u\n", + rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA); + index->offset = be64toh(rp.offset); + index->packet_size = be64toh(rp.packet_size); + index->content_size = be64toh(rp.content_size); + index->timestamp_begin = be64toh(rp.timestamp_begin); + index->timestamp_end = be64toh(rp.timestamp_end); + index->events_discarded = be64toh(rp.events_discarded); + + if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { + printf_verbose("get_next_index: new metadata needed\n"); + ret = get_new_metadata(ctx, viewer_stream, + &metadata_len); + if (ret < 0) { + goto error; + } + } + break; + case LTTNG_VIEWER_INDEX_RETRY: + printf_verbose("get_next_index: retry\n"); + sleep(1); + goto retry; + case LTTNG_VIEWER_INDEX_HUP: + printf_verbose("get_next_index: stream hung up\n"); + viewer_stream->id = -1ULL; + viewer_stream->fd = -1; + index->offset = EOF; + break; + case LTTNG_VIEWER_INDEX_ERR: + fprintf(stderr, "[error] get_next_index: error\n"); + ret = -1; + goto error; + default: + fprintf(stderr, "[error] get_next_index: unkwown value\n"); + ret = -1; + goto error; + } + + ret = 0; + +error: + return ret; +} + +void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, + int whence) +{ + struct ctf_stream_pos *pos; + struct ctf_file_stream *file_stream; + struct packet_index packet_index; + struct lttng_live_viewer_stream *viewer_stream; + struct lttng_live_session *session; + int ret; + +retry: + pos = ctf_pos(stream_pos); + file_stream = container_of(pos, struct ctf_file_stream, pos); + viewer_stream = (struct lttng_live_viewer_stream *) pos->priv; + session = viewer_stream->session; + + printf_verbose("get_next_index for stream %" PRIu64 "\n", viewer_stream->id); + ret = get_next_index(session->ctx, viewer_stream, &packet_index); + if (ret < 0) { + pos->offset = EOF; + fprintf(stderr, "[error] get_next_index failed\n"); + return; + } + + pos->packet_size = packet_index.packet_size; + pos->content_size = packet_index.content_size; + pos->mmap_base_offset = 0; + if (packet_index.offset == EOF) { + pos->offset = EOF; + } else { + pos->offset = 0; + } + + if (packet_index.content_size == 0) { + file_stream->parent.cycles_timestamp = packet_index.timestamp_end; + file_stream->parent.real_timestamp = ctf_get_real_timestamp( + &file_stream->parent, packet_index.timestamp_end); + } else { + /* Append to the cycles_index. */ + g_array_append_val(file_stream->pos.packet_cycles_index, + packet_index); + /* Convert the timestamps and append to the real_index. */ + packet_index.timestamp_begin = ctf_get_real_timestamp( + &file_stream->parent, packet_index.timestamp_begin); + packet_index.timestamp_end = ctf_get_real_timestamp( + &file_stream->parent, packet_index.timestamp_end); + g_array_append_val(file_stream->pos.packet_real_index, + packet_index); + + compute_discarded_events(file_stream, pos); + + packet_index = g_array_index(pos->packet_cycles_index, + struct packet_index, pos->cur_index); + file_stream->parent.cycles_timestamp = packet_index.timestamp_begin; + + packet_index = g_array_index(pos->packet_real_index, + struct packet_index, pos->cur_index); + file_stream->parent.real_timestamp = packet_index.timestamp_begin; + ++pos->cur_index; + } + + if (pos->packet_size == 0 || pos->offset == EOF) { + goto end; + } + + printf_verbose("get_data_packet for stream %" PRIu64 "\n", + viewer_stream->id); + ret = get_data_packet(session->ctx, pos, viewer_stream, + be64toh(packet_index.offset), + packet_index.packet_size / CHAR_BIT); + if (ret == -2) { + goto retry; + } else if (ret < 0) { + pos->offset = EOF; + fprintf(stderr, "[error] get_data_packet failed\n"); + return; + } + + printf_verbose("Index received : packet_size : %" PRIu64 + ", offset %" PRIu64 ", content_size %" PRIu64 + ", timestamp_end : %" PRIu64 "\n", + packet_index.packet_size, packet_index.offset, + packet_index.content_size, packet_index.timestamp_end); + + /* update trace_packet_header and stream_packet_context */ + if (pos->prot != PROT_WRITE && file_stream->parent.trace_packet_header) { + /* Read packet header */ + ret = generic_rw(&pos->parent, &file_stream->parent.trace_packet_header->p); + if (ret) { + pos->offset = EOF; + fprintf(stderr, "[error] trace packet header read failed\n"); + goto end; + } + } + if (pos->prot != PROT_WRITE && file_stream->parent.stream_packet_context) { + /* Read packet context */ + ret = generic_rw(&pos->parent, &file_stream->parent.stream_packet_context->p); + if (ret) { + pos->offset = EOF; + fprintf(stderr, "[error] stream packet context read failed\n"); + goto end; + } + } + pos->data_offset = pos->offset; + +end: + return; +} + +static int del_traces(gpointer key, gpointer value, gpointer user_data) +{ + struct bt_context *bt_ctx = user_data; + struct lttng_live_ctf_trace *trace = value; + int ret; + + ret = bt_context_remove_trace(bt_ctx, trace->trace_id); + if (ret < 0) + fprintf(stderr, "[error] removing trace from context\n"); + + /* remove the key/value pair from the HT. */ + return 1; +} + +static void add_traces(gpointer key, gpointer value, gpointer user_data) +{ + int i, ret, total_metadata = 0; + uint64_t metadata_len; + struct bt_context *bt_ctx = user_data; + struct lttng_live_ctf_trace *trace = value; + struct lttng_live_viewer_stream *stream; + struct bt_mmap_stream *new_mmap_stream; + struct bt_mmap_stream_list mmap_list; + struct lttng_live_ctx *ctx = NULL; + + BT_INIT_LIST_HEAD(&mmap_list.head); + + for (i = 0; i < trace->streams->len; i++) { + stream = g_ptr_array_index(trace->streams, i); + ctx = stream->session->ctx; + + if (!stream->metadata_flag) { + new_mmap_stream = zmalloc(sizeof(struct bt_mmap_stream)); + new_mmap_stream->priv = (void *) stream; + new_mmap_stream->fd = -1; + bt_list_add(&new_mmap_stream->list, &mmap_list.head); + } else { + /* Get all possible metadata before starting */ + do { + ret = get_new_metadata(ctx, stream, + &metadata_len); + if (ret == 0) { + total_metadata += metadata_len; + } + } while (ret == 0 || total_metadata == 0); + trace->metadata_fp = fopen(stream->path, "r"); + } + } + + if (!trace->metadata_fp) { + fprintf(stderr, "[error] No metadata stream opened\n"); + goto end_free; + } + + ret = bt_context_add_trace(bt_ctx, NULL, "ctf", + ctf_live_packet_seek, &mmap_list, trace->metadata_fp); + if (ret < 0) { + fprintf(stderr, "[error] Error adding trace\n"); + goto end_free; + } + trace->trace_id = ret; + + goto end; + +end_free: + bt_context_put(bt_ctx); +end: + return; +} + +void lttng_live_read(struct lttng_live_ctx *ctx, uint64_t session_id) +{ + int ret, active_session = 0; + struct bt_context *bt_ctx; + + bt_ctx = bt_context_create(); + if (!bt_ctx) { + fprintf(stderr, "[error] bt_context_create allocation\n"); + goto end; + } + + /* + * As long as the session is active, we try to reattach to it, + * even if all the streams get closed. + */ +// do { + do { + ret = lttng_live_attach_session(ctx, session_id); + printf_verbose("Attaching session returns %d\n", ret); + if (ret < 0) { + if (ret == -LTTNG_VIEWER_ATTACH_UNK) { + if (active_session) + goto end_free; + fprintf(stderr, "[error] Unknown " + "session ID\n"); + } + goto end_free; + } else { + active_session = 1; + } + } while (ctx->session->stream_count == 0); + + g_hash_table_foreach(ctx->session->ctf_traces, add_traces, bt_ctx); + + ret = check_requirements(bt_ctx); + if (ret < 0) { + fprintf(stderr, "[error] some mandatory contexts " + "were missing, exiting.\n"); + goto end; + } + + if (!opt_textdump) { + pthread_create(&display_thread, NULL, ncurses_display, + (void *) NULL); + pthread_create(&timer_thread, NULL, refresh_thread, + (void *) NULL); + } + + iter_trace(bt_ctx); + + g_hash_table_foreach_remove(ctx->session->ctf_traces, del_traces, bt_ctx); +// } while (active_session); + +end_free: + bt_context_put(bt_ctx); +end: + return; +} diff --git a/src/lttng-live-functions.h b/src/lttng-live-functions.h new file mode 100644 index 0000000..778540d --- /dev/null +++ b/src/lttng-live-functions.h @@ -0,0 +1,74 @@ +#ifndef _LTTNG_LIVE_FUNCTIONS_H +#define _LTTNG_LIVE_FUNCTIONS_H + +/* + * Copyright 2013 Julien Desfossez + * Mathieu Desnoyers + * + * 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 + +#define LTTNG_METADATA_PATH_TEMPLATE "/tmp/lttng-live-XXXXXX" +#define LTTNG_DEFAULT_NETWORK_VIEWER_PORT 5344 + +#define LTTNG_LIVE_MAJOR 2 +#define LTTNG_LIVE_MINOR 4 + +struct lttng_live_ctx { + int control_sock; + struct lttng_live_session *session; +}; + +struct lttng_live_viewer_stream { + uint64_t id; + uint64_t mmap_size; + int fd; + int metadata_flag; + int first_read; + struct lttng_live_session *session; + struct lttng_live_ctf_trace *ctf_trace; + char path[PATH_MAX]; +}; + +struct lttng_live_session { + uint64_t live_timer_interval; + uint64_t stream_count; + struct lttng_live_ctx *ctx; + struct lttng_live_viewer_stream *streams; + GHashTable *ctf_traces; +}; + +struct lttng_live_ctf_trace { + uint64_t ctf_trace_id; + struct lttng_live_viewer_stream *metadata_stream; + GPtrArray *streams; + FILE *metadata_fp; + int trace_id; +}; + +int lttng_live_connect_viewer(struct lttng_live_ctx *ctx, char *hostname, + int port); +int lttng_live_establish_connection(struct lttng_live_ctx *ctx); +int lttng_live_list_sessions(struct lttng_live_ctx *ctx, const char *path); +int lttng_live_attach_session(struct lttng_live_ctx *ctx, uint64_t id); +void lttng_live_read(struct lttng_live_ctx *ctx, uint64_t session_id); + +#endif /* _LTTNG_LIVE_FUNCTIONS_H */ diff --git a/src/lttng-viewer.h b/src/lttng-viewer.h index 1977a43..d424a97 100644 --- a/src/lttng-viewer.h +++ b/src/lttng-viewer.h @@ -32,60 +32,62 @@ #define LTTNG_VIEWER_HOST_NAME_MAX 64 /* Flags in reply to get_next_index and get_packet. */ -/* New metadata is required to read this packet. */ -#define LTTNG_VIEWER_FLAG_NEW_METADATA (1 << 0) -/* New stream got added to the trace. */ -#define LTTNG_VIEWER_FLAG_NEW_STREAM (1 << 1) +enum { + /* New metadata is required to read this packet. */ + LTTNG_VIEWER_FLAG_NEW_METADATA = (1 << 0), + /* New stream got added to the trace. */ + LTTNG_VIEWER_FLAG_NEW_STREAM = (1 << 1), +}; enum lttng_viewer_command { - VIEWER_CONNECT = 1, - VIEWER_LIST_SESSIONS = 2, - VIEWER_ATTACH_SESSION = 3, - VIEWER_GET_NEXT_INDEX = 4, - VIEWER_GET_PACKET = 5, - VIEWER_GET_METADATA = 6, + LTTNG_VIEWER_CONNECT = 1, + LTTNG_VIEWER_LIST_SESSIONS = 2, + LTTNG_VIEWER_ATTACH_SESSION = 3, + LTTNG_VIEWER_GET_NEXT_INDEX = 4, + LTTNG_VIEWER_GET_PACKET = 5, + LTTNG_VIEWER_GET_METADATA = 6, }; enum lttng_viewer_attach_return_code { - VIEWER_ATTACH_OK = 1, /* If the attach command succeeded. */ - VIEWER_ATTACH_ALREADY = 2, /* If a viewer is already attached. */ - VIEWER_ATTACH_UNK = 3, /* If the session ID is unknown. */ - VIEWER_ATTACH_NOT_LIVE = 4, /* If the session is not live. */ - VIEWER_ATTACH_SEEK_ERR = 5, /* Seek error. */ + LTTNG_VIEWER_ATTACH_OK = 1, /* The attach command succeeded. */ + LTTNG_VIEWER_ATTACH_ALREADY = 2, /* A viewer is already attached. */ + LTTNG_VIEWER_ATTACH_UNK = 3, /* The session ID is unknown. */ + LTTNG_VIEWER_ATTACH_NOT_LIVE = 4, /* The session is not live. */ + LTTNG_VIEWER_ATTACH_SEEK_ERR = 5, /* Seek error. */ }; enum lttng_viewer_next_index_return_code { - VIEWER_INDEX_OK = 1, /* Index is available. */ - VIEWER_INDEX_RETRY = 2, /* Index not yet available. */ - VIEWER_INDEX_HUP = 3, /* Index closed (trace destroyed). */ - VIEWER_INDEX_ERR = 4, /* Unknow error. */ - VIEWER_INDEX_INACTIVE = 5, /* Inactive stream beacon. */ - VIEWER_INDEX_EOF = 6, /* End of index file. */ + LTTNG_VIEWER_INDEX_OK = 1, /* Index is available. */ + LTTNG_VIEWER_INDEX_RETRY = 2, /* Index not yet available. */ + LTTNG_VIEWER_INDEX_HUP = 3, /* Index closed (trace destroyed). */ + LTTNG_VIEWER_INDEX_ERR = 4, /* Unknow error. */ + LTTNG_VIEWER_INDEX_INACTIVE = 5, /* Inactive stream beacon. */ + LTTNG_VIEWER_INDEX_EOF = 6, /* End of index file. */ }; enum lttng_viewer_get_packet_return_code { - VIEWER_GET_PACKET_OK = 1, - VIEWER_GET_PACKET_RETRY = 2, - VIEWER_GET_PACKET_ERR = 3, - VIEWER_GET_PACKET_EOF = 4, + LTTNG_VIEWER_GET_PACKET_OK = 1, + LTTNG_VIEWER_GET_PACKET_RETRY = 2, + LTTNG_VIEWER_GET_PACKET_ERR = 3, + LTTNG_VIEWER_GET_PACKET_EOF = 4, }; enum lttng_viewer_get_metadata_return_code { - VIEWER_METADATA_OK = 1, - VIEWER_NO_NEW_METADATA = 2, - VIEWER_METADATA_ERR = 3, + LTTNG_VIEWER_METADATA_OK = 1, + LTTNG_VIEWER_NO_NEW_METADATA = 2, + LTTNG_VIEWER_METADATA_ERR = 3, }; enum lttng_viewer_connection_type { - VIEWER_CLIENT_COMMAND = 1, - VIEWER_CLIENT_NOTIFICATION = 2, + LTTNG_VIEWER_CLIENT_COMMAND = 1, + LTTNG_VIEWER_CLIENT_NOTIFICATION = 2, }; enum lttng_viewer_seek { /* Receive the trace packets from the beginning. */ - VIEWER_SEEK_BEGINNING = 1, + LTTNG_VIEWER_SEEK_BEGINNING = 1, /* Receive the trace packets from now. */ - VIEWER_SEEK_LAST = 2, + LTTNG_VIEWER_SEEK_LAST = 2, }; struct lttng_viewer_session { @@ -112,26 +114,26 @@ struct lttng_viewer_cmd { } __attribute__((__packed__)); /* - * CONNECT payload. + * LTTNG_VIEWER_CONNECT payload. */ struct lttng_viewer_connect { /* session ID assigned by the relay for command connections */ uint64_t viewer_session_id; uint32_t major; uint32_t minor; - uint32_t type; /* enum lttng_viewer_connection_type */ + uint32_t type; /* enum lttng_viewer_connection_type */ } __attribute__((__packed__)); /* - * VIEWER_LIST_SESSIONS payload. + * LTTNG_VIEWER_LIST_SESSIONS payload. */ struct lttng_viewer_list_sessions { uint32_t sessions_count; - char session_list[]; /* struct lttng_viewer_session */ + char session_list[]; /* struct lttng_viewer_session */ } __attribute__((__packed__)); /* - * VIEWER_ATTACH_SESSION payload. + * LTTNG_VIEWER_ATTACH_SESSION payload. */ struct lttng_viewer_attach_session_request { uint64_t session_id; @@ -148,7 +150,7 @@ struct lttng_viewer_attach_session_response { } __attribute__((__packed__)); /* - * VIEWER_GET_NEXT_INDEX payload. + * LTTNG_VIEWER_GET_NEXT_INDEX payload. */ struct lttng_viewer_get_next_index { uint64_t stream_id; @@ -162,13 +164,12 @@ struct lttng_viewer_index { uint64_t timestamp_end; uint64_t events_discarded; uint64_t stream_id; - /* enum lttng_viewer_next_index_return_code */ - uint32_t status; - uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ + uint32_t status; /* enum lttng_viewer_next_index_return_code */ + uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ } __attribute__ ((__packed__)); /* - * VIEWER_GET_PACKET payload. + * LTTNG_VIEWER_GET_PACKET payload. */ struct lttng_viewer_get_packet { uint64_t stream_id; @@ -177,15 +178,14 @@ struct lttng_viewer_get_packet { } __attribute__((__packed__)); struct lttng_viewer_trace_packet { - /* enum lttng_viewer_get_packet_return_code */ - uint32_t status; + uint32_t status; /* enum lttng_viewer_get_packet_return_code */ uint32_t len; - uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ + uint32_t flags; /* LTTNG_VIEWER_FLAG_* */ char data[]; } __attribute__((__packed__)); /* - * VIEWER_GET_METADATA payload. + * LTTNG_VIEWER_GET_METADATA payload. */ struct lttng_viewer_get_metadata { uint64_t stream_id; @@ -193,8 +193,7 @@ struct lttng_viewer_get_metadata { struct lttng_viewer_metadata_packet { uint64_t len; - /* enum lttng_viewer_get_metadata_return_code */ - uint32_t status; + uint32_t status; /* enum lttng_viewer_get_metadata_return_code */ char data[]; } __attribute__((__packed__)); diff --git a/src/lttngtop.c b/src/lttngtop.c index ec8839c..374f3e9 100644 --- a/src/lttngtop.c +++ b/src/lttngtop.c @@ -52,14 +52,16 @@ #include "common.h" #include "network-live.h" -#include "ctf-index.h" +#define NET_URL_PREFIX "net://" +#define NET4_URL_PREFIX "net4://" +#define NET6_URL_PREFIX "net6://" #define DEFAULT_FILE_ARRAY_SIZE 1 const char *opt_input_path; -static int opt_textdump; -static int opt_child; -static int opt_begin; +int opt_textdump; +int opt_child; +int opt_begin; int quit = 0; @@ -831,6 +833,19 @@ int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path, char * const paths[2] = { lpath, NULL }; int ret = -1; + if ((strncmp(path, NET4_URL_PREFIX, sizeof(NET4_URL_PREFIX) - 1)) == 0 || + (strncmp(path, NET6_URL_PREFIX, sizeof(NET6_URL_PREFIX) - 1)) == 0 || + (strncmp(path, NET_URL_PREFIX, sizeof(NET_URL_PREFIX) - 1)) == 0) { + ret = bt_context_add_trace(ctx, + path, format_str, packet_seek, NULL, NULL); + if (ret < 0) { + fprintf(stderr, "[warning] [Context] cannot open trace \"%s\" " + "for reading.\n", path); + /* Allow to skip erroneous traces. */ + ret = 1; /* partial error */ + } + return ret; + } /* * Need to copy path, because fts_open can change it. * It is the pointer array, not the strings, that are constant. @@ -1047,6 +1062,7 @@ int main(int argc, char **argv) #endif /* LTTNGTOP_MMAP_LIVE */ } else if (!opt_input_path && remote_live) { /* network live */ +#if 0 ret = setup_network_live(opt_relay_hostname, opt_begin); if (ret < 0) { goto end; @@ -1056,6 +1072,15 @@ int main(int argc, char **argv) if (ret < 0) { goto end; } +#endif + + bt_ctx = bt_context_create(); + ret = bt_context_add_traces_recursive(bt_ctx, opt_relay_hostname, + "lttng-live", NULL); + if (ret < 0) { + fprintf(stderr, "[error] Opening the trace\n"); + goto end; + } } else { //init_lttngtop(); @@ -1065,19 +1090,24 @@ int main(int argc, char **argv) fprintf(stderr, "[error] Opening the trace\n"); goto end; } - } - ret = check_requirements(bt_ctx); - if (ret < 0) { - fprintf(stderr, "[error] some mandatory contexts were missing, exiting.\n"); - goto end; - } - if (!opt_textdump) { - pthread_create(&display_thread, NULL, ncurses_display, (void *) NULL); - pthread_create(&timer_thread, NULL, refresh_thread, (void *) NULL); + ret = check_requirements(bt_ctx); + if (ret < 0) { + fprintf(stderr, "[error] some mandatory contexts " + "were missing, exiting.\n"); + goto end; + } + + if (!opt_textdump) { + pthread_create(&display_thread, NULL, ncurses_display, + (void *) NULL); + pthread_create(&timer_thread, NULL, refresh_thread, + (void *) NULL); + } + + iter_trace(bt_ctx); } - iter_trace(bt_ctx); pthread_join(display_thread, NULL); quit = 1; diff --git a/src/lttngtop.h b/src/lttngtop.h new file mode 100644 index 0000000..526bfdc --- /dev/null +++ b/src/lttngtop.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 Julien Desfossez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef LTTNGTOP_H +#define LTTNGTOP_H + +int check_requirements(struct bt_context *ctx); +extern int opt_textdump; +extern int opt_child; +extern int opt_begin; + +extern pthread_t display_thread; +extern pthread_t timer_thread; +void *ncurses_display(void *p); +void *refresh_thread(void *p); +void iter_trace(struct bt_context *bt_ctx); + +#endif /* LTTNGTOP_H */ diff --git a/src/network-live.c b/src/network-live.c index 46a5b4d..31c1354 100644 --- a/src/network-live.c +++ b/src/network-live.c @@ -35,8 +35,8 @@ #include #include "lttng-viewer.h" -#include "ctf-index.h" #include "network-live.h" +#include "lttng-live-functions.h" #include #include @@ -49,793 +49,200 @@ #include #include #include +#include /* - * Memory allocation zeroed + * hostname parameter needs to hold NAME_MAX chars. */ -#define zmalloc(x) calloc(1, x) -/* FIXME : completely arbitrary */ -#define mmap_size 524288 - -static int control_sock; -struct live_session *session; - -struct viewer_stream { - uint64_t id; - uint64_t ctf_trace_id; - void *mmap_base; - int fd; - int metadata_flag; - int first_read; - char path[PATH_MAX]; -}; - -struct live_session { - struct viewer_stream *streams; - uint64_t live_timer_interval; - uint64_t stream_count; -}; - -static -int connect_viewer(char *hostname) +static int parse_url(const char *path, char *hostname, int *port, + uint64_t *session_id) { - struct hostent *host; - struct sockaddr_in server_addr; - int ret; + char remain[2][NAME_MAX]; + int ret = -1, proto, proto_offset = 0; + size_t path_len = strlen(path); - host = gethostbyname(hostname); - if (!host) { - ret = -1; + /* + * Since sscanf API does not allow easily checking string length + * against a size defined by a macro. Test it beforehand on the + * input. We know the output is always <= than the input length. + */ + if (path_len > NAME_MAX) { goto end; } - - if ((control_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { - perror("Socket"); - ret = -1; - goto end; + ret = sscanf(path, "net%d://", &proto); + if (ret < 1) { + proto = 4; + /* net:// */ + proto_offset = strlen("net://"); + } else { + /* net4:// or net6:// */ + proto_offset = strlen("netX://"); } - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(5344); - server_addr.sin_addr = *((struct in_addr *) host->h_addr); - bzero(&(server_addr.sin_zero), 8); - - if (connect(control_sock, (struct sockaddr *) &server_addr, - sizeof(struct sockaddr)) == -1) { - perror("Connect"); - ret = -1; + if (proto_offset > path_len) { goto end; } + /* TODO : parse for IPv6 as well */ + /* Parse the hostname or IP */ + ret = sscanf(&path[proto_offset], "%[a-zA-Z.0-9%-]%s", + hostname, remain[0]); + if (ret == 2) { + /* Optional port number */ + switch (remain[0][0]) { + case ':': + ret = sscanf(remain[0], ":%d%s", port, remain[1]); + /* Optional session ID with port number */ + if (ret == 2) { + ret = sscanf(remain[1], "/%" PRIu64, + session_id); + /* Accept 0 or 1 (optional) */ + if (ret < 0) { + goto end; + } + } + break; + case '/': + /* Optional session ID */ + ret = sscanf(remain[0], "/%" PRIu64, session_id); + /* Accept 0 or 1 (optional) */ + if (ret < 0) { + goto end; + } + break; + default: + fprintf(stderr, "[error] wrong delimitor : %c\n", + remain[0][0]); + ret = -1; + goto end; + } + } - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(5345); - server_addr.sin_addr = *((struct in_addr *) host->h_addr); - bzero(&(server_addr.sin_zero), 8); + if (*port < 0) + *port = LTTNG_DEFAULT_NETWORK_VIEWER_PORT; + if (*session_id == -1ULL) + printf_verbose("Connecting to hostname : %s, port : %d, " + "proto : IPv%d\n", + hostname, *port, proto); + else + printf_verbose("Connecting to hostname : %s, port : %d, " + "session id : %" PRIu64 ", proto : IPv%d\n", + hostname, *port, *session_id, proto); ret = 0; end: return ret; } -static -int establish_connection(void) +static int lttng_live_open_trace_read(const char *path) { - struct lttng_viewer_cmd cmd; - struct lttng_viewer_connect connect; - int ret; + char hostname[NAME_MAX]; + int port = -1; + uint64_t session_id = -1ULL; + int ret = 0; + struct lttng_live_ctx ctx; - cmd.cmd = htobe32(VIEWER_CONNECT); - cmd.data_size = sizeof(connect); - cmd.cmd_version = 0; + ctx.session = g_new0(struct lttng_live_session, 1); - connect.major = htobe32(2); - connect.minor = htobe32(4); - connect.type = htobe32(VIEWER_CLIENT_COMMAND); + /* We need a pointer to the context from the packet_seek function. */ + ctx.session->ctx = &ctx; - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; - } - do { - ret = send(control_sock, &connect, sizeof(connect), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending version\n"); - goto error; - } + /* HT to store the CTF traces. */ + ctx.session->ctf_traces = g_hash_table_new(g_direct_hash, + g_direct_equal); - do { - ret = recv(control_sock, &connect, sizeof(connect), 0); - } while (ret < 0 && errno == EINTR); + ret = parse_url(path, hostname, &port, &session_id); if (ret < 0) { - fprintf(stderr, "Error receiving version\n"); - goto error; + goto end_free; } - fprintf(stderr, " - Received viewer session ID : %" PRIu64 "\n", - be64toh(connect.viewer_session_id)); - fprintf(stderr, " - Received version : %u.%u\n", be32toh(connect.major), - be32toh(connect.minor)); - ret = 0; - -error: - return ret; -} - -int list_sessions(void) -{ - struct lttng_viewer_cmd cmd; - struct lttng_viewer_list_sessions list; - struct lttng_viewer_session lsession; - int i, ret; - int first_session = 0; - - cmd.cmd = htobe32(VIEWER_LIST_SESSIONS); - cmd.data_size = 0; - cmd.cmd_version = 0; - - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); + ret = lttng_live_connect_viewer(&ctx, hostname, port); if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; + fprintf(stderr, "[error] Connection failed\n"); + goto end_free; } + printf_verbose("LTTng-live connected to relayd\n"); - do { - ret = recv(control_sock, &list, sizeof(list), 0); - } while (ret < 0 && errno == EINTR); + ret = lttng_live_establish_connection(&ctx); if (ret < 0) { - fprintf(stderr, "Error receiving session list\n"); - goto error; + goto end_free; } - fprintf(stderr, " - %u active session(s)\n", be32toh(list.sessions_count)); - for (i = 0; i < be32toh(list.sessions_count); i++) { - do { - ret = recv(control_sock, &lsession, sizeof(lsession), 0); - } while (ret < 0 && errno == EINTR); + if (session_id == -1ULL) { + printf_verbose("Listing sessions\n"); + ret = lttng_live_list_sessions(&ctx, path); if (ret < 0) { - fprintf(stderr, "Error receiving session\n"); - goto error; - } - fprintf(stderr, " - %" PRIu64 " : %s on host %s (timer = %u, " - "%u client(s) connected)\n", - be64toh(lsession.id), lsession.session_name, - lsession.hostname, be32toh(lsession.live_timer), - be32toh(lsession.clients)); - if (first_session <= 0) { - first_session = be64toh(lsession.id); + fprintf(stderr, "[error] List error\n"); + goto end_free; } - } - - /* I know, type mismatch */ - ret = (int) first_session; - -error: - return ret; -} - -static -int attach_session(int id, int begin) -{ - struct lttng_viewer_cmd cmd; - struct lttng_viewer_attach_session_request rq; - struct lttng_viewer_attach_session_response rp; - struct lttng_viewer_stream stream; - int ret, i; - - cmd.cmd = htobe32(VIEWER_ATTACH_SESSION); - cmd.data_size = sizeof(rq); - cmd.cmd_version = 0; - - rq.session_id = htobe64(id); - if (begin) { - rq.seek = htobe32(VIEWER_SEEK_BEGINNING); } else { - rq.seek = htobe32(VIEWER_SEEK_LAST); - } - - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; - } - do { - ret = send(control_sock, &rq, sizeof(rq), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending attach request\n"); - goto error; - } - - do { - ret = recv(control_sock, &rp, sizeof(rp), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving attach response\n"); - goto error; - } - fprintf(stderr, " - session attach response : %u\n", be32toh(rp.status)); - if (be32toh(rp.status) != VIEWER_ATTACH_OK) { - ret = 1; - goto end; + lttng_live_read(&ctx, session_id); } - session->stream_count = be32toh(rp.streams_count); - fprintf(stderr, " - Waiting for %" PRIu64 " streams\n", session->stream_count); - session->streams = zmalloc(session->stream_count * - sizeof(struct viewer_stream)); - if (!session->streams) { - ret = -1; - goto error; - } - - for (i = 0; i < be32toh(rp.streams_count); i++) { - do { - ret = recv(control_sock, &stream, sizeof(stream), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving stream\n"); - goto error; - } - fprintf(stderr, " - stream %" PRIu64 " : %s/%s\n", - be64toh(stream.id), stream.path_name, - stream.channel_name); - session->streams[i].id = be64toh(stream.id); - - session->streams[i].ctf_trace_id = be64toh(stream.ctf_trace_id); - session->streams[i].first_read = 1; - session->streams[i].mmap_base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (session->streams[i].mmap_base == MAP_FAILED) { - fprintf(stderr, "mmap error\n"); - ret = -1; - goto error; - } - - if (be32toh(stream.metadata_flag)) { - session->streams[i].metadata_flag = 1; - unlink("testlivetrace"); - mkdir("testlivetrace", S_IRWXU | S_IRWXG); - snprintf(session->streams[i].path, - sizeof(session->streams[i].path), - "testlivetrace/%s", - stream.channel_name); - ret = open(session->streams[i].path, - O_WRONLY | O_CREAT | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); - if (ret < 0) { - goto error; - } - session->streams[i].fd = ret; - } - } - ret = 0; - -end: -error: +end_free: + g_hash_table_destroy(ctx.session->ctf_traces); + g_free(ctx.session); + g_free(ctx.session->streams); return ret; } -#if 0 -/* useful debug */ -static -void dump_packet_index(struct lttng_packet_index *index) -{ - printf(" - index : %lu, %lu, %lu, %lu, %lu, %lu, %lu\n", - be64toh(index->offset), - be64toh(index->packet_size), - be64toh(index->content_size), - be64toh(index->timestamp_begin), - be64toh(index->timestamp_end), - be64toh(index->events_discarded), - be64toh(index->stream_id)); -} -#endif - static -int get_data_packet(int id, uint64_t offset, - uint64_t len) +struct bt_trace_descriptor *lttng_live_open_trace(const char *path, int flags, + void (*packet_seek)(struct bt_stream_pos *pos, size_t index, + int whence), FILE *metadata_fp) { - struct lttng_viewer_cmd cmd; - struct lttng_viewer_get_packet rq; - struct lttng_viewer_trace_packet rp; - int ret; - - cmd.cmd = htobe32(VIEWER_GET_PACKET); - cmd.data_size = sizeof(rq); - cmd.cmd_version = 0; - - rq.stream_id = htobe64(session->streams[id].id); - /* Already in big endian. */ - rq.offset = offset; - rq.len = htobe32(len); - fprintf(stderr, " - get_packet "); - - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; - } - do { - ret = send(control_sock, &rq, sizeof(rq), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending get_data_packet request\n"); - goto error; - } - do { - ret = recv(control_sock, &rp, sizeof(rp), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving data response\n"); - goto error; - } - rp.flags = be32toh(rp.flags); + struct ctf_text_stream_pos *pos; - switch (be32toh(rp.status)) { - case VIEWER_GET_PACKET_OK: - fprintf(stderr, "OK\n"); + switch (flags & O_ACCMODE) { + case O_RDONLY: + /* OK */ break; - case VIEWER_GET_PACKET_RETRY: - fprintf(stderr, "RETRY\n"); - ret = -1; - goto end; - case VIEWER_GET_PACKET_ERR: - if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { - fprintf(stderr, "NEW_METADATA\n"); - ret = 0; - goto end; - } - fprintf(stderr, "ERR\n"); - ret = -1; - goto end; + case O_RDWR: + fprintf(stderr, "[error] lttng live plugin cannot be used as output plugin.\n"); + goto error; default: - fprintf(stderr, "UNKNOWN\n"); - ret = -1; - goto end; - } - - len = be32toh(rp.len); - fprintf(stderr, " - writing %" PRIu64" bytes to tracefile\n", len); - if (len <= 0) { - goto end; - } - - if (len > mmap_size) { - fprintf(stderr, "mmap_size not big enough\n"); - ret = -1; + fprintf(stderr, "[error] Incorrect open flags.\n"); goto error; } - do { - ret = recv(control_sock, session->streams[id].mmap_base, len, MSG_WAITALL); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving trace packet\n"); - goto error; - } + pos = g_new0(struct ctf_text_stream_pos, 1); + pos->parent.rw_table = NULL; + pos->parent.event_cb = NULL; + pos->parent.trace = &pos->trace_descriptor; + lttng_live_open_trace_read(path); + return &pos->trace_descriptor; -end: error: - return ret; + return NULL; } -/* - * Return number of metadata bytes written or a negative value on error. - */ static -int get_new_metadata(int id) +int lttng_live_close_trace(struct bt_trace_descriptor *td) { - struct lttng_viewer_cmd cmd; - struct lttng_viewer_get_metadata rq; - struct lttng_viewer_metadata_packet rp; - int ret; - uint64_t i; - char *data = NULL; - uint64_t len = 0; - int metadata_stream_id = -1; - - cmd.cmd = htobe32(VIEWER_GET_METADATA); - cmd.data_size = sizeof(rq); - cmd.cmd_version = 0; - - /* find the metadata stream for this ctf_trace */ - for (i = 0; i < session->stream_count; i++) { - if (session->streams[i].metadata_flag && - session->streams[i].ctf_trace_id == - session->streams[id].ctf_trace_id) { - metadata_stream_id = i; - break; - } - } - if (metadata_stream_id < 0) { - fprintf(stderr, "No metadata stream found\n"); - ret = -1; - goto error; - } - - rq.stream_id = htobe64(session->streams[metadata_stream_id].id); - fprintf(stderr, " - get_metadata "); - - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; - } - do { - ret = send(control_sock, &rq, sizeof(rq), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending get_metadata request\n"); - goto error; - } - do { - ret = recv(control_sock, &rp, sizeof(rp), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving metadata response\n"); - goto error; - } - switch (be32toh(rp.status)) { - case VIEWER_METADATA_OK: - fprintf(stderr, "OK\n"); - break; - case VIEWER_NO_NEW_METADATA: - fprintf(stderr, "NO NEW\n"); - ret = -1; - goto end; - case VIEWER_METADATA_ERR: - fprintf(stderr, "ERR\n"); - ret = -1; - goto end; - default: - fprintf(stderr, "UNKNOWN\n"); - ret = -1; - goto end; - } - - len = be64toh(rp.len); - fprintf(stderr, " - writing %" PRIu64" bytes to metadata\n", len); - if (len <= 0) { - goto end; - } - - data = zmalloc(len); - if (!data) { - perror("relay data zmalloc"); - goto error; - } - do { - ret = recv(control_sock, data, len, MSG_WAITALL); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving trace packet\n"); - free(data); - goto error; - } - do { - ret = write(session->streams[metadata_stream_id].fd, data, len); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - free(data); - goto error; - } - free(data); - - /* FIXME : bad */ - ret = (int) len; -end: -error: - return ret; + struct ctf_text_stream_pos *pos = + container_of(td, struct ctf_text_stream_pos, + trace_descriptor); + free(pos); + return 0; } -/* - * Get one index for a stream. - */ -int get_next_index(int id, struct packet_index *index) -{ - struct lttng_viewer_cmd cmd; - struct lttng_viewer_get_next_index rq; - struct lttng_viewer_index rp; - int ret; - - cmd.cmd = htobe32(VIEWER_GET_NEXT_INDEX); - cmd.data_size = sizeof(rq); - cmd.cmd_version = 0; - - fprintf(stderr, " - get next index for stream %" PRIu64 "\n", - session->streams[id].id); - rq.stream_id = htobe64(session->streams[id].id); - -retry: - do { - ret = send(control_sock, &cmd, sizeof(cmd), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending cmd\n"); - goto error; - } - do { - ret = send(control_sock, &rq, sizeof(rq), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error sending get_next_index request\n"); - goto error; - } - do { - ret = recv(control_sock, &rp, sizeof(rp), 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - fprintf(stderr, "Error receiving index response\n"); - goto error; - } - fprintf(stderr, " - reply : %u ", be32toh(rp.status)); - - rp.flags = be32toh(rp.flags); - - switch (be32toh(rp.status)) { - case VIEWER_INDEX_INACTIVE: - fprintf(stderr, "(INACTIVE)\n"); - memset(index, 0, sizeof(struct packet_index)); - index->timestamp_end = be64toh(rp.timestamp_end); - break; - case VIEWER_INDEX_OK: - fprintf(stderr, "(OK), need metadata update : %u\n", - rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA); - index->offset = be64toh(rp.offset); - index->packet_size = be64toh(rp.packet_size); - index->content_size = be64toh(rp.content_size); - index->timestamp_begin = be64toh(rp.timestamp_begin); - index->timestamp_end = be64toh(rp.timestamp_end); - index->events_discarded = be64toh(rp.events_discarded); - - if (rp.flags & LTTNG_VIEWER_FLAG_NEW_METADATA) { - fprintf(stderr, "NEW METADATA NEEDED\n"); - ret = get_new_metadata(id); - if (ret < 0) { - goto error; - } - } - break; - case VIEWER_INDEX_RETRY: - fprintf(stderr, "(RETRY)\n"); - sleep(1); - goto retry; - case VIEWER_INDEX_HUP: - fprintf(stderr, "(HUP)\n"); - session->streams[id].id = -1ULL; - session->streams[id].fd = -1; - break; - case VIEWER_INDEX_ERR: - fprintf(stderr, "(ERR)\n"); - ret = -1; - goto error; - default: - fprintf(stderr, "SHOULD NOT HAPPEN\n"); - ret = -1; - goto error; - } - -error: - return ret; -} +static +struct bt_format lttng_live_format = { + .open_trace = lttng_live_open_trace, + .close_trace = lttng_live_close_trace, +}; -void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, - int whence) +static +void __attribute__((constructor)) lttng_live_init(void) { - struct ctf_stream_pos *pos; - struct ctf_file_stream *file_stream; - struct packet_index packet_index; int ret; - pos = ctf_pos(stream_pos); - file_stream = container_of(pos, struct ctf_file_stream, pos); - - fprintf(stderr, "BT GET_NEXT_INDEX %d\n", pos->fd); - ret = get_next_index(pos->fd, &packet_index); - if (ret < 0) { - fprintf(stderr, "get_next_index failed\n"); - return; - } - - pos->packet_size = packet_index.packet_size; - pos->content_size = packet_index.content_size; - pos->mmap_base_offset = 0; - pos->offset = 0; - if (packet_index.offset == EOF) { - pos->offset = EOF; - } else { - pos->offset = 0; - } - - file_stream->parent.cycles_timestamp = packet_index.timestamp_end; - file_stream->parent.real_timestamp = ctf_get_real_timestamp( - &file_stream->parent, packet_index.timestamp_end); - - if (pos->packet_size == 0) { - goto end; - } - - fprintf(stderr, "BT GET_DATA_PACKET\n"); - ret = get_data_packet(pos->fd, be64toh(packet_index.offset), - packet_index.packet_size / CHAR_BIT); - if (ret < 0) { - fprintf(stderr, "get_data_packet failed"); - return; - } - - fprintf(stderr, "BT MMAP %d\n", pos->fd); - fprintf(stderr, "packet_size : %lu, offset %lu, content_size %lu, timestamp_end : %lu, real : %lu\n", - packet_index.packet_size, - packet_index.offset, - packet_index.content_size, - packet_index.timestamp_end, - ctf_get_real_timestamp( - &file_stream->parent, packet_index.timestamp_end)); - if (!pos->base_mma) { - pos->base_mma = zmalloc(sizeof(*pos->base_mma)); - if (!pos->base_mma) { - fprintf(stderr, "alloc pos->base_mma\n"); - return; - } - } - - mmap_align_set_addr(pos->base_mma, session->streams[pos->fd].mmap_base); - if (pos->base_mma == MAP_FAILED) { - perror("Error mmaping"); - return; - } - - /* update trace_packet_header and stream_packet_context */ - if (pos->prot != PROT_WRITE && file_stream->parent.trace_packet_header) { - /* Read packet header */ - ret = generic_rw(&pos->parent, &file_stream->parent.trace_packet_header->p); - assert(!ret); - } - if (pos->prot != PROT_WRITE && file_stream->parent.stream_packet_context) { - /* Read packet context */ - ret = generic_rw(&pos->parent, &file_stream->parent.stream_packet_context->p); - assert(!ret); - } - -end: - return; + lttng_live_format.name = g_quark_from_static_string("lttng-live"); + ret = bt_register_format(<tng_live_format); + assert(!ret); } -int open_trace(struct bt_context **bt_ctx) -{ - struct bt_mmap_stream *new_mmap_stream; - struct bt_mmap_stream_list mmap_list; - FILE *metadata_fp = NULL; - int i; - int ret = 0; - - *bt_ctx = bt_context_create(); - BT_INIT_LIST_HEAD(&mmap_list.head); - - for (i = 0; i < session->stream_count; i++) { - int total_metadata = 0; - - if (!session->streams[i].metadata_flag) { - new_mmap_stream = zmalloc(sizeof(struct bt_mmap_stream)); - /* - * The FD is unused when we handle manually the - * packet seek, so we store here the ID of the - * stream in our stream list to be able to use it - * later. - */ - new_mmap_stream->fd = i; - bt_list_add(&new_mmap_stream->list, &mmap_list.head); - } else { - /* Get all possible metadata before starting */ - do { - ret = get_new_metadata(i); - if (ret > 0) { - total_metadata += ret; - } - } while (ret > 0 || total_metadata == 0); - metadata_fp = fopen(session->streams[i].path, "r"); - } - } - - if (!metadata_fp) { - fprintf(stderr, "No metadata stream opened\n"); - goto end; - } - - ret = bt_context_add_trace(*bt_ctx, NULL, "ctf", - ctf_live_packet_seek, &mmap_list, metadata_fp); - if (ret < 0) { - fprintf(stderr, "Error adding trace\n"); - goto end; - } - - /* - begin_pos.type = BT_SEEK_BEGIN; - iter = bt_ctf_iter_create(bt_ctx, &begin_pos, NULL); - while ((event = bt_ctf_iter_read_event(iter)) != NULL) { - if (!skip) { - ret = sout->parent.event_cb(&sout->parent, event->parent->stream); - if (ret) { - fprintf(stderr, "[error] Writing event failed.\n"); - goto end; - } - } - - ret = bt_iter_next(bt_ctf_get_iter(iter)); - if (ret < 0) { - goto end; - } else if (ret == EAGAIN) { - skip = 1; - continue; - } - skip = 0; - } - */ - -end: - return ret; -} - -int setup_network_live(char *hostname, int begin) +static +void __attribute__((destructor)) lttng_live_exit(void) { - int ret; - int session_id; - - session = zmalloc(sizeof(struct live_session)); - if (!session) { - goto error; - } - - ret = connect_viewer(hostname); - if (ret < 0) { - goto error; - } - fprintf(stderr, "* Connected\n"); - - fprintf(stderr, "* Establish connection and version check\n"); - ret = establish_connection(); - if (ret < 0) { - goto error; - } - - fprintf(stderr, "* List sessions\n"); - ret = list_sessions(); - if (ret < 0) { - fprintf(stderr, "* List error\n"); - goto error; - } else if (ret == 0) { - fprintf(stderr, "* No session to attach to, exiting\n"); - ret = 0; - goto end; - } - session_id = ret; - - do { - fprintf(stderr, "* Attach session %d\n", ret); - ret = attach_session(session_id, begin); - if (ret < 0) { - goto error; - } - } while (session->stream_count == 0); - -end: - return 0; - -error: - free(session->streams); - fprintf(stderr, "* Exiting %d\n", ret); - return ret; + bt_unregister_format(<tng_live_format); } diff --git a/src/network-live.h b/src/network-live.h index b84fc0b..5d8e5df 100644 --- a/src/network-live.h +++ b/src/network-live.h @@ -21,7 +21,7 @@ #include #include #include -#include "ctf-index.h" +#include /* Copied from babeltrace/formats/ctf/events-private.h */ static inline @@ -43,12 +43,4 @@ uint64_t ctf_get_real_timestamp(struct ctf_stream_definition *stream, return ts_nsec; } -int list_sessions(void); -void dump_packet_index(struct ctf_packet_index *index); -int get_next_index(int id, struct packet_index *index); -void ctf_live_packet_seek(struct bt_stream_pos *stream_pos, size_t index, - int whence); -int open_trace(struct bt_context **bt_ctx); -int setup_network_live(char *hostname, int begin); - #endif /* _LIVE_H */