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
>();
89 enum_mappings
->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 30));
90 enum_mappings
->emplace_back("extended");
92 lst::type::cuptr choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(1,
93 trace_abi
.byte_order
, 5, lst::integer_type::base::DECIMAL
,
94 std::move(enum_mappings
),
95 std::initializer_list
<lst::integer_type::role
>(
96 {lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
98 lst::variant_type::choices variant_choices
;
100 lst::structure_type::fields compact_fields
;
101 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
102 lttng::make_unique
<lst::integer_type
>(1, trace_abi
.byte_order
, 27,
103 lst::integer_type::signedness::UNSIGNED
,
104 lst::integer_type::base::DECIMAL
,
105 std::initializer_list
<lst::integer_type::
106 role
>({lst::integer_type::role::
107 DEFAULT_CLOCK_TIMESTAMP
}))));
109 lst::type::cuptr compact
= lttng::make_unique
<lst::structure_type
>(
110 0, std::move(compact_fields
));
111 variant_choices
.emplace_back(lttng::make_unique
<lst::field
>("compact", std::move(compact
)));
113 lst::structure_type::fields extended_fields
;
114 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("id",
115 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
116 trace_abi
.byte_order
, 32,
117 lst::integer_type::signedness::UNSIGNED
,
118 lst::integer_type::base::DECIMAL
,
119 std::initializer_list
<lst::integer_type::
120 role
>({lst::integer_type::role::
121 EVENT_RECORD_CLASS_ID
}))));
122 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
123 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
124 trace_abi
.byte_order
, 64,
125 lst::integer_type::signedness::UNSIGNED
,
126 lst::integer_type::base::DECIMAL
,
127 std::initializer_list
<lst::integer_type::
128 role
>({lst::integer_type::role::
129 DEFAULT_CLOCK_TIMESTAMP
}))));
131 lst::type::cuptr extended
= lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
132 variant_choices
.emplace_back(lttng::make_unique
<lst::field
>("extended", std::move(extended
)));
134 lst::type::cuptr variant
= lttng::make_unique
<lst::variant_type
>(0,
135 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
137 std::move(variant_choices
));
139 event_header_fields
.emplace_back(lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
140 event_header_fields
.emplace_back(
141 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
143 auto enum_mappings
= std::make_shared
<lst::unsigned_enumeration_type::mappings
>();
145 enum_mappings
->emplace_back("compact", lst::unsigned_enumeration_type::mapping::range_t(0, 65534));
146 enum_mappings
->emplace_back("extended");
148 lst::type::cuptr choice_enum
= lttng::make_unique
<lst::unsigned_enumeration_type
>(
149 trace_abi
.uint16_t_alignment
, trace_abi
.byte_order
, 16,
150 lst::integer_type::base::DECIMAL
, std::move(enum_mappings
),
151 std::initializer_list
<lst::integer_type::role
>(
152 {lst::integer_type::role::EVENT_RECORD_CLASS_ID
}));
154 lst::variant_type::choices variant_choices
;
156 lst::structure_type::fields compact_fields
;
157 compact_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
158 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
159 trace_abi
.byte_order
, 32,
160 lst::integer_type::signedness::UNSIGNED
,
161 lst::integer_type::base::DECIMAL
,
162 std::initializer_list
<lst::integer_type::
163 role
>({lst::integer_type::role::
164 DEFAULT_CLOCK_TIMESTAMP
}))));
166 lst::type::cuptr compact
= lttng::make_unique
<lst::structure_type
>(
167 0, std::move(compact_fields
));
168 variant_choices
.emplace_back(
169 lttng::make_unique
<lst::field
>("compact", std::move(compact
)));
171 lst::structure_type::fields extended_fields
;
172 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("id",
173 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
174 trace_abi
.byte_order
, 32,
175 lst::integer_type::signedness::UNSIGNED
,
176 lst::integer_type::base::DECIMAL
,
177 std::initializer_list
<lst::integer_type::
178 role
>({lst::integer_type::role::
179 EVENT_RECORD_CLASS_ID
}))));
180 extended_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp",
181 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
182 trace_abi
.byte_order
, 64,
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 DEFAULT_CLOCK_TIMESTAMP
}))));
189 lst::type::cuptr extended
= lttng::make_unique
<lst::structure_type
>(0, std::move(extended_fields
));
190 variant_choices
.emplace_back(lttng::make_unique
<lst::field
>("extended", std::move(extended
)));
192 lst::type::cuptr variant
= lttng::make_unique
<lst::variant_type
>(0,
193 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER
,
195 std::move(variant_choices
));
197 event_header_fields
.emplace_back(lttng::make_unique
<lst::field
>("id", std::move(choice_enum
)));
198 event_header_fields
.emplace_back(
199 lttng::make_unique
<lst::field
>("v", std::move(variant
)));
202 return lttng::make_unique
<lst::structure_type
>(0, std::move(event_header_fields
));
205 lst::type::cuptr
create_packet_context(const lst::abi
& trace_abi
)
207 lst::structure_type::fields packet_context_fields
;
209 /* uint64_t timestamp_begin */
210 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp_begin",
211 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
212 trace_abi
.byte_order
, 64,
213 lst::integer_type::signedness::UNSIGNED
,
214 lst::integer_type::base::DECIMAL
,
215 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::DEFAULT_CLOCK_TIMESTAMP
}))));
217 /* uint64_t timestamp_end */
218 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("timestamp_end",
219 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
220 trace_abi
.byte_order
, 64,
221 lst::integer_type::signedness::UNSIGNED
,
222 lst::integer_type::base::DECIMAL
,
223 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_END_DEFAULT_CLOCK_TIMESTAMP
}))));
225 /* uint64_t content_size */
226 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("content_size",
227 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
228 trace_abi
.byte_order
, 64,
229 lst::integer_type::signedness::UNSIGNED
,
230 lst::integer_type::base::DECIMAL
,
231 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_CONTENT_LENGTH
}))));
233 /* uint64_t packet_size */
234 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("packet_size",
235 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
236 trace_abi
.byte_order
, 64,
237 lst::integer_type::signedness::UNSIGNED
,
238 lst::integer_type::base::DECIMAL
,
239 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_TOTAL_LENGTH
}))));
241 /* uint64_t packet_seq_num */
242 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("packet_seq_num",
243 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint64_t_alignment
,
244 trace_abi
.byte_order
, 64,
245 lst::integer_type::signedness::UNSIGNED
,
246 lst::integer_type::base::DECIMAL
,
247 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::PACKET_SEQUENCE_NUMBER
}))));
249 /* unsigned long events_discarded */
250 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("events_discarded",
251 lttng::make_unique
<lst::integer_type
>(trace_abi
.long_alignment
,
252 trace_abi
.byte_order
, trace_abi
.bits_per_long
,
253 lst::integer_type::signedness::UNSIGNED
,
254 lst::integer_type::base::DECIMAL
,
255 std::initializer_list
<lst::integer_type::role
>({lst::integer_type::role::DISCARDED_EVENT_RECORD_COUNTER_SNAPSHOT
}))));
257 /* uint32_t cpu_id */
258 packet_context_fields
.emplace_back(lttng::make_unique
<lst::field
>("cpu_id",
259 lttng::make_unique
<lst::integer_type
>(trace_abi
.uint32_t_alignment
,
260 trace_abi
.byte_order
, 32,
261 lst::integer_type::signedness::UNSIGNED
,
262 lst::integer_type::base::DECIMAL
)));
264 return lttng::make_unique
<lst::structure_type
>(0, std::move(packet_context_fields
));
268 lsu::registry_channel::registry_channel(unsigned int channel_id
,
269 const lst::abi
& trace_abi
,
270 std::string in_default_clock_class_name
,
271 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
272 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
273 lst::stream_class(channel_id
,
274 lst::stream_class::header_type::LARGE
,
275 std::move(in_default_clock_class_name
)),
277 _consumer_key
{-1ULL},
279 _is_registered_listener
{channel_registered_listener
},
280 _event_added_listener
{event_added_listener
},
281 _is_registered
{false}
283 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
285 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
288 /* Set custom match function. */
289 _events
->match_fct
= ht_match_event
;
290 _events
->hash_fct
= ht_hash_event
;
294 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
295 * channel object itself.
299 _packet_context
= create_packet_context(trace_abi
);
300 _event_header
= create_event_header(trace_abi
, header_type_
);
303 void lsu::registry_channel::add_event(
307 std::string signature
,
308 std::vector
<lst::field::cuptr
> event_fields
,
310 nonstd::optional
<std::string
> model_emf_uri
,
311 lttng_buffer_type buffer_type
,
313 uint32_t& out_event_id
)
316 struct cds_lfht_node
*nptr
;
317 lttng::urcu::read_lock_guard read_lock_guard
;
320 * This should not happen but since it comes from the UST tracer, an
321 * external party, don't assert and simply validate values.
323 if (session_objd
< 0) {
324 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
325 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
329 if (channel_objd
< 0) {
330 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
331 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
335 /* Check if we've reached the maximum possible id. */
336 if (is_max_event_id(_next_event_id
)) {
337 LTTNG_THROW_ERROR(fmt::format(
338 "Failed to allocate new event id (id would overflow): app = {}",
342 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
343 new lsu::registry_event(_next_event_id
, id
, session_objd
, channel_objd
,
344 std::move(name
), std::move(signature
),
345 std::move(event_fields
), loglevel_value
,
346 std::move(model_emf_uri
)));
348 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event
).c_str());
351 * This is an add unique with a custom match function for event. The node
352 * are matched using the event name and signature.
354 nptr
= cds_lfht_add_unique(_events
->ht
, _events
->hash_fct(event
.get(), lttng_ht_seed
),
355 _events
->match_fct
, event
.get(), &event
->_node
);
356 if (nptr
!= &event
->_node
) {
357 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
359 * This is normal, we just have to send the event id of the
362 const auto existing_event
= lttng::utils::container_of(
363 nptr
, <tng::sessiond::ust::registry_event::_node
);
364 event_id
= existing_event
->id
;
366 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
367 "UST registry create event add unique failed for event: event = {}",
371 const auto& event_ref
= *event
;
373 /* Ownership transferred to _events hash table. */
376 /* Request next event id if the node was successfully added. */
377 event_id
= event_ref
.id
;
380 * Only increment the next id here since we don't want to waste an ID when the event
381 * matches an existing one.
384 _event_added_listener(*this, event_ref
);
387 out_event_id
= event_id
;
390 lsu::registry_channel::~registry_channel()
392 lttng_ht_destroy(_events
);
395 const lttng::sessiond::trace::type
* lsu::registry_channel::get_event_context() const
397 LTTNG_ASSERT(_is_registered
);
398 return lst::stream_class::get_event_context();
401 void lsu::registry_channel::set_event_context(lttng::sessiond::trace::type::cuptr context
)
403 /* Must only be set once, on the first channel registration provided by an application. */
404 LTTNG_ASSERT(!_event_context
);
405 _event_context
= std::move(context
);
408 bool lsu::registry_channel::is_registered() const
410 return _is_registered
;
413 void lsu::registry_channel::set_as_registered()
415 if (!_is_registered
) {
416 _is_registered
= true;
417 _is_registered_listener(*this);
421 void lsu::registry_channel::_accept_on_event_classes(
422 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
424 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes
;
427 lttng::urcu::read_lock_guard read_lock_guard
;
428 struct lttng_ht_iter iter
;
429 const lttng::sessiond::ust::registry_event
*event
;
432 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
433 cds_lfht_for_each_entry(_events
->ht
, &iter
.iter
, event
, _node
) {
434 sorted_event_classes
.emplace_back(event
);
439 std::sort(sorted_event_classes
.begin(), sorted_event_classes
.end(),
440 [](const lttng::sessiond::ust::registry_event
*a
,
441 const lttng::sessiond::ust::registry_event
*b
) {
442 return a
->id
< b
->id
;
445 for (const auto event
: sorted_event_classes
) {
446 event
->accept(visitor
);