docs: Add supported versions and fix-backport policy
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry-channel.cpp
1 /*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "ust-app.hpp"
9 #include "ust-registry-channel.hpp"
10 #include "ust-registry-event.hpp"
11
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>
18
19 #include <utility>
20
21 namespace lst = lttng::sessiond::trace;
22 namespace lsu = lttng::sessiond::ust;
23
24 namespace {
25 bool is_max_event_id(uint32_t id)
26 {
27 return id == UINT32_MAX;
28 }
29
30 unsigned long ht_hash_event(const void *_key, unsigned long seed)
31 {
32 uint64_t hashed_key;
33 const lttng::sessiond::ust::registry_event *key =
34 (lttng::sessiond::ust::registry_event *) _key;
35
36 LTTNG_ASSERT(key);
37
38 hashed_key = (uint64_t) hash_key_str(key->name.c_str(), seed);
39
40 return hash_key_u64(&hashed_key, seed);
41 }
42
43 /*
44 * Hash table match function for event in the registry.
45 */
46 int ht_match_event(struct cds_lfht_node *node, const void *_key)
47 {
48 const lttng::sessiond::ust::registry_event *key;
49 lttng::sessiond::ust::registry_event *event;
50
51 LTTNG_ASSERT(node);
52 LTTNG_ASSERT(_key);
53
54 event = lttng::utils::container_of(node, &lttng::sessiond::ust::registry_event::_node);
55 key = (lttng::sessiond::ust::registry_event *) _key;
56
57 /* It has to be a perfect match. First, compare the event names. */
58 if (event->name != key->name) {
59 goto no_match;
60 }
61
62 /* Compare log levels. */
63 if (event->log_level != key->log_level) {
64 goto no_match;
65 }
66
67 /* Compare the arrays of fields. */
68 if (*event->payload != *key->payload) {
69 goto no_match;
70 }
71
72 /* Compare model URI. */
73 if (event->model_emf_uri != key->model_emf_uri) {
74 goto no_match;
75 }
76
77 /* Match */
78 return 1;
79
80 no_match:
81 return 0;
82 }
83
84 lst::type::cuptr create_event_header(const lst::abi& trace_abi,
85 lst::stream_class::header_type header_type)
86 {
87 lst::structure_type::fields event_header_fields;
88
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)
93 };
94 lst::unsigned_enumeration_type::mapping extended_mapping{ "extended", 31 };
95
96 enum_mappings->emplace_back(compact_mapping);
97 enum_mappings->emplace_back(extended_mapping);
98
99 lst::type::cuptr choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
100 1,
101 trace_abi.byte_order,
102 5,
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 }));
107
108 lst::variant_type<
109 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::choices
110 variant_choices;
111
112 lst::structure_type::fields compact_fields;
113 compact_fields.emplace_back(lttng::make_unique<lst::field>(
114 "timestamp",
115 lttng::make_unique<lst::integer_type>(
116 1,
117 trace_abi.byte_order,
118 27,
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 }))));
123
124 auto compact_type =
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));
127
128 lst::structure_type::fields extended_fields;
129 extended_fields.emplace_back(lttng::make_unique<lst::field>(
130 "id",
131 lttng::make_unique<lst::integer_type>(
132 trace_abi.uint32_t_alignment,
133 trace_abi.byte_order,
134 32,
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>(
140 "timestamp",
141 lttng::make_unique<lst::integer_type>(
142 trace_abi.uint64_t_alignment,
143 trace_abi.byte_order,
144 64,
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 }))));
149
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));
153
154 auto variant = lttng::make_unique<lst::variant_type<
155 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
156 0,
157 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
158 { "id" }),
159 std::move(variant_choices));
160
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)));
165 } else {
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)
169 };
170 lst::unsigned_enumeration_type::mapping extended_mapping{ "extended", 65535 };
171 enum_mappings->emplace_back(compact_mapping);
172 enum_mappings->emplace_back(extended_mapping);
173
174 auto choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
175 trace_abi.uint16_t_alignment,
176 trace_abi.byte_order,
177 16,
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 }));
182
183 lst::variant_type<
184 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::choices
185 variant_choices;
186
187 lst::structure_type::fields compact_fields;
188 compact_fields.emplace_back(lttng::make_unique<lst::field>(
189 "timestamp",
190 lttng::make_unique<lst::integer_type>(
191 trace_abi.uint32_t_alignment,
192 trace_abi.byte_order,
193 32,
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 }))));
198
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));
202
203 lst::structure_type::fields extended_fields;
204 extended_fields.emplace_back(lttng::make_unique<lst::field>(
205 "id",
206 lttng::make_unique<lst::integer_type>(
207 trace_abi.uint32_t_alignment,
208 trace_abi.byte_order,
209 32,
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>(
215 "timestamp",
216 lttng::make_unique<lst::integer_type>(
217 trace_abi.uint64_t_alignment,
218 trace_abi.byte_order,
219 64,
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 }))));
224
225 auto extended_type =
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));
228
229 auto variant = lttng::make_unique<lst::variant_type<
230 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
231 0,
232 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
233 { "id" }),
234 std::move(variant_choices));
235
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)));
240 }
241
242 return lttng::make_unique<lst::structure_type>(0, std::move(event_header_fields));
243 }
244
245 lst::type::cuptr create_packet_context(const lst::abi& trace_abi)
246 {
247 lst::structure_type::fields packet_context_fields;
248
249 /* uint64_t timestamp_begin */
250 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
251 "timestamp_begin",
252 lttng::make_unique<lst::integer_type>(
253 trace_abi.uint64_t_alignment,
254 trace_abi.byte_order,
255 64,
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 }))));
260
261 /* uint64_t timestamp_end */
262 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
263 "timestamp_end",
264 lttng::make_unique<lst::integer_type>(
265 trace_abi.uint64_t_alignment,
266 trace_abi.byte_order,
267 64,
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 }))));
272
273 /* uint64_t content_size */
274 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
275 "content_size",
276 lttng::make_unique<lst::integer_type>(
277 trace_abi.uint64_t_alignment,
278 trace_abi.byte_order,
279 64,
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 }))));
284
285 /* uint64_t packet_size */
286 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
287 "packet_size",
288 lttng::make_unique<lst::integer_type>(
289 trace_abi.uint64_t_alignment,
290 trace_abi.byte_order,
291 64,
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 }))));
296
297 /* uint64_t packet_seq_num */
298 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
299 "packet_seq_num",
300 lttng::make_unique<lst::integer_type>(
301 trace_abi.uint64_t_alignment,
302 trace_abi.byte_order,
303 64,
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 }))));
308
309 /* unsigned long events_discarded */
310 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
311 "events_discarded",
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 }))));
321
322 /* uint32_t cpu_id */
323 packet_context_fields.emplace_back(lttng::make_unique<lst::field>(
324 "cpu_id",
325 lttng::make_unique<lst::integer_type>(trace_abi.uint32_t_alignment,
326 trace_abi.byte_order,
327 32,
328 lst::integer_type::signedness::UNSIGNED,
329 lst::integer_type::base::DECIMAL)));
330
331 return lttng::make_unique<lst::structure_type>(0, std::move(packet_context_fields));
332 }
333 }; /* namespace */
334
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)),
344 _key{ -1ULL },
345 _consumer_key{ -1ULL },
346 _next_event_id{ 0 },
347 _is_registered_listener{ std::move(channel_registered_listener) },
348 _event_added_listener{ std::move(event_added_listener) },
349 _is_registered{ false }
350 {
351 _events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
352 if (!_events) {
353 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM);
354 }
355
356 /* Set custom match function. */
357 _events->match_fct = ht_match_event;
358 _events->hash_fct = ht_hash_event;
359
360 _rcu_head = {};
361 /*
362 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
363 * channel object itself.
364 */
365 _node = {};
366
367 _packet_context = create_packet_context(trace_abi);
368 _event_header = create_event_header(trace_abi, header_type_);
369 }
370
371 void lsu::registry_channel::add_event(int session_objd,
372 int channel_objd,
373 std::string name,
374 std::string signature,
375 std::vector<lst::field::cuptr> event_fields,
376 int loglevel_value,
377 nonstd::optional<std::string> model_emf_uri,
378 lttng_buffer_type buffer_type,
379 const ust_app& app,
380 uint32_t& out_event_id)
381 {
382 uint32_t event_id;
383 struct cds_lfht_node *nptr;
384 lttng::urcu::read_lock_guard read_lock_guard;
385
386 /*
387 * This should not happen but since it comes from the UST tracer, an
388 * external party, don't assert and simply validate values.
389 */
390 if (session_objd < 0) {
391 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
392 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
393 session_objd,
394 app));
395 }
396
397 if (channel_objd < 0) {
398 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
399 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
400 channel_objd,
401 app));
402 }
403
404 /* Check if we've reached the maximum possible id. */
405 if (is_max_event_id(_next_event_id)) {
406 LTTNG_THROW_ERROR(fmt::format(
407 "Failed to allocate new event id (id would overflow): app = {}", app));
408 }
409
410 auto event = lttng::make_unique_wrapper<lsu::registry_event, registry_event_destroy>(
411 new lsu::registry_event(_next_event_id,
412 id,
413 session_objd,
414 channel_objd,
415 std::move(name),
416 std::move(signature),
417 std::move(event_fields),
418 loglevel_value,
419 std::move(model_emf_uri)));
420
421 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event).c_str());
422
423 /*
424 * This is an add unique with a custom match function for event. The node
425 * are matched using the event name and signature.
426 */
427 nptr = cds_lfht_add_unique(_events->ht,
428 _events->hash_fct(event.get(), lttng_ht_seed),
429 _events->match_fct,
430 event.get(),
431 &event->_node);
432 if (nptr != &event->_node) {
433 if (buffer_type == LTTNG_BUFFER_PER_UID) {
434 /*
435 * This is normal, we just have to send the event id of the
436 * returned node.
437 */
438 const auto existing_event = lttng::utils::container_of(
439 nptr, &lttng::sessiond::ust::registry_event::_node);
440 event_id = existing_event->id;
441 } else {
442 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
443 "UST registry create event add unique failed for event: event = {}",
444 *event));
445 }
446 } else {
447 const auto& event_ref = *event;
448
449 /* Ownership transferred to _events hash table. */
450 (void) event.release();
451
452 /* Request next event id if the node was successfully added. */
453 event_id = event_ref.id;
454
455 /*
456 * Only increment the next id here since we don't want to waste an ID when the event
457 * matches an existing one.
458 */
459 _next_event_id++;
460 _event_added_listener(*this, event_ref);
461 }
462
463 out_event_id = event_id;
464 }
465
466 lsu::registry_channel::~registry_channel()
467 {
468 lttng_ht_destroy(_events);
469 }
470
471 const lttng::sessiond::trace::type *lsu::registry_channel::event_context() const
472 {
473 LTTNG_ASSERT(_is_registered);
474 return lst::stream_class::event_context();
475 }
476
477 void lsu::registry_channel::event_context(lttng::sessiond::trace::type::cuptr context)
478 {
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);
482 }
483
484 bool lsu::registry_channel::is_registered() const
485 {
486 return _is_registered;
487 }
488
489 void lsu::registry_channel::set_as_registered()
490 {
491 if (!_is_registered) {
492 _is_registered = true;
493 _is_registered_listener(*this);
494 }
495 }
496
497 void lsu::registry_channel::_accept_on_event_classes(
498 lttng::sessiond::trace::trace_class_visitor& visitor) const
499 {
500 std::vector<const lttng::sessiond::ust::registry_event *> sorted_event_classes;
501
502 {
503 lttng::urcu::read_lock_guard read_lock_guard;
504 struct lttng_ht_iter iter;
505 const lttng::sessiond::ust::registry_event *event;
506
507 DIAGNOSTIC_PUSH
508 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
509 cds_lfht_for_each_entry (_events->ht, &iter.iter, event, _node) {
510 sorted_event_classes.emplace_back(event);
511 }
512 DIAGNOSTIC_POP
513 }
514
515 std::sort(sorted_event_classes.begin(),
516 sorted_event_classes.end(),
517 [](const lttng::sessiond::ust::registry_event *a,
518 const lttng::sessiond::ust::registry_event *b) { return a->id < b->id; });
519
520 for (const auto event : sorted_event_classes) {
521 event->accept(visitor);
522 }
523 }
This page took 0.039548 seconds and 4 git commands to generate.