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/urcu.hpp>
18 namespace lst
= lttng::sessiond::trace
;
19 namespace lsu
= lttng::sessiond::ust
;
22 bool is_max_event_id(uint32_t id
)
24 return id
== UINT32_MAX
;
27 unsigned long ht_hash_event(const void *_key
, unsigned long seed
)
30 const lttng::sessiond::ust::registry_event
*key
=
31 (lttng::sessiond::ust::registry_event
*) _key
;
35 hashed_key
= (uint64_t) hash_key_str(key
->name
.c_str(), seed
);
37 return hash_key_u64(&hashed_key
, seed
);
41 * Hash table match function for event in the registry.
43 int ht_match_event(struct cds_lfht_node
*node
, const void *_key
)
45 const lttng::sessiond::ust::registry_event
*key
;
46 lttng::sessiond::ust::registry_event
*event
;
52 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
53 event
= caa_container_of(node
, lttng::sessiond::ust::registry_event
, _node
.node
);
57 key
= (lttng::sessiond::ust::registry_event
*) _key
;
59 /* It has to be a perfect match. First, compare the event names. */
60 if (event
->name
!= key
->name
) {
64 /* Compare log levels. */
65 if (event
->log_level
!= key
->log_level
) {
69 /* Compare the arrays of fields. */
70 if (*event
->payload
!= *key
->payload
) {
74 /* Compare model URI. */
75 if (event
->model_emf_uri
!= key
->model_emf_uri
) {
87 lsu::registry_channel::registry_channel(unsigned int channel_id
,
88 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
89 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
90 lst::stream_class(channel_id
, lst::stream_class::header_type::LARGE
),
93 _metadata_dumped
{false},
95 _is_registered_listener
{channel_registered_listener
},
96 _event_added_listener
{event_added_listener
},
99 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
101 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
104 /* Set custom match function. */
105 _events
->match_fct
= ht_match_event
;
106 _events
->hash_fct
= ht_hash_event
;
109 void lsu::registry_channel::add_event(
113 std::string signature
,
114 std::vector
<lst::field::cuptr
> event_fields
,
116 nonstd::optional
<std::string
> model_emf_uri
,
117 lttng_buffer_type buffer_type
,
119 uint32_t& out_event_id
)
122 struct cds_lfht_node
*nptr
;
123 lttng::urcu::read_lock_guard read_lock_guard
;
126 * This should not happen but since it comes from the UST tracer, an
127 * external party, don't assert and simply validate values.
129 if (session_objd
< 0) {
130 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
131 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
135 if (channel_objd
< 0) {
136 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
137 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
141 /* Check if we've reached the maximum possible id. */
142 if (is_max_event_id(_next_event_id
)) {
143 LTTNG_THROW_ERROR(fmt::format(
144 "Failed to allocate new event id (id would overflow): app = {}",
148 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
149 new lsu::registry_event(_next_event_id
, id
, session_objd
, channel_objd
,
150 std::move(name
), std::move(signature
),
151 std::move(event_fields
), loglevel_value
,
152 std::move(model_emf_uri
)));
154 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event
).c_str());
157 * This is an add unique with a custom match function for event. The node
158 * are matched using the event name and signature.
160 nptr
= cds_lfht_add_unique(_events
->ht
, _events
->hash_fct(event
.get(), lttng_ht_seed
),
161 _events
->match_fct
, event
.get(), &event
->_node
.node
);
162 if (nptr
!= &event
->_node
.node
) {
163 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
165 * This is normal, we just have to send the event id of the
169 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
170 const auto existing_event
= caa_container_of(
171 nptr
, lttng::sessiond::ust::registry_event
, _node
.node
);
173 event_id
= existing_event
->id
;
175 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
176 "UST registry create event add unique failed for event: event = {}",
180 const auto& event_ref
= *event
;
182 /* Ownership transferred to _events hash table. */
185 /* Request next event id if the node was successfully added. */
186 event_id
= event_ref
.id
;
189 * Only increment the next id here since we don't want to waste an ID when the event
190 * matches an existing one.
193 _event_added_listener(*this, event_ref
);
196 out_event_id
= event_id
;
199 lsu::registry_channel::~registry_channel()
201 lttng_ht_destroy(_events
);
204 const lttng::sessiond::trace::type
& lsu::registry_channel::get_context() const
206 LTTNG_ASSERT(_is_registered
);
207 return lst::stream_class::get_context();
210 void lsu::registry_channel::set_context(lttng::sessiond::trace::type::cuptr context
)
212 /* Must only be set once, on the first channel registration provided by an application. */
213 LTTNG_ASSERT(!_context
);
214 _context
= std::move(context
);
217 bool lsu::registry_channel::is_registered() const
219 return _is_registered
;
222 void lsu::registry_channel::set_as_registered()
224 if (!_is_registered
) {
225 _is_registered
= true;
226 _is_registered_listener(*this);
230 void lsu::registry_channel::_accept_on_event_classes(
231 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
233 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes
;
236 lttng::urcu::read_lock_guard read_lock_guard
;
237 struct lttng_ht_iter iter
;
238 const lttng::sessiond::ust::registry_event
*event
;
241 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
242 cds_lfht_for_each_entry(_events
->ht
, &iter
.iter
, event
, _node
.node
) {
243 sorted_event_classes
.emplace_back(event
);
248 std::sort(sorted_event_classes
.begin(), sorted_event_classes
.end(),
249 [](const lttng::sessiond::ust::registry_event
*a
,
250 const lttng::sessiond::ust::registry_event
*b
) {
251 return a
->id
< b
->id
;
254 for (const auto event
: sorted_event_classes
) {
255 event
->accept(visitor
);