*/
#include "event-class.hpp"
+#include "trace-class.hpp"
namespace lst = lttng::sessiond::trace;
#ifndef LTTNG_FIELD_H
#define LTTNG_FIELD_H
-#include "trace-class.hpp"
-
#include <memory>
#include <string>
#include <type_traits>
class field_visitor;
class type_visitor;
+enum class byte_order {
+ BIG_ENDIAN_,
+ LITTLE_ENDIAN_,
+};
+
/*
* 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
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}
+lttng::sessiond::trace::stream_class::stream_class(unsigned int in_id,
+ enum header_type in_header_type,
+ nonstd::optional<std::string> in_default_clock_class_name) :
+ id{in_id},
+ header_type_{in_header_type},
+ default_clock_class_name{std::move(in_default_clock_class_name)}
{
}
_accept_on_event_classes(visitor);
}
-const lttng::sessiond::trace::type& lst::stream_class::get_context() const
+const lttng::sessiond::trace::type *lst::stream_class::get_packet_context() const
{
- LTTNG_ASSERT(_context);
- return *_context;
+ return _packet_context.get();
+}
+
+const lttng::sessiond::trace::type *lst::stream_class::get_event_header() const
+{
+ return _event_header.get();
+}
+
+const lttng::sessiond::trace::type *lst::stream_class::get_event_context() const
+{
+ return _event_context.get();
}
#include "field.hpp"
+#include <vendor/optional.hpp>
+
#include <vector>
namespace lttng {
void accept(trace_class_visitor& visitor) const;
virtual ~stream_class() = default;
- virtual const lttng::sessiond::trace::type& get_context() const;
+ virtual const type* get_packet_context() const;
+ virtual const type* get_event_header() const;
+ virtual const type* get_event_context() const;
const unsigned int id;
/*
* nested-name-specifiers.
*/
const header_type header_type_;
+ const nonstd::optional<std::string> default_clock_class_name;
protected:
- stream_class(unsigned int id, enum header_type header_type);
+ stream_class(unsigned int id,
+ enum header_type header_type,
+ nonstd::optional<std::string> default_clock_class_name = nonstd::nullopt);
virtual void _accept_on_event_classes(trace_class_visitor& trace_class_visitor) const = 0;
- lttng::sessiond::trace::type::cuptr _context;
+ lttng::sessiond::trace::type::cuptr _packet_context;
+ lttng::sessiond::trace::type::cuptr _event_header;
+ lttng::sessiond::trace::type::cuptr _event_context;
};
} /* namespace trace */
#ifndef LTTNG_TRACE_CLASS_H
#define LTTNG_TRACE_CLASS_H
+#include "field.hpp"
+
#include <common/uuid.hpp>
namespace lttng {
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;
* to continue the traversal to the trace class' children.
*/
virtual void accept(trace_class_visitor& trace_class_visitor) const;
+ virtual lttng::sessiond::trace::type::cuptr get_packet_header() const = 0;
virtual ~trace_class() = default;
*
*/
-#include "clock-class.hpp"
#include "tsdl-trace-class-visitor.hpp"
+#include "clock-class.hpp"
#include <common/exception.hpp>
#include <common/format.hpp>
#include <common/make-unique.hpp>
#include <common/uuid.hpp>
+#include <vendor/optional.hpp>
+
+#include <algorithm>
#include <array>
#include <locale>
#include <queue>
#include <set>
+#include <stack>
namespace lst = lttng::sessiond::trace;
namespace tsdl = lttng::sessiond::tsdl;
* Although the CTF v1.8 specification recommends ignoring any leading underscore, Some readers,
* such as Babeltrace 1.x, expect special identifiers without a prepended underscore.
*/
-const std::set<std::string> safe_tsdl_identifiers = {"stream_id"};
+const std::set<std::string> safe_tsdl_identifiers = {
+ "stream_id",
+ "packet_size",
+ "content_size",
+ "id",
+ "v",
+ "timestamp",
+ "events_discarded",
+ "packet_seq_num",
+ "timestamp_begin",
+ "timestamp_end",
+ "cpu_id",
+ "magic",
+ "uuid",
+ "stream_instance_id"
+};
/*
* A previous implementation always prepended '_' to the identifiers in order to
class tsdl_field_visitor : public lttng::sessiond::trace::field_visitor,
public lttng::sessiond::trace::type_visitor {
public:
- tsdl_field_visitor(const lst::abi& abi, unsigned int indentation_level) :
- _indentation_level{indentation_level}, _trace_abi{abi}
+ tsdl_field_visitor(const lst::abi& abi,
+ unsigned int indentation_level,
+ const nonstd::optional<std::string>& in_default_clock_class_name =
+ nonstd::nullopt) :
+ _indentation_level{indentation_level},
+ _trace_abi{abi},
+ _bypass_identifier_escape{false},
+ _default_clock_class_name{in_default_clock_class_name ?
+ in_default_clock_class_name->c_str() :
+ nullptr}
{
}
* empty structure declaration is inserted when needed to express the aligment
* constraint. The name of this structure is generated using the field's name.
*/
- _escaped_current_field_name = escape_tsdl_identifier(field.name);
+ _current_field_name.push(_bypass_identifier_escape ?
+ field.name : escape_tsdl_identifier(field.name));
field._type->accept(*this);
_description += " ";
- _description += _escaped_current_field_name;
+ _description += _current_field_name.top();
+ _current_field_name.pop();
/*
* Some types requires suffixes to be appended (e.g. the length of arrays
}
_description += ";";
- _escaped_current_field_name.clear();
}
virtual void visit(const lst::integer_type& type) override final
_current_integer_encoding_override.reset();
}
+ if (std::find(type.roles_.begin(), type.roles_.end(),
+ lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP) !=
+ type.roles_.end() ||
+ std::find(type.roles_.begin(), type.roles_.end(),
+ lst::integer_type::role::
+ PACKET_END_DEFAULT_CLOCK_TIMESTAMP) !=
+ type.roles_.end()) {
+ LTTNG_ASSERT(_default_clock_class_name);
+ _description += fmt::format(
+ " map = clock.{}.value;", _default_clock_class_name);
+ }
+
_description += " }";
}
virtual void visit(const lst::static_length_array_type& type) override final
{
if (type.alignment != 0) {
- LTTNG_ASSERT(_escaped_current_field_name.size() > 0);
+ LTTNG_ASSERT(_current_field_name.size() > 0);
_description += fmt::format(
"struct {{ }} align({alignment}) {field_name}_padding;\n",
fmt::arg("alignment", type.alignment),
- fmt::arg("field_name", _escaped_current_field_name));
+ fmt::arg("field_name", _current_field_name.top()));
_description.resize(_description.size() + _indentation_level, '\t');
}
* could wrap nested sequences in structures, which
* would allow us to express alignment constraints.
*/
- LTTNG_ASSERT(_escaped_current_field_name.size() > 0);
+ LTTNG_ASSERT(_current_field_name.size() > 0);
_description += fmt::format(
"struct {{ }} align({alignment}) {field_name}_padding;\n",
fmt::arg("alignment", type.alignment),
- fmt::arg("field_name", _escaped_current_field_name));
+ fmt::arg("field_name", _current_field_name.top()));
_description.resize(_description.size() + _indentation_level, '\t');
}
type.element_type->accept(*this);
- _type_suffixes.emplace(fmt::format(
- "[{}]", escape_tsdl_identifier(type.length_field_name)));
+ _type_suffixes.emplace(fmt::format("[{}]",
+ _bypass_identifier_escape ?
+ type.length_field_name :
+ escape_tsdl_identifier(type.length_field_name)));
}
virtual void visit(const lst::static_length_blob_type& type) override final
virtual void visit(const lst::null_terminated_string_type& type) override final
{
- /* Defaults to UTF-8. */
+ /* Defaults to UTF-8. */
if (type.encoding_ == lst::null_terminated_string_type::encoding::ASCII) {
_description += "string { encoding = ASCII }";
} else {
_indentation_level++;
_description += "struct {";
+ const auto previous_bypass_identifier_escape = _bypass_identifier_escape;
+ _bypass_identifier_escape = false;
for (const auto& field : type._fields) {
_description += "\n";
_description.resize(_description.size() + _indentation_level, '\t');
field->accept(*this);
}
+ _bypass_identifier_escape = previous_bypass_identifier_escape;
+
_indentation_level--;
if (type._fields.size() != 0) {
_description += "\n";
_description.resize(_description.size() + _indentation_level, '\t');
}
- _description += "};";
+ _description += "}";
}
virtual void visit(const lst::variant_type& type) override final
{
if (type.alignment != 0) {
- LTTNG_ASSERT(_escaped_current_field_name.size() > 0);
+ LTTNG_ASSERT(_current_field_name.size() > 0);
_description += fmt::format(
"struct {{ }} align({alignment}) {field_name}_padding;\n",
fmt::arg("alignment", type.alignment),
- fmt::arg("field_name", _escaped_current_field_name));
+ fmt::arg("field_name", _current_field_name.top()));
_description.resize(_description.size() + _indentation_level, '\t');
}
_indentation_level++;
- _description += fmt::format("variant <{}> {\n", escape_tsdl_identifier(type.tag_name));
+ _description += fmt::format("variant <{}> {{\n",
+ _bypass_identifier_escape ?
+ type.tag_name :
+ escape_tsdl_identifier(type.tag_name));
- bool first_field = true;
+ /*
+ * The CTF 1.8 specification only recommends that implementations ignore
+ * leading underscores in field names. Both babeltrace 1 and 2 expect the
+ * variant choice and enumeration mapping name to match perfectly. Given that we
+ * don't have access to the tag in this context, we have to assume they match.
+ */
+ const auto previous_bypass_identifier_escape = _bypass_identifier_escape;
+ _bypass_identifier_escape = true;
for (const auto& field : type._choices) {
- if (!first_field) {
- _description += ",\n";
- }
-
_description.resize(_description.size() + _indentation_level, '\t');
field->accept(*this);
- first_field = false;
+ _description += fmt::format("\n", field->name);
}
- _description += "\n";
- _description.resize(_description.size() + _indentation_level, '\t');
- _description += "};";
+ _bypass_identifier_escape = previous_bypass_identifier_escape;
+
_indentation_level--;
+ _description.resize(_description.size() + _indentation_level, '\t');
+ _description += "}";
}
lst::type::cuptr create_character_type(enum lst::string_type::encoding encoding)
visit(*char_sequence);
}
- std::string _escaped_current_field_name;
+ std::stack<std::string> _current_field_name;
/*
* Encoding to specify for the next serialized integer type.
* Since the integer_type does not allow an encoding to be specified (it is a TSDL-specific
/* Description in TSDL format. */
std::string _description;
+
+ bool _bypass_identifier_escape;
+ const char *_default_clock_class_name;
};
} /* namespace */
tsdl::trace_class_visitor::trace_class_visitor(const lst::abi& trace_abi,
tsdl::append_metadata_fragment_function append_metadata_fragment) :
- _trace_abi{trace_abi}, _append_metadata_fragment(append_metadata_fragment)
+ _trace_abi{trace_abi},
+ _append_metadata_fragment(append_metadata_fragment)
{
}
void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::trace_class& trace_class)
{
+ tsdl_field_visitor packet_header_visitor(trace_class.abi, 1);
+
+ trace_class.get_packet_header()->accept(packet_header_visitor);
+
/* Declare type aliases, trace class, and packet header. */
auto trace_class_tsdl = fmt::format(
"/* CTF {ctf_major}.{ctf_minor} */\n\n"
- "typealias integer {{ size = 8; align = {uint8_t_alignment}; signed = false; }} := uint8_t;\n"
- "typealias integer {{ size = 16; align = {uint16_t_alignment}; signed = false; }} := uint16_t;\n"
- "typealias integer {{ size = 32; align = {uint32_t_alignment}; signed = false; }} := uint32_t;\n"
- "typealias integer {{ size = 64; align = {uint64_t_alignment}; signed = false; }} := uint64_t;\n"
- "typealias integer {{ size = {bits_per_long}; align = {long_alignment}; signed = false; }} := unsigned long;\n"
- "typealias integer {{ size = 5; align = 1; signed = false; }} := uint5_t;\n"
- "typealias integer {{ size = 27; align = 1; signed = false; }} := uint27_t;\n"
- "\n"
"trace {{\n"
" major = {ctf_major};\n"
" minor = {ctf_minor};\n"
" uuid = \"{uuid}\";\n"
" byte_order = {byte_order};\n"
- " packet.header := struct {{\n"
- " uint32_t magic;\n"
- " uint8_t uuid[16];\n"
- " uint32_t stream_id;\n"
- " uint64_t stream_instance_id;\n"
- " }};\n"
+ " packet.header := {packet_header_layout};\n"
"}};\n\n",
fmt::arg("ctf_major", ctf_spec_major),
fmt::arg("ctf_minor", ctf_spec_minor),
fmt::arg("bits_per_long", trace_class.abi.bits_per_long),
fmt::arg("uuid", lttng::utils::uuid_to_str(trace_class.uuid)),
fmt::arg("byte_order",
- trace_class.abi.byte_order == lst::byte_order::BIG_ENDIAN_ ?
- "be" :
- "le"));
+ trace_class.abi.byte_order == lst::byte_order::BIG_ENDIAN_ ? "be" : "le"),
+ fmt::arg("packet_header_layout", packet_header_visitor.get_description()));
/* Declare trace scope and type aliases. */
append_metadata_fragment(std::move(trace_class_tsdl));
" freq = {frequency};\n"
" offset = {offset};\n"
"}};\n"
- "\n"
- "typealias integer {{\n"
- " size = 27; align = 1; signed = false;\n"
- " map = clock.{name}.value;\n"
- "}} := uint27_clock_{name}_t;\n"
- "\n"
- "typealias integer {{\n"
- " size = 32; align = {uint32_t_alignment}; signed = false;\n"
- " map = clock.{name}.value;\n"
- "}} := uint32_clock_{name}_t;\n"
- "\n"
- "typealias integer {{\n"
- " size = 64; align = {uint64_t_alignment}; signed = false;\n"
- " map = clock.{name}.value;\n"
- "}} := uint64_clock_{name}_t;\n"
- "\n"
- "struct packet_context {{\n"
- " uint64_clock_{name}_t timestamp_begin;\n"
- " uint64_clock_{name}_t timestamp_end;\n"
- " uint64_t content_size;\n"
- " uint64_t packet_size;\n"
- " uint64_t packet_seq_num;\n"
- " unsigned long events_discarded;\n"
- " uint32_t cpu_id;\n"
- "}};\n"
- "\n"
- "struct event_header_compact {{\n"
- " enum : uint5_t {{ compact = 0 ... 30, extended = 31 }} id;\n"
- " variant <id> {{\n"
- " struct {{\n"
- " uint27_clock_{name}_t timestamp;\n"
- " }} compact;\n"
- " struct {{\n"
- " uint32_t id;\n"
- " uint64_clock_{name}_t timestamp;\n"
- " }} extended;\n"
- " }} v;\n"
- "}} align({uint32_t_alignment});\n"
- "\n"
- "struct event_header_large {{\n"
- " enum : uint16_t {{ compact = 0 ... 65534, extended = 65535 }} id;\n"
- " variant <id> {{\n"
- " struct {{\n"
- " uint32_clock_{name}_t timestamp;\n"
- " }} compact;\n"
- " struct {{\n"
- " uint32_t id;\n"
- " uint64_clock_{name}_t timestamp;\n"
- " }} extended;\n"
- " }} v;\n"
- "}} align({uint16_t_alignment});\n\n",
+ "\n",
fmt::arg("name", clock_class.name),
fmt::arg("uuid", uuid_str),
fmt::arg("description", clock_class.description),
fmt::arg("frequency", clock_class.frequency),
- fmt::arg("offset", clock_class.offset),
- fmt::arg("uint16_t_alignment", _trace_abi.uint16_t_alignment),
- fmt::arg("uint32_t_alignment", _trace_abi.uint32_t_alignment),
- fmt::arg("uint64_t_alignment", _trace_abi.uint64_t_alignment));
+ fmt::arg("offset", clock_class.offset));
append_metadata_fragment(std::move(clock_class_str));
}
void tsdl::trace_class_visitor::visit(const lttng::sessiond::trace::stream_class& stream_class)
{
- /* Declare stream. */
auto stream_class_str = fmt::format("stream {{\n"
- " id = {id};\n"
- " event.header := {header_type};\n"
- " packet.context := struct packet_context;\n",
- fmt::arg("id", stream_class.id),
- fmt::arg("header_type", stream_class.header_type_ == lst::stream_class::header_type::COMPACT ?
- "struct event_header_compact" :
- "struct event_header_large"));
+ " id = {};\n", stream_class.id);
- auto context_field_visitor = tsdl_field_visitor(_trace_abi, 1);
+ const auto *event_header = stream_class.get_event_header();
+ if (event_header) {
+ auto event_header_visitor = tsdl_field_visitor(
+ _trace_abi, 1, stream_class.default_clock_class_name);
- stream_class.get_context().accept(static_cast<lst::type_visitor&>(context_field_visitor));
+ event_header->accept(event_header_visitor);
+ stream_class_str += fmt::format(" event.header := {};\n",
+ event_header_visitor.get_description());
+ }
+
+ const auto *packet_context = stream_class.get_packet_context();
+ if (packet_context) {
+ auto packet_context_visitor = tsdl_field_visitor(
+ _trace_abi, 1, stream_class.default_clock_class_name);
+
+ packet_context->accept(packet_context_visitor);
+ stream_class_str += fmt::format(" packet.context := {};\n",
+ packet_context_visitor.get_description());
+ }
+
+ const auto *event_context = stream_class.get_event_context();
+ if (event_context) {
+ auto event_context_visitor = tsdl_field_visitor(_trace_abi, 1);
+
+ event_context->accept(event_context_visitor);
+ stream_class_str += fmt::format(" event.context := {};\n",
+ event_context_visitor.get_description());
+ }
- stream_class_str += fmt::format(" event.context := {}\n}};\n\n",
- context_field_visitor.get_description());
+ stream_class_str += "};\n\n";
append_metadata_fragment(stream_class_str);
}
event_class.payload->accept(static_cast<lst::type_visitor&>(payload_visitor));
event_class_str += fmt::format(
- " fields := {}\n}};\n\n", payload_visitor.get_description());
+ " fields := {};\n}};\n\n", payload_visitor.get_description());
append_metadata_fragment(event_class_str);
}
* that all apps provide the same typing for the context fields as a
* sanity check.
*/
- lst::type::cuptr context_fields = lttng::make_unique<lst::structure_type>(0,
- lsu::create_trace_fields_from_ust_ctl_fields(*locked_registry_session,
- ust_ctl_context_fields.get(), context_field_count));
+ try {
+ auto app_context_fields = lsu::create_trace_fields_from_ust_ctl_fields(
+ *locked_registry_session, ust_ctl_context_fields.get(),
+ context_field_count);
- if (!ust_reg_chan.is_registered()) {
- ust_reg_chan.set_context(std::move(context_fields));
- } else {
- /*
- * Validate that the context fields match between
- * registry and newcoming application.
- */
- if (ust_reg_chan.get_context() != *context_fields) {
- ERR("Registering application channel due to context field mismatch: pid = %d, sock = %d",
- app->pid, app->sock);
- ret_code = -EINVAL;
- goto reply;
+ if (!ust_reg_chan.is_registered()) {
+ lst::type::cuptr event_context = app_context_fields.size() ?
+ lttng::make_unique<lst::structure_type>(
+ 0, std::move(app_context_fields)) :
+ nullptr;
+
+ ust_reg_chan.set_event_context(std::move(event_context));
+ } else {
+ /*
+ * Validate that the context fields match between
+ * registry and newcoming application.
+ */
+ bool context_fields_match;
+ const auto *previous_event_context = ust_reg_chan.get_event_context();
+
+ if (!previous_event_context) {
+ context_fields_match = app_context_fields.size() == 0;
+ } else {
+ const lst::structure_type app_event_context_struct(
+ 0, std::move(app_context_fields));
+
+ context_fields_match = *previous_event_context ==
+ app_event_context_struct;
+ }
+
+ if (!context_fields_match) {
+ ERR("Registering application channel due to context field mismatch: pid = %d, sock = %d",
+ app->pid, app->sock);
+ ret_code = -EINVAL;
+ goto reply;
+ }
}
+ } catch (std::exception& ex) {
+ ERR("Failed to handle application context: %s", ex.what());
+ ret_code = -EINVAL;
+ goto reply;
}
reply:
lst::integer_type::reverse_byte_order(
session_attributes._native_trace_byte_order) :
session_attributes._native_trace_byte_order;
+ const auto signedness = enum_container_uctl_type->signedness ?
+ lst::integer_type::signedness::SIGNED :
+ lst::integer_type::signedness::UNSIGNED;
- if (enum_container_uctl_type->signedness) {
+ if (signedness == lst::integer_type::signedness::SIGNED) {
const auto& enum_registry = static_cast<const lsu::registry_signed_enum&>(
*session_attributes.get_registry_enum(
enumeration_name, enumeration_id));
#include <common/exception.hpp>
#include <common/hashtable/utils.hpp>
#include <common/make-unique-wrapper.hpp>
+#include <common/make-unique.hpp>
#include <common/urcu.hpp>
namespace lst = lttng::sessiond::trace;
no_match:
return 0;
}
+
+lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_class::header_type header_type)
+{
+ lst::structure_type::fields event_header_fields;
+
+ if (header_type == lst::stream_class::header_type::COMPACT) {
+ auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
+
+ enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30));
+ enum_mappings->emplace_back("extended");
+
+ lst::type::cuptr choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(1,
+ trace_abi.byte_order, 5, lst::integer_type::base::DECIMAL,
+ std::move(enum_mappings),
+ std::initializer_list<lst::integer_type::role>(
+ {lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
+
+ lst::variant_type::choices variant_choices;
+
+ lst::structure_type::fields compact_fields;
+ compact_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
+ lttng::make_unique<lst::integer_type>(1, trace_abi.byte_order, 27,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ DEFAULT_CLOCK_TIMESTAMP}))));
+
+ lst::type::cuptr compact = lttng::make_unique<lst::structure_type>(
+ 0, std::move(compact_fields));
+ variant_choices.emplace_back(lttng::make_unique<lst::field>("compact", std::move(compact)));
+
+ lst::structure_type::fields extended_fields;
+ extended_fields.emplace_back(lttng::make_unique<lst::field>("id",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint32_t_alignment,
+ trace_abi.byte_order, 32,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ EVENT_RECORD_CLASS_ID}))));
+ extended_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ DEFAULT_CLOCK_TIMESTAMP}))));
+
+ lst::type::cuptr extended = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
+ variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+
+ lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(
+ 0, "id", std::move(variant_choices));
+
+ event_header_fields.emplace_back(lttng::make_unique<lst::field>("id", std::move(choice_enum)));
+ event_header_fields.emplace_back(
+ lttng::make_unique<lst::field>("v", std::move(variant)));
+ } else {
+ auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
+
+ enum_mappings->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534));
+ enum_mappings->emplace_back("extended");
+
+ lst::type::cuptr choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
+ trace_abi.uint16_t_alignment, trace_abi.byte_order, 16,
+ lst::integer_type::base::DECIMAL, std::move(enum_mappings),
+ std::initializer_list<lst::integer_type::role>(
+ {lst::integer_type::role::EVENT_RECORD_CLASS_ID}));
+
+ lst::variant_type::choices variant_choices;
+
+ lst::structure_type::fields compact_fields;
+ compact_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint32_t_alignment,
+ trace_abi.byte_order, 32,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ DEFAULT_CLOCK_TIMESTAMP}))));
+
+ lst::type::cuptr compact = lttng::make_unique<lst::structure_type>(
+ 0, std::move(compact_fields));
+ variant_choices.emplace_back(
+ lttng::make_unique<lst::field>("compact", std::move(compact)));
+
+ lst::structure_type::fields extended_fields;
+ extended_fields.emplace_back(lttng::make_unique<lst::field>("id",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint32_t_alignment,
+ trace_abi.byte_order, 32,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ EVENT_RECORD_CLASS_ID}))));
+ extended_fields.emplace_back(lttng::make_unique<lst::field>("timestamp",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::
+ role>({lst::integer_type::role::
+ DEFAULT_CLOCK_TIMESTAMP}))));
+
+ lst::type::cuptr extended = lttng::make_unique<lst::structure_type>(0, std::move(extended_fields));
+ variant_choices.emplace_back(lttng::make_unique<lst::field>("extended", std::move(extended)));
+
+ lst::type::cuptr variant = lttng::make_unique<lst::variant_type>(
+ 0, "id", std::move(variant_choices));
+
+ event_header_fields.emplace_back(lttng::make_unique<lst::field>("id", std::move(choice_enum)));
+ event_header_fields.emplace_back(
+ lttng::make_unique<lst::field>("v", std::move(variant)));
+ }
+
+ return lttng::make_unique<lst::structure_type>(0, std::move(event_header_fields));
+}
+
+lst::type::cuptr create_packet_context(const lst::abi& trace_abi)
+{
+ lst::structure_type::fields packet_context_fields;
+
+ /* uint64_t timestamp_begin */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("timestamp_begin",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP}))));
+
+ /* uint64_t timestamp_end */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("timestamp_end",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP}))));
+
+ /* uint64_t content_size */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("content_size",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::PACKET_CONTENT_LENGTH}))));
+
+ /* uint64_t packet_size */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("packet_size",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::PACKET_TOTAL_LENGTH}))));
+
+ /* uint64_t packet_seq_num */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("packet_seq_num",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint64_t_alignment,
+ trace_abi.byte_order, 64,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::PACKET_SEQUENCE_NUMBER}))));
+
+ /* unsigned long events_discarded */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("events_discarded",
+ lttng::make_unique<lst::integer_type>(trace_abi.long_alignment,
+ trace_abi.byte_order, trace_abi.bits_per_long,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT}))));
+
+ /* uint32_t cpu_id */
+ packet_context_fields.emplace_back(lttng::make_unique<lst::field>("cpu_id",
+ lttng::make_unique<lst::integer_type>(trace_abi.uint32_t_alignment,
+ trace_abi.byte_order, 32,
+ lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL)));
+
+ return lttng::make_unique<lst::structure_type>(0, std::move(packet_context_fields));
+}
}; /* namespace */
lsu::registry_channel::registry_channel(unsigned int channel_id,
+ const lst::abi& trace_abi,
+ std::string in_default_clock_class_name,
lsu::registry_channel::registered_listener_fn channel_registered_listener,
lsu::registry_channel::event_added_listener_fn event_added_listener) :
- lst::stream_class(channel_id, lst::stream_class::header_type::LARGE),
+ lst::stream_class(channel_id,
+ lst::stream_class::header_type::LARGE,
+ std::move(in_default_clock_class_name)),
_key{-1ULL},
_consumer_key{-1ULL},
_next_event_id{0},
* channel object itself.
*/
_node = {};
+
+ _packet_context = create_packet_context(trace_abi);
+ _event_header = create_event_header(trace_abi, header_type_);
}
void lsu::registry_channel::add_event(
lttng_ht_destroy(_events);
}
-const lttng::sessiond::trace::type& lsu::registry_channel::get_context() const
+const lttng::sessiond::trace::type* lsu::registry_channel::get_event_context() const
{
LTTNG_ASSERT(_is_registered);
- return lst::stream_class::get_context();
+ return lst::stream_class::get_event_context();
}
-void lsu::registry_channel::set_context(lttng::sessiond::trace::type::cuptr context)
+void lsu::registry_channel::set_event_context(lttng::sessiond::trace::type::cuptr context)
{
/* Must only be set once, on the first channel registration provided by an application. */
- LTTNG_ASSERT(!_context);
- _context = std::move(context);
+ LTTNG_ASSERT(!_event_context);
+ _event_context = std::move(context);
}
bool lsu::registry_channel::is_registered() const
#define LTTNG_UST_REGISTRY_CHANNEL_H
#include "stream-class.hpp"
+#include "trace-class.hpp"
#include <common/hashtable/hashtable.hpp>
using event_added_listener_fn = std::function<void(const registry_channel&, const registry_event &)>;
registry_channel(uint32_t channel_id,
+ const lttng::sessiond::trace::abi& trace_abi,
+ std::string default_clock_class_name,
registered_listener_fn channel_registered_listener,
event_added_listener_fn new_event_listener);
void add_event(int session_objd,
uint32_t& out_event_id);
virtual ~registry_channel();
- virtual const lttng::sessiond::trace::type& get_context() const override final;
- void set_context(lttng::sessiond::trace::type::cuptr context);
+ virtual const lttng::sessiond::trace::type *get_event_context() const override final;
+ void set_event_context(lttng::sessiond::trace::type::cuptr context);
/* Channel was registered to at least one application. */
bool is_registered() const;
#include <fcntl.h>
#include <functional>
+#include <initializer_list>
#include <mutex>
#include <sstream>
#include <string>
lst::trace_class(in_abi, generate_uuid_or_throw()),
_root_shm_path{root_shm_path ? root_shm_path : ""},
_shm_path{shm_path ? shm_path : ""},
- _metadata_path{_shm_path.size() > 0 ?
- fmt::format("{}/metadata", _shm_path) : std::string("")},
+ _metadata_path{_shm_path.size() > 0 ? fmt::format("{}/metadata", _shm_path) :
+ std::string("")},
_uid{euid},
_gid{egid},
_app_tracer_version{.major = major, .minor = minor},
_tracing_id{tracing_id},
_clock{lttng::make_unique<lsu::clock_class>()},
- _metadata_generating_visitor{lttng::make_unique<ls::tsdl::trace_class_visitor>(abi,
- [this](const std::string& fragment) {
+ _metadata_generating_visitor{lttng::make_unique<ls::tsdl::trace_class_visitor>(
+ abi, [this](const std::string& fragment) {
_append_metadata_fragment(fragment);
})}
{
}
auto chan = new lsu::registry_channel(
- _get_next_channel_id(),
+ _get_next_channel_id(), abi, _clock->name,
/* Registered channel listener. */
[this](const lsu::registry_channel& registered_channel) {
/*
return lsu::registry_enum::const_rcu_protected_reference{*reg_enum, std::move(rcu_lock)};
}
+lst::type::cuptr lsu::registry_session::get_packet_header() const
+{
+ lst::structure_type::fields packet_header_fields;
+
+ /* uint32_t magic */
+ packet_header_fields.emplace_back(lttng::make_unique<lst::field>("magic",
+ lttng::make_unique<lst::integer_type>(abi.uint32_t_alignment,
+ abi.byte_order, 32, lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::HEXADECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::PACKET_MAGIC_NUMBER}))));
+
+ /* uuid */
+ packet_header_fields.emplace_back(lttng::make_unique<lst::field>("uuid",
+ lttng::make_unique<lst::static_length_blob_type>(0, 16,
+ std::initializer_list<lst::static_length_blob_type::role>({lst::static_length_blob_type::role::TRACE_CLASS_UUID}))));
+
+ /* uint32_t stream_id */
+ packet_header_fields.emplace_back(lttng::make_unique<lst::field>("stream_id",
+ lttng::make_unique<lst::integer_type>(abi.uint32_t_alignment,
+ abi.byte_order, 32, lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::DATA_STREAM_CLASS_ID}))));
+
+ /* uint64_t stream_instance_id */
+ packet_header_fields.emplace_back(lttng::make_unique<lst::field>("stream_instance_id",
+ lttng::make_unique<lst::integer_type>(abi.uint64_t_alignment,
+ abi.byte_order, 64, lst::integer_type::signedness::UNSIGNED,
+ lst::integer_type::base::DECIMAL,
+ std::initializer_list<lst::integer_type::role>({lst::integer_type::role::DATA_STREAM_ID}))));
+
+ return lttng::make_unique<lst::structure_type>(0, std::move(packet_header_fields));
+}
+
/*
* Lookup enumeration by name and comparing enumeration entries.
* Needs to be called from RCU read-side critical section.
void regenerate_metadata();
virtual ~registry_session();
+ virtual lttng::sessiond::trace::type::cuptr get_packet_header() const override;
+
/*
* With multiple writers and readers, use this lock to access
* the registry. Can nest within the ust app session lock.