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
;
51 event
= lttng::utils::container_of(node
, <tng::sessiond::ust::registry_event::_node
);
52 key
= (lttng::sessiond::ust::registry_event
*) _key
;
54 /* It has to be a perfect match. First, compare the event names. */
55 if (event
->name
!= key
->name
) {
59 /* Compare log levels. */
60 if (event
->log_level
!= key
->log_level
) {
64 /* Compare the arrays of fields. */
65 if (*event
->payload
!= *key
->payload
) {
69 /* Compare model URI. */
70 if (event
->model_emf_uri
!= key
->model_emf_uri
) {
82 lsu::registry_channel::registry_channel(unsigned int channel_id
,
83 lsu::registry_channel::registered_listener_fn channel_registered_listener
,
84 lsu::registry_channel::event_added_listener_fn event_added_listener
) :
85 lst::stream_class(channel_id
, lst::stream_class::header_type::LARGE
),
88 _metadata_dumped
{false},
90 _is_registered_listener
{channel_registered_listener
},
91 _event_added_listener
{event_added_listener
},
94 _events
= lttng_ht_new(0, LTTNG_HT_TYPE_STRING
);
96 LTTNG_THROW_POSIX("Failed to allocate urcu events hash table", ENOMEM
);
99 /* Set custom match function. */
100 _events
->match_fct
= ht_match_event
;
101 _events
->hash_fct
= ht_hash_event
;
105 * Node's key is initialized by the channel's parent session. Its value is irrelevant to the
106 * channel object itself.
111 void lsu::registry_channel::add_event(
115 std::string signature
,
116 std::vector
<lst::field::cuptr
> event_fields
,
118 nonstd::optional
<std::string
> model_emf_uri
,
119 lttng_buffer_type buffer_type
,
121 uint32_t& out_event_id
)
124 struct cds_lfht_node
*nptr
;
125 lttng::urcu::read_lock_guard read_lock_guard
;
128 * This should not happen but since it comes from the UST tracer, an
129 * external party, don't assert and simply validate values.
131 if (session_objd
< 0) {
132 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
133 "Invalid session object descriptor provided by application: session descriptor = {}, app = {}",
137 if (channel_objd
< 0) {
138 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
139 "Invalid channel object descriptor provided by application: channel descriptor = {}, app = {}",
143 /* Check if we've reached the maximum possible id. */
144 if (is_max_event_id(_next_event_id
)) {
145 LTTNG_THROW_ERROR(fmt::format(
146 "Failed to allocate new event id (id would overflow): app = {}",
150 auto event
= lttng::make_unique_wrapper
<lsu::registry_event
, registry_event_destroy
>(
151 new lsu::registry_event(_next_event_id
, id
, session_objd
, channel_objd
,
152 std::move(name
), std::move(signature
),
153 std::move(event_fields
), loglevel_value
,
154 std::move(model_emf_uri
)));
156 DBG3("%s", fmt::format("UST registry creating event: event = {}", *event
).c_str());
159 * This is an add unique with a custom match function for event. The node
160 * are matched using the event name and signature.
162 nptr
= cds_lfht_add_unique(_events
->ht
, _events
->hash_fct(event
.get(), lttng_ht_seed
),
163 _events
->match_fct
, event
.get(), &event
->_node
);
164 if (nptr
!= &event
->_node
) {
165 if (buffer_type
== LTTNG_BUFFER_PER_UID
) {
167 * This is normal, we just have to send the event id of the
170 const auto existing_event
= lttng::utils::container_of(
171 nptr
, <tng::sessiond::ust::registry_event::_node
);
172 event_id
= existing_event
->id
;
174 LTTNG_THROW_INVALID_ARGUMENT_ERROR(fmt::format(
175 "UST registry create event add unique failed for event: event = {}",
179 const auto& event_ref
= *event
;
181 /* Ownership transferred to _events hash table. */
184 /* Request next event id if the node was successfully added. */
185 event_id
= event_ref
.id
;
188 * Only increment the next id here since we don't want to waste an ID when the event
189 * matches an existing one.
192 _event_added_listener(*this, event_ref
);
195 out_event_id
= event_id
;
198 lsu::registry_channel::~registry_channel()
200 lttng_ht_destroy(_events
);
203 const lttng::sessiond::trace::type
& lsu::registry_channel::get_context() const
205 LTTNG_ASSERT(_is_registered
);
206 return lst::stream_class::get_context();
209 void lsu::registry_channel::set_context(lttng::sessiond::trace::type::cuptr context
)
211 /* Must only be set once, on the first channel registration provided by an application. */
212 LTTNG_ASSERT(!_context
);
213 _context
= std::move(context
);
216 bool lsu::registry_channel::is_registered() const
218 return _is_registered
;
221 void lsu::registry_channel::set_as_registered()
223 if (!_is_registered
) {
224 _is_registered
= true;
225 _is_registered_listener(*this);
229 void lsu::registry_channel::_accept_on_event_classes(
230 lttng::sessiond::trace::trace_class_visitor
& visitor
) const
232 std::vector
<const lttng::sessiond::ust::registry_event
*> sorted_event_classes
;
235 lttng::urcu::read_lock_guard read_lock_guard
;
236 struct lttng_ht_iter iter
;
237 const lttng::sessiond::ust::registry_event
*event
;
240 DIAGNOSTIC_IGNORE_INVALID_OFFSETOF
241 cds_lfht_for_each_entry(_events
->ht
, &iter
.iter
, event
, _node
) {
242 sorted_event_classes
.emplace_back(event
);
247 std::sort(sorted_event_classes
.begin(), sorted_event_classes
.end(),
248 [](const lttng::sessiond::ust::registry_event
*a
,
249 const lttng::sessiond::ust::registry_event
*b
) {
250 return a
->id
< b
->id
;
253 for (const auto event
: sorted_event_classes
) {
254 event
->accept(visitor
);