--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/clock.h>
+#include <babeltrace/ctf-writer/writer-internal.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <glib.h>
+#include <uuid/uuid.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/event-fields.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf/types.h>
+#include <glib.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <stdint.h>
+
+#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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/event-types.h>
+#include <babeltrace/ctf-writer/event-fields.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf/types.h>
+#include <glib.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/event-types.h>
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/event-fields.h>
+#include <babeltrace/ctf-writer/writer.h>
+#include <babeltrace/ctf-writer/writer-internal.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/types.h>
+#include <babeltrace/ctf/events.h>
+#include <glib.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * The Common Trace Format (CTF) Specification is available at
+ * http://www.efficios.com/ctf
+ */
+
+#include <babeltrace/ctf-writer/writer.h>
+#include <babeltrace/ctf/events.h>
+#include <stdint.h>
+
+#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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * 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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <glib.h>
+#include <babeltrace/babeltrace-internal.h>
+
+struct search_query {
+ gpointer value;
+ int found;
+};
+
+BT_HIDDEN
+void value_exists(gpointer element, gpointer search_query);
+
+#endif /* BABELTRACE_CTF_WRITER_FUNCTOR_INTERNAL_H */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/clock.h>
+#include <babeltrace/ctf-writer/event-fields.h>
+#include <babeltrace/ctf-writer/event-types.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <babeltrace/ctf/types.h>
+#include <glib.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * 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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <babeltrace/ctf-writer/ref-internal.h>
+#include <babeltrace/ctf-writer/writer.h>
+#include <babeltrace/ctf-writer/event-types.h>
+#include <babeltrace/ctf-writer/event-fields.h>
+#include <babeltrace/babeltrace-internal.h>
+#include <glib.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <uuid/uuid.h>
+
+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 */
--- /dev/null
+#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 <jeremie.galarneau@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * 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 */
--- /dev/null
+/*
+ * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
+ * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * David Goulet <dgoulet@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef LTTNG_INDEX_H
+#define LTTNG_INDEX_H
+
+#include <limits.h>
+
+#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 */
#include <glib.h>
struct ctf_stream_definition;
+struct ctf_file_stream;
/*
* These structures are public mappings to internal ctf_event structures.
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 */
*/
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
*
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
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 */
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,
int dummy; /* dummy position, for length calculation */
struct bt_stream_callbacks *cb; /* Callbacks registered for iterator. */
+ void *priv;
};
static inline
/*
* 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
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
struct bt_mmap_stream {
int fd;
struct bt_list_head list;
+ void *priv;
};
struct bt_mmap_stream_list {
/* Flags for the iterator read_event */
enum {
BT_ITER_FLAG_LOST_EVENTS = (1 << 0),
+ BT_ITER_FLAG_RETRY = (1 << 1),
};
/* Forward declarations */
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);
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
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 = \
cursesdisplay.h \
iostreamtop.h \
mmap-live.h \
- network-live.h
+ network-live.h \
+ lttng-live-functions.h \
+ lttngtop.h
lttngtop_SOURCES = \
lttngtop.c \
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
+
--- /dev/null
+/*
+ * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
+ * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <babeltrace/ctf/ctf-index.h>
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/callbacks.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* for packet_index */
+#include <babeltrace/ctf/types.h>
+
+#include <babeltrace/ctf/metadata.h>
+#include <babeltrace/ctf-text/types.h>
+#include <babeltrace/ctf/events-internal.h>
+/*
+#include <formats/ctf/events-private.h>
+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;
+}
--- /dev/null
+#ifndef _LTTNG_LIVE_FUNCTIONS_H
+#define _LTTNG_LIVE_FUNCTIONS_H
+
+/*
+ * Copyright 2013 Julien Desfossez <julien.desfossez@efficios.com>
+ * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#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 */
#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 {
} __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;
} __attribute__((__packed__));
/*
- * VIEWER_GET_NEXT_INDEX payload.
+ * LTTNG_VIEWER_GET_NEXT_INDEX payload.
*/
struct lttng_viewer_get_next_index {
uint64_t stream_id;
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;
} __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;
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__));
#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;
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.
#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;
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();
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;
--- /dev/null
+/*
+ * 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 */
#include <sys/mman.h>
#include "lttng-viewer.h"
-#include "ctf-index.h"
#include "network-live.h"
+#include "lttng-live-functions.h"
#include <babeltrace/babeltrace.h>
#include <babeltrace/ctf/events.h>
#include <babeltrace/ctf/metadata.h>
#include <babeltrace/ctf-text/types.h>
#include <babeltrace/ctf/events-internal.h>
+#include <lib/babeltrace/ctf/ctf-index.h>
/*
- * 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);
}
#include <lib/babeltrace/ctf/types.h>
#include <lib/babeltrace/ctf-ir/metadata.h>
#include <lib/babeltrace/clock-internal.h>
-#include "ctf-index.h"
+#include <lib/babeltrace/ctf/ctf-index.h>
/* Copied from babeltrace/formats/ctf/events-private.h */
static inline
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 */