sessiond: add tracer-agnostic trace hierarchy classes
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Thu, 12 May 2022 18:34:30 +0000 (14:34 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 13 Jun 2022 20:34:47 +0000 (16:34 -0400)
The session daemon receives the fields present in events from the
instrumented applications in the form of an array of lttng_ust_ctl_field
structures and uses them directly in a number of code paths.

This makes it impossible to extend the structures which makes a number of
features harder to implement than they should be.

The session daemon also implements various CTF concepts (clock, trace,
event, stream classes) as part of various structures defined under
`ust_registry*`. This makes it hard to isolate which attributes are
"internal" and which are visible to the external world through the
traces.

Tracer-agnostic trace hierachy classes are introduced under the
lttng::sessiond::trace namespace. Those classes don't cover the full
functionality of CTF: they expose what the tracers can currently
express.

The top-level elements of the trace hierarchy -- trace, event, stream,
clock classes -- are visited using the trace_class_visitor interface.

Seperate field and type visitor interfaces are used to make it easier to
visit this subset of the trace hierarchy. This will be useful to
implement the listing of event fields through liblttng-ctl, for example.

In the short term, these classes will be used to implement the
serialization of the layout descriptions of CTF 1.8 and 2.

Change-Id: I6d99f0ec93082259bf64434c440a720ed9a49bf8
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
src/bin/lttng-sessiond/Makefile.am
src/bin/lttng-sessiond/clock-class.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/clock-class.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/event-class.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/event-class.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/field.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/field.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/stream-class.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/stream-class.hpp [new file with mode: 0644]
src/bin/lttng-sessiond/trace-class.cpp [new file with mode: 0644]
src/bin/lttng-sessiond/trace-class.hpp [new file with mode: 0644]

index 5b5047f4306b48a04d2b8b0daaa4aaea8a578135..78e769ef6bd216ad2c418ef2b7737a7d245d079f 100644 (file)
@@ -57,7 +57,12 @@ liblttng_sessiond_common_la_SOURCES = utils.cpp utils.hpp \
                        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 \
diff --git a/src/bin/lttng-sessiond/clock-class.cpp b/src/bin/lttng-sessiond/clock-class.cpp
new file mode 100644 (file)
index 0000000..d81a487
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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);
+}
diff --git a/src/bin/lttng-sessiond/clock-class.hpp b/src/bin/lttng-sessiond/clock-class.hpp
new file mode 100644 (file)
index 0000000..3a4755d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 */
diff --git a/src/bin/lttng-sessiond/event-class.cpp b/src/bin/lttng-sessiond/event-class.cpp
new file mode 100644 (file)
index 0000000..9d36703
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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);
+}
diff --git a/src/bin/lttng-sessiond/event-class.hpp b/src/bin/lttng-sessiond/event-class.hpp
new file mode 100644 (file)
index 0000000..d42d764
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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 */
diff --git a/src/bin/lttng-sessiond/field.cpp b/src/bin/lttng-sessiond/field.cpp
new file mode 100644 (file)
index 0000000..25f0e46
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * 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
diff --git a/src/bin/lttng-sessiond/field.hpp b/src/bin/lttng-sessiond/field.hpp
new file mode 100644 (file)
index 0000000..bad66a3
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * 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 */
diff --git a/src/bin/lttng-sessiond/stream-class.cpp b/src/bin/lttng-sessiond/stream-class.cpp
new file mode 100644 (file)
index 0000000..b2092f5
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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;
+}
diff --git a/src/bin/lttng-sessiond/stream-class.hpp b/src/bin/lttng-sessiond/stream-class.hpp
new file mode 100644 (file)
index 0000000..636d0b1
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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 */
diff --git a/src/bin/lttng-sessiond/trace-class.cpp b/src/bin/lttng-sessiond/trace-class.cpp
new file mode 100644 (file)
index 0000000..21a0c52
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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()));
+}
diff --git a/src/bin/lttng-sessiond/trace-class.hpp b/src/bin/lttng-sessiond/trace-class.hpp
new file mode 100644 (file)
index 0000000..0874998
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 */
This page took 0.036712 seconds and 4 git commands to generate.