2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
8 #include "ust-registry-channel.hpp"
10 #include "ust-registry-event.hpp"
12 #include <common/error.hpp>
13 #include <common/exception.hpp>
14 #include <common/hashtable/utils.hpp>
15 #include <common/make-unique-wrapper.hpp>
16 #include <common/make-unique.hpp>
17 #include <common/urcu.hpp>
19 namespace lst
= lttng::sessiond::trace
;
20 namespace lsu
= lttng::sessiond::ust
;
23 bool is_max_event_id(uint32_t id
)
25 return id
== UINT32_MAX
;
28 unsigned long ht_hash_event(const void *_key
, unsigned long seed
)
31 const lttng::sessiond::ust::registry_event
*key
=
32 (lttng::sessiond::ust::registry_event
*) _key
;
36 hashed_key
= (uint64_t) hash_key_str(key
->name
.c_str(), seed
);
38 return hash_key_u64(&hashed_key
, seed
);
42 * Hash table match function for event in the registry.
44 int ht_match_event(struct cds_lfht_node
*node
, const void *_key
)
46 const lttng::sessiond::ust::registry_event
*key
;
47 lttng::sessiond::ust::registry_event
*event
;
52 event
= lttng::utils::container_of(node
, <tng::sessiond::ust::registry_event::_node
);
53 key
= (lttng::sessiond::ust::registry_event
*) _key
;
55 /* It has to be a perfect match. First, compare the event names. */
56 if (event
->name
!= key
->name
) {
60 /* Compare log levels. */
61 if (event
->log_level
!= key
->log_level
) {
65 /* Compare the arrays of fields. */
66 if (*event
->payload
!= *key
->payload
) {
70 /* Compare model URI. */
71 if (event
->model_emf_uri
!= key
->model_emf_uri
) {
82 lst::type::cuptr
create_event_header(const lst::abi
& trace_abi
, lst::stream_class::header_type header_type
)
84 lst::structure_type::fields event_header_fields
;
86 if (header_type
== lst::stream_class::header_type::COMPACT
) {
87 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
88 lst::unsigned_enumeration_type::mapping compact_mapping
{
89 "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)};
90 lst::unsigned_enumeration_type::mapping extended_mapping
{"extended", 31};
92 enum_mappings
->emplace_back(compact_mapping
);
93 enum_mappings
->emplace_back(extended_mapping
);
95 lst::type::cuptr choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(1,
96 trace_abi
.byte_order
, 5, lst::integer_type::base::DECIMAL
,
97 std::move(enum_mappings
),
98 std::initializer_list
<lst::integer_type::role
>(
99 {lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
101 lst::variant_type
<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::
102 choices variant_choices
;
104 lst::structure_type::fields compact_fields
;
105 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
106 lttng::make_unique
<lst::integer_type
>(1, trace_abi
.byte_order
, 27,
107 lst::integer_type::signedness::UNSIGNED
,
108 lst::integer_type::base::DECIMAL
,
109 std::initializer_list
<lst::integer_type::
110 role
>({lst::integer_type::role::
111 DEFAULT_CLOCK_TIMESTAMP
}))));
113 auto compact_type
= lttng::make_unique
<lst::structure_type
>(
114 0, std::move(compact_fields
));
115 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
117 lst::structure_type::fields extended_fields
;
118 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("id",
119 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
120 trace_abi
.byte_order
, 32,
121 lst::integer_type::signedness::UNSIGNED
,
122 lst::integer_type::base::DECIMAL
,
123 std::initializer_list
<lst::integer_type::
124 role
>({lst::integer_type::role::
125 EVENT_RECORD_CLASS_ID
}))));
126 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
127 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
128 trace_abi
.byte_order
, 64,
129 lst::integer_type::signedness::UNSIGNED
,
130 lst::integer_type::base::DECIMAL
,
131 std::initializer_list
<lst::integer_type::
132 role
>({lst::integer_type::role::
133 DEFAULT_CLOCK_TIMESTAMP
}))));
135 lst::type::cuptr extended_type
= lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
136 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
138 auto variant
= lttng::make_unique
<lst::variant_type
<
139 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
141 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
143 std::move(variant_choices
));
145 event_header_fields
.emplace_back(lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
146 event_header_fields
.emplace_back(
147 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
149 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
150 lst::unsigned_enumeration_type::mapping compact_mapping
{"compact",
151 lst::unsigned_enumeration_type::mapping::range_t(0, 65534)};
152 lst::unsigned_enumeration_type::mapping extended_mapping
{"extended", 65535};
153 enum_mappings
->emplace_back(compact_mapping
);
154 enum_mappings
->emplace_back(extended_mapping
);
156 auto choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
157 trace_abi
.uint16_t_alignment
, trace_abi
.byte_order
, 16,
158 lst::integer_type::base::DECIMAL
, std::move(enum_mappings
),
159 std::initializer_list
<lst::integer_type::role
>(
160 {lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
162 lst::variant_type
<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::
163 choices variant_choices
;
165 lst::structure_type::fields compact_fields
;
166 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
167 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
168 trace_abi
.byte_order
, 32,
169 lst::integer_type::signedness::UNSIGNED
,
170 lst::integer_type::base::DECIMAL
,
171 std::initializer_list
<lst::integer_type::
172 role
>({lst::integer_type::role::
173 DEFAULT_CLOCK_TIMESTAMP
}))));
175 lst::type::cuptr compact_type
= lttng::make_unique
<lst::structure_type
>(
176 0, std::move(compact_fields
));
177 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
179 lst::structure_type::fields extended_fields
;
180 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("id",
181 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
182 trace_abi
.byte_order
, 32,
183 lst::integer_type::signedness::UNSIGNED
,
184 lst::integer_type::base::DECIMAL
,
185 std::initializer_list
<lst::integer_type::
186 role
>({lst::integer_type::role::
187 EVENT_RECORD_CLASS_ID
}))));
188 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
189 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
190 trace_abi
.byte_order
, 64,
191 lst::integer_type::signedness::UNSIGNED
,
192 lst::integer_type::base::DECIMAL
,
193 std::initializer_list
<lst::integer_type::
194 role
>({lst::integer_type::role::
195 DEFAULT_CLOCK_TIMESTAMP
}))));
197 auto extended_type
= lttng::make_unique
<lst::structure_type
>(
198 0, std::move(extended_fields
));
199 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
201 auto variant
= lttng::make_unique
<lst::variant_type
<
202 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
204 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
206 std::move(variant_choices
));
208 event_header_fields
.emplace_back(
209 lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
210 event_header_fields
.emplace_back(
211 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
214 return lttng::make_unique
<lst::structure_type
>(0, std::move(event_header_fields
));
217 lst::type::cuptr
create_packet_context(const lst::abi
& trace_abi
)
219 lst::structure_type::fields packet_context_fields
;
221 /* uint64_t timestamp_begin */
222 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp_begin",
223 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
224 trace_abi
.byte_order
, 64,
225 lst::integer_type::signedness::UNSIGNED
,
226 lst::integer_type::base::DECIMAL
,
227 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
229 /* uint64_t timestamp_end */
230 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp_end",
231 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
232 trace_abi
.byte_order
, 64,
233 lst::integer_type::signedness::UNSIGNED
,
234 lst::integer_type::base::DECIMAL
,
235 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP
}))));
237 /* uint64_t content_size */
238 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("content_size",
239 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
240 trace_abi
.byte_order
, 64,
241 lst::integer_type::signedness::UNSIGNED
,
242 lst::integer_type::base::DECIMAL
,
243 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_CONTENT_LENGTH
}))));
245 /* uint64_t packet_size */
246 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("packet_size",
247 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
248 trace_abi
.byte_order
, 64,
249 lst::integer_type::signedness::UNSIGNED
,
250 lst::integer_type::base::DECIMAL
,
251 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_TOTAL_LENGTH
}))));
253 /* uint64_t packet_seq_num */
254 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("packet_seq_num",
255 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
256 trace_abi
.byte_order
, 64,
257 lst::integer_type::signedness::UNSIGNED
,
258 lst::integer_type::base::DECIMAL
,
259 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_SEQUENCE_NUMBER
}))));
261 /* unsigned long events_discarded */
262 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("events_discarded",
263 lttng::make_unique
<lst::integer_type
>(trace_abi
.long_alignment
,
264 trace_abi
.byte_order
, trace_abi
.bits_per_long
,
265 lst::integer_type::signedness::UNSIGNED
,
266 lst::integer_type::base::DECIMAL
,
267 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT
}))));
269 /* uint32_t cpu_id */
270 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("cpu_id",
271 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
272 trace_abi
.byte_order
, 32,
273 lst::integer_type::signedness::UNSIGNED
,
274 lst::integer_type::base::DECIMAL
)));
276 return lttng::make_unique
<lst::structure_type
>(0, std::move(packet_context_fields
));
280 lsu::registry_channel::registry_channel(unsigned int channel_id
,
281 const lst::abi
& trace_abi
,
282 std::string in_default_clock_class_name
,
283 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
284 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
285 lst::stream_class(channel_id
,
286 lst::stream_class::header_type::LARGE
,
287 std::move(in_default_clock_class_name
)),
289 _consumer_key
{-1ULL},
291 _is_registered_listener
{channel_registered_listener
},
292 _event_added_listener
{event_added_listener
},
293 _is_registered
{false}
295 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
297 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
300 /* Set custom match function. */
301 _events
->match_fct
= ht_match_event
;
302 _events
->hash_fct
= ht_hash_event
;
306 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
307 * channel object itself.
311 _packet_context
= create_packet_context(trace_abi
);
312 _event_header
= create_event_header(trace_abi
, header_type_
);
315 void lsu::registry_channel::add_event(
319 std::string signature
,
320 std::vector
<lst::field::cuptr
> event_fields
,
322 nonstd::optional
<std::string
> model_emf_uri
,
323 lttng_buffer_type buffer_type
,
325 uint32_t& out_event_id
)
328 struct cds_lfht_node
*nptr
;
329 lttng::urcu::read_lock_guard read_lock_guard
;
332 * This should not happen but since it comes from the UST tracer, an
333 * external party, don't assert and simply validate values.
335 if (session_objd
< 0) {
336 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
337 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
341 if (channel_objd
< 0) {
342 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
343 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
347 /* Check if we've reached the maximum possible id. */
348 if (is_max_event_id(_next_event_id
)) {
349 LTTNG_THROW_ERROR(fmt::format(
350 "Failed to allocate new event id (id would overflow): app = {}",
354 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
355 new lsu::registry_event(_next_event_id
, id
, session_objd
, channel_objd
,
356 std::move(name
), std::move(signature
),
357 std::move(event_fields
), loglevel_value
,
358 std::move(model_emf_uri
)));
360 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event
).c_str());
363 * This is an add unique with a custom match function for event. The node
364 * are matched using the event name and signature.
366 nptr
= cds_lfht_add_unique(_events
->ht
, _events
->hash_fct(event
.get(), lttng_ht_seed
),
367 _events
->match_fct
, event
.get(), &event
->_node
);
368 if (nptr
!= &event
->_node
) {
369 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
371 * This is normal, we just have to send the event id of the
374 const auto existing_event
= lttng::utils::container_of(
375 nptr
, <tng::sessiond::ust::registry_event::_node
);
376 event_id
= existing_event
->id
;
378 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
379 "UST registry create event add unique failed for event: event = {}",
383 const auto& event_ref
= *event
;
385 /* Ownership transferred to _events hash table. */
388 /* Request next event id if the node was successfully added. */
389 event_id
= event_ref
.id
;
392 * Only increment the next id here since we don't want to waste an ID when the event
393 * matches an existing one.
396 _event_added_listener(*this, event_ref
);
399 out_event_id
= event_id
;
402 lsu::registry_channel::~registry_channel()
404 lttng_ht_destroy(_events
);
407 const lttng::sessiond::trace::type
* lsu::registry_channel::get_event_context() const
409 LTTNG_ASSERT(_is_registered
);
410 return lst::stream_class::get_event_context();
413 void lsu::registry_channel::set_event_context(lttng::sessiond::trace::type::cuptr context
)
415 /* Must only be set once, on the first channel registration provided by an application. */
416 LTTNG_ASSERT(!_event_context
);
417 _event_context
= std::move(context
);
420 bool lsu::registry_channel::is_registered() const
422 return _is_registered
;
425 void lsu::registry_channel::set_as_registered()
427 if (!_is_registered
) {
428 _is_registered
= true;
429 _is_registered_listener(*this);
433 void lsu::registry_channel::_accept_on_event_classes(
434 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
436 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes
;
439 lttng::urcu::read_lock_guard read_lock_guard
;
440 struct lttng_ht_iter iter
;
441 const lttng::sessiond::ust::registry_event
*event
;
444 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
445 cds_lfht_for_each_entry(_events
->ht
, &iter
.iter
, event
, _node
) {
446 sorted_event_classes
.emplace_back(event
);
451 std::sort(sorted_event_classes
.begin(), sorted_event_classes
.end(),
452 [](const lttng::sessiond::ust::registry_event
*a
,
453 const lttng::sessiond::ust::registry_event
*b
) {
454 return a
->id
< b
->id
;
457 for (const auto event
: sorted_event_classes
) {
458 event
->accept(visitor
);