tracker.cpp tracker.hpp \
event-notifier-error-accounting.cpp event-notifier-error-accounting.hpp \
action-executor.cpp action-executor.hpp\
- trigger-error-query.cpp
+ trigger-error-query.cpp \
+ field.hpp field.cpp \
+ clock-class.hpp clock-class.cpp \
+ event-class.hpp event-class.cpp \
+ stream-class.hpp stream-class.cpp \
+ trace-class.hpp trace-class.cpp
if HAVE_LIBLTTNG_UST_CTL
liblttng_sessiond_common_la_SOURCES += trace-ust.cpp ust-registry.cpp ust-app.cpp \
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "clock-class.hpp"
+#include "trace-class.hpp"
+
+lttng::sessiond::trace::clock_class::clock_class(std::string in_name,
+ std::string in_description,
+ nonstd::optional<lttng_uuid> in_uuid,
+ scycles_t in_offset,
+ cycles_t in_frequency) :
+ name{std::move(in_name)},
+ description{std::move(in_description)},
+ uuid{std::move(in_uuid)},
+ offset{in_offset},
+ frequency{in_frequency}
+{
+}
+
+void lttng::sessiond::trace::clock_class::accept(trace_class_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_CLOCK_CLASS_H
+#define LTTNG_CLOCK_CLASS_H
+
+#include <common/compat/time.hpp>
+#include <common/uuid.hpp>
+#include <vendor/optional.hpp>
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <sys/time.h>
+#include <urcu/arch.h>
+#include <urcu/system.h>
+
+namespace lttng {
+namespace sessiond {
+namespace trace {
+
+class trace_class_visitor;
+
+class clock_class {
+public:
+ using cycles_t = uint64_t;
+ using scycles_t = int64_t;
+
+ const std::string name;
+ const std::string description;
+ const nonstd::optional<lttng_uuid> uuid;
+ const scycles_t offset;
+ const cycles_t frequency;
+
+ virtual void accept(trace_class_visitor& visitor) const;
+ virtual ~clock_class() = default;
+
+protected:
+ clock_class(std::string name,
+ std::string description,
+ nonstd::optional<lttng_uuid> uuid,
+ scycles_t offset,
+ cycles_t frequency);
+};
+
+} /* namespace trace */
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_CLOCK_CLASS_H */
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "event-class.hpp"
+
+namespace lst = lttng::sessiond::trace;
+
+lst::event_class::event_class(unsigned int in_id,
+ unsigned int in_stream_class_id,
+ int in_log_level,
+ std::string in_name,
+ nonstd::optional<std::string> in_model_emf_uri,
+ lttng::sessiond::trace::type::cuptr in_payload) :
+ id{in_id},
+ stream_class_id{in_stream_class_id},
+ log_level{in_log_level},
+ name{std::move(in_name)},
+ model_emf_uri{std::move(in_model_emf_uri)},
+ payload{std::move(in_payload)}
+{
+}
+
+void lst::event_class::accept(lst::trace_class_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_EVENT_CLASS_H
+#define LTTNG_EVENT_CLASS_H
+
+#include "field.hpp"
+
+#include <common/uuid.hpp>
+#include <vendor/optional.hpp>
+
+#include <string>
+
+namespace lttng {
+namespace sessiond {
+namespace trace {
+
+class trace_class_visitor;
+
+class event_class {
+public:
+ virtual void accept(trace_class_visitor& visitor) const;
+ virtual ~event_class() = default;
+
+ const unsigned int id;
+ const unsigned int stream_class_id;
+ const int log_level;
+ const std::string name;
+ const nonstd::optional<std::string> model_emf_uri;
+ const lttng::sessiond::trace::type::cuptr payload;
+
+protected:
+ event_class(unsigned int id,
+ unsigned int stream_class_id,
+ int log_level,
+ std::string name,
+ nonstd::optional<std::string> model_emf_uri,
+ lttng::sessiond::trace::type::cuptr payload);
+};
+
+} /* namespace trace */
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_EVENT_CLASS_H */
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "field.hpp"
+
+#include <common/exception.hpp>
+#include <common/format.hpp>
+
+namespace lst = lttng::sessiond::trace;
+
+namespace {
+template <class FieldTypeSet>
+bool fields_are_equal(const FieldTypeSet& a, const FieldTypeSet& b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+
+ return std::equal(a.cbegin(), a.cend(), b.cbegin(),
+ [](typename FieldTypeSet::const_reference field_a,
+ typename FieldTypeSet::const_reference field_b) {
+ return *field_a == *field_b;
+ });
+}
+} /* namespace */
+
+lst::type::type(unsigned int in_alignment) : alignment{in_alignment}
+{
+}
+
+lst::type::~type()
+{
+}
+
+bool lst::type::operator==(const lst::type& other) const noexcept
+{
+ return typeid(*this) == typeid(other) &&
+ alignment == other.alignment &&
+ /* defer to concrete type comparison */
+ this->_is_equal(other);
+}
+
+bool lst::type::operator!=(const lst::type& other) const noexcept
+{
+ return !(*this == other);
+}
+
+lst::field::field(std::string in_name, lst::type::cuptr in_type) :
+ name{std::move(in_name)}, _type{std::move(in_type)}
+{
+}
+
+void lst::field::accept(lst::field_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+bool lst::field::operator==(const lst::field& other) const noexcept
+{
+ return name == other.name && *_type == *other._type;
+}
+
+lst::integer_type::integer_type(unsigned int in_alignment,
+ enum lst::byte_order in_byte_order,
+ unsigned int in_size,
+ enum lst::integer_type::signedness in_signedness,
+ enum lst::integer_type::base in_base) :
+ type(in_alignment),
+ byte_order{in_byte_order},
+ size{in_size},
+ signedness{in_signedness},
+ base{in_base}
+{
+}
+
+bool lst::integer_type::_is_equal(const type &base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return this->byte_order == other.byte_order &&
+ this->size == other.size &&
+ this->signedness == other.signedness &&
+ this->base == other.base;
+}
+
+void lst::integer_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::byte_order lst::type::reverse_byte_order(lst::byte_order byte_order) noexcept
+{
+ if (byte_order == lst::byte_order::BIG_ENDIAN_) {
+ return lst::byte_order::LITTLE_ENDIAN_;
+ } else {
+ return lst::byte_order::BIG_ENDIAN_;
+ }
+}
+
+lst::floating_point_type::floating_point_type(unsigned int in_alignment,
+ lst::byte_order in_byte_order,
+ unsigned int in_exponent_digits,
+ unsigned int in_mantissa_digits) :
+ type(in_alignment),
+ byte_order(in_byte_order),
+ exponent_digits{in_exponent_digits},
+ mantissa_digits(in_mantissa_digits)
+{
+ /* Allowed (exponent, mantissa) pairs. */
+ static const std::vector<std::pair<unsigned int, unsigned int>> allowed_pairs{
+ {5, 11}, /* binary16 */
+ {8, 24}, /* binary32 */
+ {11, 53}, /* binary64 */
+ {15, 113}, /* binary128 */
+ };
+
+ const auto input_pair = decltype(allowed_pairs)::value_type(exponent_digits, mantissa_digits);
+ for (const auto& pair : allowed_pairs) {
+ if (input_pair == pair) {
+ /* mantissa and exponent digits is a valid pair. */
+ return;
+ }
+ }
+
+ LTTNG_THROW_INVALID_ARGUMENT_ERROR(
+ fmt::format("Invalid exponent/mantissa values provided while creating {}",
+ typeid(*this)));
+}
+
+void lst::floating_point_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+bool lst::floating_point_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return this->byte_order == other.byte_order &&
+ this->exponent_digits == other.exponent_digits &&
+ this->mantissa_digits == other.mantissa_digits;
+}
+
+lst::enumeration_type::enumeration_type(unsigned int in_alignment,
+ enum lst::byte_order in_byte_order,
+ unsigned int in_size,
+ enum signedness in_signedness,
+ enum base in_base) :
+ integer_type(in_alignment, in_byte_order, in_size, in_signedness, in_base)
+{
+}
+
+template <>
+void lst::signed_enumeration_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+template <>
+void lst::unsigned_enumeration_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::array_type::array_type(unsigned int in_alignment, type::cuptr in_element_type) :
+ type(in_alignment), element_type{std::move(in_element_type)}
+{
+}
+
+bool lst::array_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return *this->element_type == *other.element_type;
+}
+
+lst::static_length_array_type::static_length_array_type(unsigned int in_alignment,
+ type::cuptr in_element_type,
+ uint64_t in_length) :
+ array_type(in_alignment, std::move(in_element_type)),
+ length{in_length}
+{
+}
+
+bool lst::static_length_array_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return array_type::_is_equal(base_other) && this->length == other.length;
+}
+
+void lst::static_length_array_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::dynamic_length_array_type::dynamic_length_array_type(unsigned int in_alignment,
+ type::cuptr in_element_type,
+ std::string in_length_field_name) :
+ array_type(in_alignment, std::move(in_element_type)),
+ length_field_name{std::move(in_length_field_name)}
+{
+}
+
+bool lst::dynamic_length_array_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return array_type::_is_equal(base_other) &&
+ this->length_field_name == other.length_field_name;
+}
+
+void lst::dynamic_length_array_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::string_type::string_type(unsigned int in_alignment, enum encoding in_encoding) :
+ type(in_alignment), encoding{in_encoding}
+{
+}
+
+bool lst::string_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return this->encoding == other.encoding;
+}
+
+lst::static_length_string_type::static_length_string_type(
+ unsigned int in_alignment, enum encoding in_encoding, uint64_t in_length) :
+ string_type(in_alignment, in_encoding), length{in_length}
+{
+}
+
+bool lst::static_length_string_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return string_type::_is_equal(base_other) && this->length == other.length;
+}
+
+void lst::static_length_string_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::dynamic_length_string_type::dynamic_length_string_type(unsigned int in_alignment,
+ enum encoding in_encoding,
+ std::string in_length_field_name) :
+ string_type(in_alignment, in_encoding), length_field_name{std::move(in_length_field_name)}
+{
+}
+
+bool lst::dynamic_length_string_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto& other = static_cast<decltype(*this)&>(base_other);
+
+ return string_type::_is_equal(base_other) &&
+ this->length_field_name == other.length_field_name;
+}
+
+void lst::dynamic_length_string_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::null_terminated_string_type::null_terminated_string_type(unsigned int in_alignment,
+ enum encoding in_encoding) :
+ string_type(in_alignment, in_encoding)
+{
+}
+
+void lst::null_terminated_string_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::structure_type::structure_type(unsigned int in_alignment, fields in_fields) :
+ type(in_alignment), _fields{std::move(in_fields)}
+{
+}
+
+bool lst::structure_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto &other = static_cast<decltype(*this)&>(base_other);
+
+ return fields_are_equal(this->_fields, other._fields);
+}
+
+void lst::structure_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
+
+lst::variant_type::variant_type(unsigned int in_alignment,
+ std::string in_tag_name,
+ choices in_choices) :
+ type(in_alignment),
+ tag_name{std::move(in_tag_name)},
+ _choices{std::move(in_choices)}
+{
+}
+
+bool lst::variant_type::_is_equal(const type& base_other) const noexcept
+{
+ const auto &other = static_cast<decltype(*this)&>(base_other);
+
+ return this->tag_name == other.tag_name &&
+ fields_are_equal(this->_choices, other._choices);
+}
+
+void lst::variant_type::accept(type_visitor& visitor) const
+{
+ visitor.visit(*this);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_FIELD_H
+#define LTTNG_FIELD_H
+
+#include "trace-class.hpp"
+
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <vendor/optional.hpp>
+
+namespace lttng {
+namespace sessiond {
+namespace trace {
+
+class field_visitor;
+class type_visitor;
+
+/*
+ * Field, and the various field types, represents fields as exposed by the
+ * LTTng tracers. These classes do not attempt to describe the complete spectrum of the CTF
+ * specification.
+ */
+
+class type {
+public:
+ using cuptr = std::unique_ptr<const type>;
+
+ static byte_order reverse_byte_order(byte_order byte_order) noexcept;
+
+ bool operator==(const type& other) const noexcept;
+ bool operator!=(const type& other) const noexcept;
+ virtual ~type();
+ virtual void accept(type_visitor& visitor) const = 0;
+
+ const unsigned int alignment;
+
+protected:
+ type(unsigned int alignment);
+
+private:
+ virtual bool _is_equal(const type& rhs) const noexcept = 0;
+};
+
+class field {
+public:
+ using cuptr = std::unique_ptr<const field>;
+
+ field(std::string name, type::cuptr type);
+ void accept(field_visitor& visitor) const;
+ bool operator==(const field& other) const noexcept;
+
+ const std::string name;
+ const type::cuptr _type;
+};
+
+class integer_type : public type {
+public:
+ enum class signedness {
+ SIGNED,
+ UNSIGNED,
+ };
+
+ enum class base {
+ BINARY = 2,
+ OCTAL = 8,
+ DECIMAL = 10,
+ HEXADECIMAL = 16,
+ };
+
+ integer_type(unsigned int alignment,
+ byte_order byte_order,
+ unsigned int size,
+ signedness signedness,
+ base base);
+
+ virtual void accept(type_visitor& visitor) const override;
+
+ const enum byte_order byte_order;
+ const unsigned int size;
+ const signedness signedness;
+ const base base;
+
+protected:
+ virtual bool _is_equal(const type& other) const noexcept override;
+};
+
+class floating_point_type : public type {
+public:
+ floating_point_type(unsigned int alignment,
+ byte_order byte_order,
+ unsigned int exponent_digits,
+ unsigned int mantissa_digits);
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const enum byte_order byte_order;
+ const unsigned int exponent_digits;
+ const unsigned int mantissa_digits;
+
+private:
+ virtual bool _is_equal(const type& other) const noexcept override final;
+};
+
+class enumeration_type : public integer_type {
+protected:
+ enumeration_type(unsigned int alignment,
+ enum byte_order byte_order,
+ unsigned int size,
+ enum signedness signedness,
+ enum base base);
+
+ virtual void accept(type_visitor& visitor) const = 0;
+};
+
+namespace details {
+template <class MappingIntegerType>
+class enumeration_mapping_range {
+public:
+ using range_integer_t = MappingIntegerType;
+
+ enumeration_mapping_range(MappingIntegerType in_begin, MappingIntegerType in_end) :
+ begin{in_begin}, end{in_end}
+ {
+ }
+
+ const range_integer_t begin, end;
+};
+
+template <class MappingIntegerType>
+bool operator==(const enumeration_mapping_range<MappingIntegerType>& lhs,
+ const enumeration_mapping_range<MappingIntegerType>& rhs) noexcept
+{
+ return lhs.begin == rhs.begin && lhs.end == rhs.end;
+}
+
+template <class MappingIntegerType>
+class enumeration_mapping {
+public:
+ using range_t = enumeration_mapping_range<MappingIntegerType>;
+
+ enumeration_mapping(const enumeration_mapping<MappingIntegerType>& other) = delete;
+ enumeration_mapping(const enumeration_mapping<MappingIntegerType>&& other) :
+ name{std::move(other.name)}, range{other.range}
+ {
+ }
+
+ /* Mapping with an implicit value. */
+ enumeration_mapping(std::string in_name) : name{std::move(in_name)}
+ {
+ }
+
+ enumeration_mapping(std::string in_name, range_t in_range) : name{std::move(in_name)}, range{in_range}
+ {
+ }
+
+ const std::string name;
+ const nonstd::optional<range_t> range;
+};
+
+template <class MappingIntegerType>
+bool operator==(const enumeration_mapping<MappingIntegerType>& lhs,
+ const enumeration_mapping<MappingIntegerType>& rhs) noexcept
+{
+ return lhs.name == rhs.name && lhs.range == rhs.range;
+}
+} /* namespace details */
+
+template <class MappingIntegerType>
+class typed_enumeration_type : public enumeration_type {
+public:
+ using mapping = details::enumeration_mapping<MappingIntegerType>;
+ using mappings = std::vector<mapping>;
+
+ static_assert(std::is_integral<MappingIntegerType>::value &&
+ sizeof(MappingIntegerType) == 8,
+ "MappingIntegerType must be either int64_t or uint64_t");
+
+ typed_enumeration_type(unsigned int in_alignment,
+ enum byte_order in_byte_order,
+ unsigned int in_size,
+ enum signedness in_signedness,
+ enum base in_base,
+ const std::shared_ptr<const mappings>& in_mappings) :
+ enumeration_type(in_alignment,
+ in_byte_order,
+ in_size,
+ in_signedness,
+ in_base),
+ _mappings{std::move(in_mappings)}
+ {
+ }
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const std::shared_ptr<const mappings> _mappings;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final
+ {
+ const auto& other = static_cast<const typed_enumeration_type<MappingIntegerType>&>(
+ base_other);
+
+ return integer_type::_is_equal(base_other) && *this->_mappings == *other._mappings;
+ }
+};
+
+/* Aliases for all allowed enumeration mapping types. */
+using signed_enumeration_type = typed_enumeration_type<int64_t>;
+using unsigned_enumeration_type = typed_enumeration_type<uint64_t>;
+
+class array_type : public type {
+public:
+ array_type(unsigned int alignment, type::cuptr element_type);
+
+ const type::cuptr element_type;
+
+protected:
+ virtual bool _is_equal(const type& base_other) const noexcept override;
+};
+
+class static_length_array_type : public array_type {
+public:
+ static_length_array_type(unsigned int alignment,
+ type::cuptr element_type,
+ uint64_t in_length);
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const uint64_t length;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class dynamic_length_array_type : public array_type {
+public:
+ dynamic_length_array_type(unsigned int alignment,
+ type::cuptr element_type,
+ std::string length_field_name);
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const std::string length_field_name;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class string_type : public type {
+public:
+ enum class encoding {
+ ASCII,
+ UTF8,
+ };
+
+ string_type(unsigned int alignment, enum encoding encoding);
+
+ const encoding encoding;
+
+protected:
+ virtual bool _is_equal(const type& base_other) const noexcept override;
+};
+
+class static_length_string_type : public string_type {
+public:
+ static_length_string_type(
+ unsigned int alignment, enum encoding in_encoding, uint64_t length);
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const uint64_t length;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class dynamic_length_string_type : public string_type {
+public:
+ dynamic_length_string_type(unsigned int alignment,
+ enum encoding in_encoding,
+ std::string length_field_name);
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const std::string length_field_name;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class null_terminated_string_type : public string_type {
+public:
+ null_terminated_string_type(unsigned int alignment, enum encoding in_encoding);
+ virtual void accept(type_visitor& visitor) const override final;
+};
+
+class structure_type : public type {
+public:
+ using fields = std::vector<field::cuptr>;
+
+ structure_type(unsigned int alignment, fields in_fields);
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const fields _fields;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class variant_type : public type {
+public:
+ using choices = std::vector<field::cuptr>;
+
+ variant_type(unsigned int alignment, std::string tag_name, choices in_choices);
+
+ virtual void accept(type_visitor& visitor) const override final;
+
+ const std::string tag_name;
+ const choices _choices;
+
+private:
+ virtual bool _is_equal(const type& base_other) const noexcept override final;
+};
+
+class field_visitor {
+public:
+ virtual ~field_visitor() = default;
+ virtual void visit(const field& field) = 0;
+
+protected:
+ field_visitor() = default;
+};
+
+class type_visitor {
+public:
+ virtual ~type_visitor() = default;
+ virtual void visit(const integer_type& type) = 0;
+ virtual void visit(const floating_point_type& type) = 0;
+ virtual void visit(const signed_enumeration_type& type) = 0;
+ virtual void visit(const unsigned_enumeration_type& type) = 0;
+ virtual void visit(const static_length_array_type& type) = 0;
+ virtual void visit(const dynamic_length_array_type& type) = 0;
+ virtual void visit(const null_terminated_string_type& type) = 0;
+ virtual void visit(const static_length_string_type& type) = 0;
+ virtual void visit(const dynamic_length_string_type& type) = 0;
+ virtual void visit(const structure_type& type) = 0;
+ virtual void visit(const variant_type& type) = 0;
+
+protected:
+ type_visitor() = default;
+};
+
+} /* namespace trace */
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_FIELD_H */
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "stream-class.hpp"
+#include "trace-class.hpp"
+
+namespace lst = lttng::sessiond::trace;
+
+lttng::sessiond::trace::stream_class::stream_class(
+ unsigned int in_id, enum header_type in_header_type) :
+ id{in_id}, header_type{in_header_type}
+{
+}
+
+void lst::stream_class::accept(trace_class_visitor& visitor) const
+{
+ visitor.visit(*this);
+ _accept_on_event_classes(visitor);
+}
+
+const lttng::sessiond::trace::type& lst::stream_class::get_context() const
+{
+ LTTNG_ASSERT(_context);
+ return *_context;
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_STREAM_CLASS_H
+#define LTTNG_STREAM_CLASS_H
+
+#include "field.hpp"
+
+#include <vector>
+
+namespace lttng {
+namespace sessiond {
+namespace trace {
+
+class trace_class_visitor;
+
+class stream_class {
+public:
+ enum class header_type { COMPACT, LARGE };
+
+ /*
+ * Derived classes must implement _accept_on_event_classes()
+ * to continue the traversal to the stream class' event classes.
+ */
+ void accept(trace_class_visitor& visitor) const;
+ virtual ~stream_class() = default;
+
+ virtual const lttng::sessiond::trace::type& get_context() const;
+
+ const unsigned int id;
+ const header_type header_type;
+
+protected:
+ stream_class(unsigned int id, enum header_type header_type);
+ virtual void _accept_on_event_classes(trace_class_visitor& trace_class_visitor) const = 0;
+
+ lttng::sessiond::trace::type::cuptr _context;
+};
+
+} /* namespace trace */
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_STREAM_CLASS_H */
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "trace-class.hpp"
+
+namespace lst = lttng::sessiond::trace;
+
+lttng::sessiond::trace::trace_class::trace_class(
+ const struct abi& in_abi,
+ const lttng_uuid& in_trace_uuid) :
+ abi{in_abi},
+ uuid{in_trace_uuid}
+{
+}
+
+void lttng::sessiond::trace::trace_class::accept(trace_class_visitor& trace_class_visitor) const
+{
+ trace_class_visitor.visit(*this);
+ _accept_on_clock_classes(trace_class_visitor);
+
+ trace_class_visitor.environment_begin();
+ _visit_environment(trace_class_visitor);
+ trace_class_visitor.environment_end();
+
+ _accept_on_stream_classes(trace_class_visitor);
+}
+
+void lst::trace_class_visitor::visit(const environment_field<std::string>& field)
+{
+ visit(environment_field<const char *>(field.name, field.value.c_str()));
+}
--- /dev/null
+/*
+ * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#ifndef LTTNG_TRACE_CLASS_H
+#define LTTNG_TRACE_CLASS_H
+
+#include <common/uuid.hpp>
+
+namespace lttng {
+namespace sessiond {
+namespace trace {
+
+class clock_class;
+class stream_class;
+class event_class;
+class trace_class_visitor;
+
+enum class byte_order {
+ BIG_ENDIAN_,
+ LITTLE_ENDIAN_,
+};
+
+struct abi {
+ unsigned int bits_per_long;
+ unsigned int long_alignment;
+ unsigned int uint8_t_alignment;
+ unsigned int uint16_t_alignment;
+ unsigned int uint32_t_alignment;
+ unsigned int uint64_t_alignment;
+ enum byte_order byte_order;
+};
+
+template <class ValueType>
+class environment_field {
+public:
+ environment_field(const char *in_name, const ValueType& in_value) :
+ name(in_name), value(in_value)
+ {
+ }
+
+ const char * const name;
+ const ValueType& value;
+};
+
+class trace_class {
+public:
+ /*
+ * Derived classes must implement the _accept_on_*()
+ * to continue the traversal to the trace class' children.
+ */
+ virtual void accept(trace_class_visitor& trace_class_visitor) const;
+
+ virtual ~trace_class() = default;
+
+ const struct abi abi;
+ const lttng_uuid uuid;
+
+protected:
+ trace_class(const struct abi& abi, const lttng_uuid& trace_uuid);
+ virtual void _accept_on_clock_classes(trace_class_visitor& trace_class_visitor) const = 0;
+ virtual void _visit_environment(trace_class_visitor& trace_class_visitor) const = 0;
+ virtual void _accept_on_stream_classes(trace_class_visitor& trace_class_visitor) const = 0;
+};
+
+class trace_class_visitor {
+public:
+ using cuptr = std::unique_ptr<trace_class_visitor>;
+
+ virtual ~trace_class_visitor() = default;
+
+ /* trace class visitor interface. */
+ virtual void visit(const lttng::sessiond::trace::trace_class& trace_class) = 0;
+
+ /* clock class visitor interface. */
+ virtual void visit(const lttng::sessiond::trace::clock_class& clock_class) = 0;
+
+ /* environment visitor interface. */
+ virtual void environment_begin() = 0;
+ virtual void visit(const environment_field<int64_t>& field) = 0;
+ virtual void visit(const environment_field<const char *>& field) = 0;
+ void visit(const environment_field<std::string>& field);
+ virtual void environment_end() = 0;
+
+ /* stream class visitor interface. */
+ virtual void visit(const lttng::sessiond::trace::stream_class& stream_class) = 0;
+
+ /* event class visitor interface. */
+ virtual void visit(const lttng::sessiond::trace::event_class& event_class) = 0;
+};
+
+} /* namespace trace */
+} /* namespace sessiond */
+} /* namespace lttng */
+
+#endif /* LTTNG_TRACE_CLASS_H */