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>
21 namespace lst
= lttng::sessiond::trace
;
22 namespace lsu
= lttng::sessiond::ust
;
25 bool is_max_event_id(lttng::sessiond::ust::event_id id
)
27 return id
== UINT32_MAX
;
30 unsigned long ht_hash_event(const void *_key
, unsigned long seed
)
33 const lttng::sessiond::ust::registry_event
*key
=
34 (lttng::sessiond::ust::registry_event
*) _key
;
38 hashed_key
= (uint64_t) hash_key_str(key
->name
.c_str(), seed
);
40 return hash_key_u64(&hashed_key
, seed
);
44 * Hash table match function for event in the registry.
46 int ht_match_event(struct cds_lfht_node
*node
, const void *_key
)
48 const lttng::sessiond::ust::registry_event
*key
;
49 lttng::sessiond::ust::registry_event
*event
;
54 event
= lttng::utils::container_of(node
, <tng::sessiond::ust::registry_event::_node
);
55 key
= (lttng::sessiond::ust::registry_event
*) _key
;
57 /* It has to be a perfect match. First, compare the event names. */
58 if (event
->name
!= key
->name
) {
62 /* Compare log levels. */
63 if (event
->log_level
!= key
->log_level
) {
67 /* Compare the arrays of fields. */
68 if (*event
->payload
!= *key
->payload
) {
72 /* Compare model URI. */
73 if (event
->model_emf_uri
!= key
->model_emf_uri
) {
84 lst::type::cuptr
create_event_header(const lst::abi
& trace_abi
,
85 lst::stream_class::header_type header_type
)
87 lst::structure_type::fields event_header_fields
;
89 if (header_type
== lst::stream_class::header_type::COMPACT
) {
90 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
91 lst::unsigned_enumeration_type::mapping compact_mapping
{
92 "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30)
94 lst::unsigned_enumeration_type::mapping extended_mapping
{ "extended", 31 };
96 enum_mappings
->emplace_back(compact_mapping
);
97 enum_mappings
->emplace_back(extended_mapping
);
99 lst::type::cuptr choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
101 trace_abi
.byte_order
,
103 lst::integer_type::base::DECIMAL
,
104 std::move(enum_mappings
),
105 std::initializer_list
<lst::integer_type::role
>(
106 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
109 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::choices
112 lst::structure_type::fields compact_fields
;
113 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>(
115 lttng::make_unique
<lst::integer_type
>(
117 trace_abi
.byte_order
,
119 lst::integer_type::signedness::UNSIGNED
,
120 lst::integer_type::base::DECIMAL
,
121 std::initializer_list
<lst::integer_type::role
>(
122 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
125 lttng::make_unique
<lst::structure_type
>(0, std::move(compact_fields
));
126 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
128 lst::structure_type::fields extended_fields
;
129 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
131 lttng::make_unique
<lst::integer_type
>(
132 trace_abi
.uint32_t_alignment
,
133 trace_abi
.byte_order
,
135 lst::integer_type::signedness::UNSIGNED
,
136 lst::integer_type::base::DECIMAL
,
137 std::initializer_list
<lst::integer_type::role
>(
138 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}))));
139 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
141 lttng::make_unique
<lst::integer_type
>(
142 trace_abi
.uint64_t_alignment
,
143 trace_abi
.byte_order
,
145 lst::integer_type::signedness::UNSIGNED
,
146 lst::integer_type::base::DECIMAL
,
147 std::initializer_list
<lst::integer_type::role
>(
148 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
150 lst::type::cuptr extended_type
=
151 lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
152 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
154 auto variant
= lttng::make_unique
<lst::variant_type
<
155 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
157 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
159 std::move(variant_choices
));
161 event_header_fields
.emplace_back(
162 lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
163 event_header_fields
.emplace_back(
164 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
166 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
167 lst::unsigned_enumeration_type::mapping compact_mapping
{
168 "compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534)
170 lst::unsigned_enumeration_type::mapping extended_mapping
{ "extended", 65535 };
171 enum_mappings
->emplace_back(compact_mapping
);
172 enum_mappings
->emplace_back(extended_mapping
);
174 auto choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
175 trace_abi
.uint16_t_alignment
,
176 trace_abi
.byte_order
,
178 lst::integer_type::base::DECIMAL
,
179 std::move(enum_mappings
),
180 std::initializer_list
<lst::integer_type::role
>(
181 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
184 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::choices
187 lst::structure_type::fields compact_fields
;
188 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>(
190 lttng::make_unique
<lst::integer_type
>(
191 trace_abi
.uint32_t_alignment
,
192 trace_abi
.byte_order
,
194 lst::integer_type::signedness::UNSIGNED
,
195 lst::integer_type::base::DECIMAL
,
196 std::initializer_list
<lst::integer_type::role
>(
197 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
199 lst::type::cuptr compact_type
=
200 lttng::make_unique
<lst::structure_type
>(0, std::move(compact_fields
));
201 variant_choices
.emplace_back(std::move(compact_mapping
), std::move(compact_type
));
203 lst::structure_type::fields extended_fields
;
204 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
206 lttng::make_unique
<lst::integer_type
>(
207 trace_abi
.uint32_t_alignment
,
208 trace_abi
.byte_order
,
210 lst::integer_type::signedness::UNSIGNED
,
211 lst::integer_type::base::DECIMAL
,
212 std::initializer_list
<lst::integer_type::role
>(
213 { lst::integer_type::role::EVENT_RECORD_CLASS_ID
}))));
214 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>(
216 lttng::make_unique
<lst::integer_type
>(
217 trace_abi
.uint64_t_alignment
,
218 trace_abi
.byte_order
,
220 lst::integer_type::signedness::UNSIGNED
,
221 lst::integer_type::base::DECIMAL
,
222 std::initializer_list
<lst::integer_type::role
>(
223 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
226 lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
227 variant_choices
.emplace_back(std::move(extended_mapping
), std::move(extended_type
));
229 auto variant
= lttng::make_unique
<lst::variant_type
<
230 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>>(
232 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
234 std::move(variant_choices
));
236 event_header_fields
.emplace_back(
237 lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
238 event_header_fields
.emplace_back(
239 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
242 return lttng::make_unique
<lst::structure_type
>(0, std::move(event_header_fields
));
245 lst::type::cuptr
create_packet_context(const lst::abi
& trace_abi
)
247 lst::structure_type::fields packet_context_fields
;
249 /* uint64_t timestamp_begin */
250 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
252 lttng::make_unique
<lst::integer_type
>(
253 trace_abi
.uint64_t_alignment
,
254 trace_abi
.byte_order
,
256 lst::integer_type::signedness::UNSIGNED
,
257 lst::integer_type::base::DECIMAL
,
258 std::initializer_list
<lst::integer_type::role
>(
259 { lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
261 /* uint64_t timestamp_end */
262 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
264 lttng::make_unique
<lst::integer_type
>(
265 trace_abi
.uint64_t_alignment
,
266 trace_abi
.byte_order
,
268 lst::integer_type::signedness::UNSIGNED
,
269 lst::integer_type::base::DECIMAL
,
270 std::initializer_list
<lst::integer_type::role
>(
271 { lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP
}))));
273 /* uint64_t content_size */
274 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
276 lttng::make_unique
<lst::integer_type
>(
277 trace_abi
.uint64_t_alignment
,
278 trace_abi
.byte_order
,
280 lst::integer_type::signedness::UNSIGNED
,
281 lst::integer_type::base::DECIMAL
,
282 std::initializer_list
<lst::integer_type::role
>(
283 { lst::integer_type::role::PACKET_CONTENT_LENGTH
}))));
285 /* uint64_t packet_size */
286 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
288 lttng::make_unique
<lst::integer_type
>(
289 trace_abi
.uint64_t_alignment
,
290 trace_abi
.byte_order
,
292 lst::integer_type::signedness::UNSIGNED
,
293 lst::integer_type::base::DECIMAL
,
294 std::initializer_list
<lst::integer_type::role
>(
295 { lst::integer_type::role::PACKET_TOTAL_LENGTH
}))));
297 /* uint64_t packet_seq_num */
298 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
300 lttng::make_unique
<lst::integer_type
>(
301 trace_abi
.uint64_t_alignment
,
302 trace_abi
.byte_order
,
304 lst::integer_type::signedness::UNSIGNED
,
305 lst::integer_type::base::DECIMAL
,
306 std::initializer_list
<lst::integer_type::role
>(
307 { lst::integer_type::role::PACKET_SEQUENCE_NUMBER
}))));
309 /* unsigned long events_discarded */
310 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
312 lttng::make_unique
<lst::integer_type
>(
313 trace_abi
.long_alignment
,
314 trace_abi
.byte_order
,
315 trace_abi
.bits_per_long
,
316 lst::integer_type::signedness::UNSIGNED
,
317 lst::integer_type::base::DECIMAL
,
318 std::initializer_list
<lst::integer_type::role
>(
319 { lst::integer_type::role::
320 DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT
}))));
322 /* uint32_t cpu_id */
323 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>(
325 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
326 trace_abi
.byte_order
,
328 lst::integer_type::signedness::UNSIGNED
,
329 lst::integer_type::base::DECIMAL
)));
331 return lttng::make_unique
<lst::structure_type
>(0, std::move(packet_context_fields
));
335 lsu::registry_channel::registry_channel(
336 unsigned int channel_id
,
337 const lst::abi
& trace_abi
,
338 std::string in_default_clock_class_name
,
339 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
340 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
341 lst::stream_class(channel_id
,
342 lst::stream_class::header_type::LARGE
,
343 std::move(in_default_clock_class_name
)),
345 _consumer_key
{ -1ULL },
347 _is_registered_listener
{ std::move(channel_registered_listener
) },
348 _event_added_listener
{ std::move(event_added_listener
) },
349 _is_registered
{ false }
351 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
353 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
356 /* Set custom match function. */
357 _events
->match_fct
= ht_match_event
;
358 _events
->hash_fct
= ht_hash_event
;
362 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
363 * channel object itself.
367 _packet_context
= create_packet_context(trace_abi
);
368 _event_header
= create_event_header(trace_abi
, header_type_
);
371 void lsu::registry_channel::add_event(int session_objd
,
374 std::string signature
,
375 std::vector
<lst::field::cuptr
> event_fields
,
377 nonstd::optional
<std::string
> model_emf_uri
,
378 lttng_buffer_type buffer_type
,
380 lsu::event_id
& out_event_id
)
382 lsu::event_id event_id
;
383 struct cds_lfht_node
*nptr
;
384 const lttng::urcu::read_lock_guard read_lock_guard
;
387 * This should not happen but since it comes from the UST tracer, an
388 * external party, don't assert and simply validate values.
390 if (session_objd
< 0) {
391 LTTNG_THROW_INVALID_ARGUMENT_ERROR(lttng::format(
392 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
397 if (channel_objd
< 0) {
398 LTTNG_THROW_INVALID_ARGUMENT_ERROR(lttng::format(
399 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
404 /* Check if we've reached the maximum possible id. */
405 if (is_max_event_id(_next_event_id
)) {
406 LTTNG_THROW_ERROR(lttng::format(
407 "Failed to allocate new event id (id would overflow): app = {}", app
));
410 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
411 new lsu::registry_event(_next_event_id
,
416 std::move(signature
),
417 std::move(event_fields
),
419 std::move(model_emf_uri
)));
421 DBG3("%s", lttng::format("UST registry creating event: event = {}", *event
).c_str());
424 * This is an add unique with a custom match function for event. The node
425 * are matched using the event name and signature.
427 nptr
= cds_lfht_add_unique(_events
->ht
,
428 _events
->hash_fct(event
.get(), lttng_ht_seed
),
432 if (nptr
!= &event
->_node
) {
433 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
435 * This is normal, we just have to send the event id of the
438 const auto existing_event
= lttng::utils::container_of(
439 nptr
, <tng::sessiond::ust::registry_event::_node
);
440 event_id
= existing_event
->id
;
442 LTTNG_THROW_INVALID_ARGUMENT_ERROR(lttng::format(
443 "UST registry create event add unique failed for event: event = {}",
447 const auto& event_ref
= *event
;
449 /* Ownership transferred to _events hash table. */
450 (void) event
.release();
452 /* Request next event id if the node was successfully added. */
453 event_id
= event_ref
.id
;
456 * Only increment the next id here since we don't want to waste an ID when the event
457 * matches an existing one.
460 _event_added_listener(*this, event_ref
);
463 out_event_id
= event_id
;
466 lsu::registry_channel::~registry_channel()
468 lttng_ht_destroy(_events
);
471 const lttng::sessiond::trace::type
*lsu::registry_channel::event_context() const
473 LTTNG_ASSERT(_is_registered
);
474 return lst::stream_class::event_context();
477 void lsu::registry_channel::event_context(lttng::sessiond::trace::type::cuptr context
)
479 /* Must only be set once, on the first channel registration provided by an application. */
480 LTTNG_ASSERT(!_event_context
);
481 _event_context
= std::move(context
);
484 bool lsu::registry_channel::is_registered() const
486 return _is_registered
;
489 void lsu::registry_channel::set_as_registered()
491 if (!_is_registered
) {
492 _is_registered
= true;
493 _is_registered_listener(*this);
497 void lsu::registry_channel::_accept_on_event_classes(
498 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
500 const lttng::urcu::lfht_iteration_adapter
<lsu::registry_event
,
501 decltype(lsu::registry_event::_node
),
502 &lsu::registry_event::_node
>
503 events_view(*_events
->ht
);
505 /* Copy the event ptrs from the _events ht to this vector which we'll sort. */
506 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes(
507 events_view
.begin(), events_view
.end());
509 std::sort(sorted_event_classes
.begin(),
510 sorted_event_classes
.end(),
511 [](const lttng::sessiond::ust::registry_event
*a
,
512 const lttng::sessiond::ust::registry_event
*b
) { return a
->id
< b
->id
; });
514 for (const auto event
: sorted_event_classes
) {
515 event
->accept(visitor
);