sessiond: add variant selector intervals
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry-channel.cpp
CommitLineData
d7bfb9b0
JG
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-registry-channel.hpp"
9#include "ust-app.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>
24ed18f2 16#include <common/make-unique.hpp>
d7bfb9b0
JG
17#include <common/urcu.hpp>
18
19namespace lst = lttng::sessiond::trace;
20namespace lsu = lttng::sessiond::ust;
21
22namespace {
23bool is_max_event_id(uint32_t id)
24{
25 return id == UINT32_MAX;
26}
27
28unsigned long ht_hash_event(const void *_key, unsigned long seed)
29{
30 uint64_t hashed_key;
31 const lttng::sessiond::ust::registry_event *key =
32 (lttng::sessiond::ust::registry_event *) _key;
33
34 LTTNG_ASSERT(key);
35
36 hashed_key = (uint64_t) hash_key_str(key->name.c_str(), seed);
37
38 return hash_key_u64(&hashed_key, seed);
39}
40
41/*
42 * Hash table match function for event in the registry.
43 */
44int ht_match_event(struct cds_lfht_node *node, const void *_key)
45{
46 const lttng::sessiond::ust::registry_event *key;
47 lttng::sessiond::ust::registry_event *event;
48
49 LTTNG_ASSERT(node);
50 LTTNG_ASSERT(_key);
51
f139a4f9 52 event = lttng::utils::container_of(node, &lttng::sessiond::ust::registry_event::_node);
d7bfb9b0
JG
53 key = (lttng::sessiond::ust::registry_event *) _key;
54
55 /* It has to be a perfect match. First, compare the event names. */
56 if (event->name != key->name) {
57 goto no_match;
58 }
59
60 /* Compare log levels. */
61 if (event->log_level != key->log_level) {
62 goto no_match;
63 }
64
65 /* Compare the arrays of fields. */
66 if (*event->payload != *key->payload) {
67 goto no_match;
68 }
69
70 /* Compare model URI. */
71 if (event->model_emf_uri != key->model_emf_uri) {
72 goto no_match;
73 }
74
75 /* Match */
76 return 1;
77
78no_match:
79 return 0;
80}
24ed18f2
JG
81
82lst::type::cuptr create_event_header(const lst::abi& trace_abi, lst::stream_class::header_type header_type)
83{
84 lst::structure_type::fields event_header_fields;
85
86 if (header_type == lst::stream_class::header_type::COMPACT) {
87 auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
45110cdd
JG
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"};
24ed18f2 91
45110cdd
JG
92 enum_mappings->emplace_back(compact_mapping);
93 enum_mappings->emplace_back(extended_mapping);
24ed18f2
JG
94
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}));
100
45110cdd
JG
101 lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
102 choices variant_choices;
24ed18f2
JG
103
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}))));
112
45110cdd 113 auto compact_type = lttng::make_unique<lst::structure_type>(
24ed18f2 114 0, std::move(compact_fields));
45110cdd 115 variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type));
24ed18f2
JG
116
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}))));
134
45110cdd
JG
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));
24ed18f2 137
45110cdd
JG
138 auto variant = lttng::make_unique<lst::variant_type<
139 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
140 0,
eda1aa02
JG
141 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
142 {"id"}),
143 std::move(variant_choices));
24ed18f2
JG
144
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)));
148 } else {
149 auto enum_mappings = std::make_shared<lst::unsigned_enumeration_type::mappings>();
45110cdd
JG
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"};
153 enum_mappings->emplace_back(compact_mapping);
154 enum_mappings->emplace_back(extended_mapping);
24ed18f2 155
45110cdd 156 auto choice_enum = lttng::make_unique<lst::unsigned_enumeration_type>(
24ed18f2
JG
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}));
161
45110cdd
JG
162 lst::variant_type<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>::
163 choices variant_choices;
24ed18f2
JG
164
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}))));
174
45110cdd 175 lst::type::cuptr compact_type = lttng::make_unique<lst::structure_type>(
24ed18f2 176 0, std::move(compact_fields));
45110cdd 177 variant_choices.emplace_back(std::move(compact_mapping), std::move(compact_type));
24ed18f2
JG
178
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}))));
196
45110cdd
JG
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));
24ed18f2 200
45110cdd
JG
201 auto variant = lttng::make_unique<lst::variant_type<
202 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t>>(
203 0,
eda1aa02
JG
204 lst::field_location(lst::field_location::root::EVENT_RECORD_HEADER,
205 {"id"}),
206 std::move(variant_choices));
24ed18f2 207
45110cdd
JG
208 event_header_fields.emplace_back(
209 lttng::make_unique<lst::field>("id", std::move(choice_enum)));
24ed18f2
JG
210 event_header_fields.emplace_back(
211 lttng::make_unique<lst::field>("v", std::move(variant)));
212 }
213
214 return lttng::make_unique<lst::structure_type>(0, std::move(event_header_fields));
215}
216
217lst::type::cuptr create_packet_context(const lst::abi& trace_abi)
218{
219 lst::structure_type::fields packet_context_fields;
220
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}))));
228
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}))));
236
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}))));
244
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}))));
252
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}))));
260
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}))));
268
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)));
275
276 return lttng::make_unique<lst::structure_type>(0, std::move(packet_context_fields));
277}
d7bfb9b0
JG
278}; /* namespace */
279
280lsu::registry_channel::registry_channel(unsigned int channel_id,
24ed18f2
JG
281 const lst::abi& trace_abi,
282 std::string in_default_clock_class_name,
d7bfb9b0
JG
283 lsu::registry_channel::registered_listener_fn channel_registered_listener,
284 lsu::registry_channel::event_added_listener_fn event_added_listener) :
24ed18f2
JG
285 lst::stream_class(channel_id,
286 lst::stream_class::header_type::LARGE,
287 std::move(in_default_clock_class_name)),
d7bfb9b0
JG
288 _key{-1ULL},
289 _consumer_key{-1ULL},
d7bfb9b0
JG
290 _next_event_id{0},
291 _is_registered_listener{channel_registered_listener},
292 _event_added_listener{event_added_listener},
293 _is_registered{false}
294{
295 _events = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
296 if (!_events) {
297 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM);
298 }
299
300 /* Set custom match function. */
301 _events->match_fct = ht_match_event;
302 _events->hash_fct = ht_hash_event;
36038679
JG
303
304 _rcu_head = {};
305 /*
306 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
307 * channel object itself.
308 */
309 _node = {};
24ed18f2
JG
310
311 _packet_context = create_packet_context(trace_abi);
312 _event_header = create_event_header(trace_abi, header_type_);
d7bfb9b0
JG
313}
314
315void lsu::registry_channel::add_event(
316 int session_objd,
317 int channel_objd,
318 std::string name,
319 std::string signature,
320 std::vector<lst::field::cuptr> event_fields,
321 int loglevel_value,
322 nonstd::optional<std::string> model_emf_uri,
323 lttng_buffer_type buffer_type,
324 const ust_app& app,
325 uint32_t& out_event_id)
326{
327 uint32_t event_id;
328 struct cds_lfht_node *nptr;
329 lttng::urcu::read_lock_guard read_lock_guard;
330
331 /*
332 * This should not happen but since it comes from the UST tracer, an
333 * external party, don't assert and simply validate values.
334 */
335 if (session_objd < 0) {
336 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
337 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
338 session_objd, app));
339 }
340
341 if (channel_objd < 0) {
342 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
343 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
344 channel_objd, app));
345 }
346
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 = {}",
351 app));
352 }
353
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)));
359
360 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event).c_str());
361
362 /*
363 * This is an add unique with a custom match function for event. The node
364 * are matched using the event name and signature.
365 */
366 nptr = cds_lfht_add_unique(_events->ht, _events->hash_fct(event.get(), lttng_ht_seed),
f139a4f9
JG
367 _events->match_fct, event.get(), &event->_node);
368 if (nptr != &event->_node) {
d7bfb9b0
JG
369 if (buffer_type == LTTNG_BUFFER_PER_UID) {
370 /*
371 * This is normal, we just have to send the event id of the
372 * returned node.
373 */
f139a4f9
JG
374 const auto existing_event = lttng::utils::container_of(
375 nptr, &lttng::sessiond::ust::registry_event::_node);
d7bfb9b0
JG
376 event_id = existing_event->id;
377 } else {
378 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
379 "UST registry create event add unique failed for event: event = {}",
380 *event));
381 }
382 } else {
383 const auto& event_ref = *event;
384
385 /* Ownership transferred to _events hash table. */
386 event.release();
387
388 /* Request next event id if the node was successfully added. */
389 event_id = event_ref.id;
390
391 /*
392 * Only increment the next id here since we don't want to waste an ID when the event
393 * matches an existing one.
394 */
395 _next_event_id++;
396 _event_added_listener(*this, event_ref);
397 }
398
399 out_event_id = event_id;
400}
401
402lsu::registry_channel::~registry_channel()
403{
404 lttng_ht_destroy(_events);
405}
406
24ed18f2 407const lttng::sessiond::trace::type* lsu::registry_channel::get_event_context() const
d7bfb9b0
JG
408{
409 LTTNG_ASSERT(_is_registered);
24ed18f2 410 return lst::stream_class::get_event_context();
d7bfb9b0
JG
411}
412
24ed18f2 413void lsu::registry_channel::set_event_context(lttng::sessiond::trace::type::cuptr context)
d7bfb9b0
JG
414{
415 /* Must only be set once, on the first channel registration provided by an application. */
24ed18f2
JG
416 LTTNG_ASSERT(!_event_context);
417 _event_context = std::move(context);
d7bfb9b0
JG
418}
419
420bool lsu::registry_channel::is_registered() const
421{
422 return _is_registered;
423}
424
425void lsu::registry_channel::set_as_registered()
426{
427 if (!_is_registered) {
428 _is_registered = true;
429 _is_registered_listener(*this);
430 }
431}
432
433void lsu::registry_channel::_accept_on_event_classes(
434 lttng::sessiond::trace::trace_class_visitor& visitor) const
435{
436 std::vector<const lttng::sessiond::ust::registry_event *> sorted_event_classes;
437
438 {
439 lttng::urcu::read_lock_guard read_lock_guard;
440 struct lttng_ht_iter iter;
441 const lttng::sessiond::ust::registry_event *event;
442
443 DIAGNOSTIC_PUSH
444 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
f139a4f9 445 cds_lfht_for_each_entry(_events->ht, &iter.iter, event, _node) {
d7bfb9b0
JG
446 sorted_event_classes.emplace_back(event);
447 }
448 DIAGNOSTIC_POP
449 }
450
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;
455 });
456
457 for (const auto event : sorted_event_classes) {
458 event->accept(visitor);
459 }
460}
This page took 0.044439 seconds and 4 git commands to generate.