2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
9 #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
,
83 lst::stream_class::header_type header_type
)
85 lst::structure_type::fields event_header_fields
;
87 if (header_type
== lst::stream_class::header_type::COMPACT
) {
88 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
89 lst::unsigned_enumeration_type::mapping compact_mapping
{
90 "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)
92 lst::unsigned_enumeration_type::mapping extended_mapping
{ "extended", 31 };
94 enum_mappings
->emplace_back(compact_mapping
);
95 enum_mappings
->emplace_back(extended_mapping
);
97 lst::type::cuptr choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
101 lst::integer_type::base::DECIMAL
,
102 std::move(enum_mappings
),
103 std::initializer_list
<lst::integer_type::role
>(
104 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
107 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::choices
110 lst::structure_type::fields compact_fields
;
111 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>(
113 lttng::make_unique
<lst::integer_type
>(
115 trace_abi
.byte_order
,
117 lst::integer_type::signedness::UNSIGNED
,
118 lst::integer_type::base::DECIMAL
,
119 std::initializer_list
<lst::integer_type::role
>(
120 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
123 lttng::make_unique
<lst::structure_type
>(0, std::move(compact_fields
));
124 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
126 lst::structure_type::fields extended_fields
;
127 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
129 lttng::make_unique
<lst::integer_type
>(
130 trace_abi
.uint32_t_alignment
,
131 trace_abi
.byte_order
,
133 lst::integer_type::signedness::UNSIGNED
,
134 lst::integer_type::base::DECIMAL
,
135 std::initializer_list
<lst::integer_type::role
>(
136 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}))));
137 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
139 lttng::make_unique
<lst::integer_type
>(
140 trace_abi
.uint64_t_alignment
,
141 trace_abi
.byte_order
,
143 lst::integer_type::signedness::UNSIGNED
,
144 lst::integer_type::base::DECIMAL
,
145 std::initializer_list
<lst::integer_type::role
>(
146 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
148 lst::type::cuptr extended_type
=
149 lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
150 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
152 auto variant
= lttng::make_unique
<lst::variant_type
<
153 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
155 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
157 std::move(variant_choices
));
159 event_header_fields
.emplace_back(
160 lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
161 event_header_fields
.emplace_back(
162 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
164 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
165 lst::unsigned_enumeration_type::mapping compact_mapping
{
166 "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534)
168 lst::unsigned_enumeration_type::mapping extended_mapping
{ "extended", 65535 };
169 enum_mappings
->emplace_back(compact_mapping
);
170 enum_mappings
->emplace_back(extended_mapping
);
172 auto choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
173 trace_abi
.uint16_t_alignment
,
174 trace_abi
.byte_order
,
176 lst::integer_type::base::DECIMAL
,
177 std::move(enum_mappings
),
178 std::initializer_list
<lst::integer_type::role
>(
179 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
182 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::choices
185 lst::structure_type::fields compact_fields
;
186 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>(
188 lttng::make_unique
<lst::integer_type
>(
189 trace_abi
.uint32_t_alignment
,
190 trace_abi
.byte_order
,
192 lst::integer_type::signedness::UNSIGNED
,
193 lst::integer_type::base::DECIMAL
,
194 std::initializer_list
<lst::integer_type::role
>(
195 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
197 lst::type::cuptr compact_type
=
198 lttng::make_unique
<lst::structure_type
>(0, std::move(compact_fields
));
199 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
201 lst::structure_type::fields extended_fields
;
202 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
204 lttng::make_unique
<lst::integer_type
>(
205 trace_abi
.uint32_t_alignment
,
206 trace_abi
.byte_order
,
208 lst::integer_type::signedness::UNSIGNED
,
209 lst::integer_type::base::DECIMAL
,
210 std::initializer_list
<lst::integer_type::role
>(
211 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}))));
212 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
214 lttng::make_unique
<lst::integer_type
>(
215 trace_abi
.uint64_t_alignment
,
216 trace_abi
.byte_order
,
218 lst::integer_type::signedness::UNSIGNED
,
219 lst::integer_type::base::DECIMAL
,
220 std::initializer_list
<lst::integer_type::role
>(
221 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
224 lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
225 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
227 auto variant
= lttng::make_unique
<lst::variant_type
<
228 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
230 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
232 std::move(variant_choices
));
234 event_header_fields
.emplace_back(
235 lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
236 event_header_fields
.emplace_back(
237 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
240 return lttng::make_unique
<lst::structure_type
>(0, std::move(event_header_fields
));
243 lst::type::cuptr
create_packet_context(const lst::abi
& trace_abi
)
245 lst::structure_type::fields packet_context_fields
;
247 /* uint64_t timestamp_begin */
248 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
250 lttng::make_unique
<lst::integer_type
>(
251 trace_abi
.uint64_t_alignment
,
252 trace_abi
.byte_order
,
254 lst::integer_type::signedness::UNSIGNED
,
255 lst::integer_type::base::DECIMAL
,
256 std::initializer_list
<lst::integer_type::role
>(
257 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
259 /* uint64_t timestamp_end */
260 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
262 lttng::make_unique
<lst::integer_type
>(
263 trace_abi
.uint64_t_alignment
,
264 trace_abi
.byte_order
,
266 lst::integer_type::signedness::UNSIGNED
,
267 lst::integer_type::base::DECIMAL
,
268 std::initializer_list
<lst::integer_type::role
>(
269 { lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP
}))));
271 /* uint64_t content_size */
272 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
274 lttng::make_unique
<lst::integer_type
>(
275 trace_abi
.uint64_t_alignment
,
276 trace_abi
.byte_order
,
278 lst::integer_type::signedness::UNSIGNED
,
279 lst::integer_type::base::DECIMAL
,
280 std::initializer_list
<lst::integer_type::role
>(
281 { lst::integer_type::role::PACKET_CONTENT_LENGTH
}))));
283 /* uint64_t packet_size */
284 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
286 lttng::make_unique
<lst::integer_type
>(
287 trace_abi
.uint64_t_alignment
,
288 trace_abi
.byte_order
,
290 lst::integer_type::signedness::UNSIGNED
,
291 lst::integer_type::base::DECIMAL
,
292 std::initializer_list
<lst::integer_type::role
>(
293 { lst::integer_type::role::PACKET_TOTAL_LENGTH
}))));
295 /* uint64_t packet_seq_num */
296 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
298 lttng::make_unique
<lst::integer_type
>(
299 trace_abi
.uint64_t_alignment
,
300 trace_abi
.byte_order
,
302 lst::integer_type::signedness::UNSIGNED
,
303 lst::integer_type::base::DECIMAL
,
304 std::initializer_list
<lst::integer_type::role
>(
305 { lst::integer_type::role::PACKET_SEQUENCE_NUMBER
}))));
307 /* unsigned long events_discarded */
308 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
310 lttng::make_unique
<lst::integer_type
>(
311 trace_abi
.long_alignment
,
312 trace_abi
.byte_order
,
313 trace_abi
.bits_per_long
,
314 lst::integer_type::signedness::UNSIGNED
,
315 lst::integer_type::base::DECIMAL
,
316 std::initializer_list
<lst::integer_type::role
>(
317 { lst::integer_type::role::
318 DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT
}))));
320 /* uint32_t cpu_id */
321 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
323 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
324 trace_abi
.byte_order
,
326 lst::integer_type::signedness::UNSIGNED
,
327 lst::integer_type::base::DECIMAL
)));
329 return lttng::make_unique
<lst::structure_type
>(0, std::move(packet_context_fields
));
333 lsu::registry_channel::registry_channel(
334 unsigned int channel_id
,
335 const lst::abi
& trace_abi
,
336 std::string in_default_clock_class_name
,
337 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
338 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
339 lst::stream_class(channel_id
,
340 lst::stream_class::header_type::LARGE
,
341 std::move(in_default_clock_class_name
)),
343 _consumer_key
{ -1ULL },
345 _is_registered_listener
{ channel_registered_listener
},
346 _event_added_listener
{ event_added_listener
},
347 _is_registered
{ false }
349 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
351 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
354 /* Set custom match function. */
355 _events
->match_fct
= ht_match_event
;
356 _events
->hash_fct
= ht_hash_event
;
360 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
361 * channel object itself.
365 _packet_context
= create_packet_context(trace_abi
);
366 _event_header
= create_event_header(trace_abi
, header_type_
);
369 void lsu::registry_channel::add_event(int session_objd
,
372 std::string signature
,
373 std::vector
<lst::field::cuptr
> event_fields
,
375 nonstd::optional
<std::string
> model_emf_uri
,
376 lttng_buffer_type buffer_type
,
378 uint32_t& out_event_id
)
381 struct cds_lfht_node
*nptr
;
382 lttng::urcu::read_lock_guard read_lock_guard
;
385 * This should not happen but since it comes from the UST tracer, an
386 * external party, don't assert and simply validate values.
388 if (session_objd
< 0) {
389 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
390 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
395 if (channel_objd
< 0) {
396 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
397 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
402 /* Check if we've reached the maximum possible id. */
403 if (is_max_event_id(_next_event_id
)) {
404 LTTNG_THROW_ERROR(fmt::format(
405 "Failed to allocate new event id (id would overflow): app = {}", app
));
408 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
409 new lsu::registry_event(_next_event_id
,
414 std::move(signature
),
415 std::move(event_fields
),
417 std::move(model_emf_uri
)));
419 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event
).c_str());
422 * This is an add unique with a custom match function for event. The node
423 * are matched using the event name and signature.
425 nptr
= cds_lfht_add_unique(_events
->ht
,
426 _events
->hash_fct(event
.get(), lttng_ht_seed
),
430 if (nptr
!= &event
->_node
) {
431 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
433 * This is normal, we just have to send the event id of the
436 const auto existing_event
= lttng::utils::container_of(
437 nptr
, <tng::sessiond::ust::registry_event::_node
);
438 event_id
= existing_event
->id
;
440 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
441 "UST registry create event add unique failed for event: event = {}",
445 const auto& event_ref
= *event
;
447 /* Ownership transferred to _events hash table. */
450 /* Request next event id if the node was successfully added. */
451 event_id
= event_ref
.id
;
454 * Only increment the next id here since we don't want to waste an ID when the event
455 * matches an existing one.
458 _event_added_listener(*this, event_ref
);
461 out_event_id
= event_id
;
464 lsu::registry_channel::~registry_channel()
466 lttng_ht_destroy(_events
);
469 const lttng::sessiond::trace::type
*lsu::registry_channel::event_context() const
471 LTTNG_ASSERT(_is_registered
);
472 return lst::stream_class::event_context();
475 void lsu::registry_channel::event_context(lttng::sessiond::trace::type::cuptr context
)
477 /* Must only be set once, on the first channel registration provided by an application. */
478 LTTNG_ASSERT(!_event_context
);
479 _event_context
= std::move(context
);
482 bool lsu::registry_channel::is_registered() const
484 return _is_registered
;
487 void lsu::registry_channel::set_as_registered()
489 if (!_is_registered
) {
490 _is_registered
= true;
491 _is_registered_listener(*this);
495 void lsu::registry_channel::_accept_on_event_classes(
496 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
498 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes
;
501 lttng::urcu::read_lock_guard read_lock_guard
;
502 struct lttng_ht_iter iter
;
503 const lttng::sessiond::ust::registry_event
*event
;
506 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
507 cds_lfht_for_each_entry (_events
->ht
, &iter
.iter
, event
, _node
) {
508 sorted_event_classes
.emplace_back(event
);
513 std::sort(sorted_event_classes
.begin(),
514 sorted_event_classes
.end(),
515 [](const lttng::sessiond::ust::registry_event
*a
,
516 const lttng::sessiond::ust::registry_event
*b
) { return a
->id
< b
->id
; });
518 for (const auto event
: sorted_event_classes
) {
519 event
->accept(visitor
);