Commit | Line | Data |
---|---|---|
9f263671 KS |
1 | /* |
2 | * Copyright (C) 2023 Kienan Stewart <kstewart@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
d73aeddd | 8 | #include "../utils.hpp" |
9f263671 KS |
9 | #include "event_name.hpp" |
10 | ||
d73aeddd JG |
11 | #include <common/container-wrapper.hpp> |
12 | #include <common/macros.hpp> | |
13 | #include <common/make-unique.hpp> | |
14 | ||
9f263671 KS |
15 | #include <assert.h> |
16 | #include <babeltrace2/babeltrace.h> | |
d73aeddd JG |
17 | #include <cstdint> |
18 | #include <exception> | |
9f263671 KS |
19 | #include <stdlib.h> |
20 | #include <string.h> | |
21 | #include <string> | |
22 | #include <unordered_set> | |
23 | ||
d73aeddd JG |
24 | class event_name_set_operations { |
25 | public: | |
26 | static const char *get(const bt_value *array, std::size_t index) | |
27 | { | |
28 | const auto *names_entry = | |
29 | bt_value_array_borrow_element_by_index_const(array, index); | |
30 | ||
31 | if (bt_value_get_type(names_entry) != BT_VALUE_TYPE_STRING) { | |
32 | throw std::runtime_error( | |
33 | "All members of the 'names' parameter array must be strings"); | |
34 | } | |
35 | ||
36 | return bt_value_string_get(names_entry); | |
37 | } | |
38 | ||
39 | static std::size_t size(const bt_value *array) | |
40 | { | |
41 | return bt_value_array_get_length(array); | |
42 | } | |
43 | }; | |
44 | ||
45 | class event_name_set | |
46 | : public lttng::utils::random_access_container_wrapper<const bt_value *, | |
47 | const char *, | |
48 | event_name_set_operations> { | |
49 | public: | |
50 | friend event_name_set_operations; | |
51 | ||
52 | event_name_set() : | |
53 | lttng::utils::random_access_container_wrapper<const bt_value *, | |
54 | const char *, | |
55 | event_name_set_operations>(nullptr) | |
56 | { | |
57 | } | |
58 | ||
59 | event_name_set(event_name_set&& original) : | |
60 | lttng::utils::random_access_container_wrapper<const bt_value *, | |
61 | const char *, | |
62 | event_name_set_operations>( | |
63 | std::move(original._container)) | |
64 | { | |
65 | } | |
66 | ||
67 | event_name_set(const bt_value *names) : | |
68 | lttng::utils::random_access_container_wrapper<const bt_value *, | |
69 | const char *, | |
70 | event_name_set_operations>(names) | |
71 | { | |
72 | if (bt_value_get_type(names) != BT_VALUE_TYPE_ARRAY) { | |
73 | throw std::invalid_argument("'names' parameter must be an array"); | |
74 | } | |
75 | } | |
76 | }; | |
77 | ||
78 | class event_name_filter { | |
79 | public: | |
80 | event_name_filter(bt_self_component_port_input *input_port_, | |
81 | const event_name_set& name_set) : | |
82 | input_port{ input_port_ }, _names{ name_set.begin(), name_set.end() } | |
83 | { | |
84 | } | |
85 | ||
86 | bool event_name_is_allowed(const char *event_name) const noexcept | |
87 | { | |
88 | return _names.find(event_name) != _names.end(); | |
89 | } | |
90 | ||
9f263671 | 91 | /* weak reference */ |
d73aeddd JG |
92 | bt_self_component_port_input *const input_port; |
93 | ||
94 | private: | |
95 | const std::unordered_set<std::string> _names; | |
9f263671 KS |
96 | }; |
97 | ||
98 | struct event_name_iterator_data { | |
d73aeddd JG |
99 | event_name_iterator_data(lttng::bt2::message_iterator_ref iterator_, |
100 | const class event_name_filter& event_name_filter_) : | |
101 | upstream_iterator{ std::move(iterator_) }, event_name_filter{ event_name_filter_ } | |
102 | { | |
103 | } | |
104 | ||
105 | ~event_name_iterator_data() | |
106 | { | |
107 | } | |
108 | ||
109 | const lttng::bt2::message_iterator_ref upstream_iterator; | |
110 | const class event_name_filter& event_name_filter; | |
9f263671 KS |
111 | }; |
112 | ||
d73aeddd JG |
113 | namespace { |
114 | bool message_passes(const bt_message *message, const event_name_filter& event_name_filter) | |
115 | { | |
116 | if (bt_message_get_type(message) != BT_MESSAGE_TYPE_EVENT) { | |
117 | return true; | |
118 | } | |
119 | ||
120 | const bt_event *event = bt_message_event_borrow_event_const(message); | |
121 | const bt_event_class *event_class = bt_event_borrow_class_const(event); | |
122 | const char *event_name = bt_event_class_get_name(event_class); | |
123 | ||
124 | if (event_name == nullptr) { | |
125 | return false; | |
126 | } | |
127 | ||
128 | return event_name_filter.event_name_is_allowed(event_name); | |
129 | } | |
130 | } /* namespace */ | |
131 | ||
9f263671 KS |
132 | bt_component_class_initialize_method_status |
133 | event_name_initialize(bt_self_component_filter *self_comp, | |
134 | bt_self_component_filter_configuration *, | |
135 | const bt_value *params, | |
136 | void *) | |
137 | { | |
9f263671 | 138 | bt_self_component_port_input *input_port; |
d73aeddd JG |
139 | std::unique_ptr<class event_name_filter> event_name_filter; |
140 | ||
9f263671 KS |
141 | auto self = bt_self_component_filter_as_self_component(self_comp); |
142 | if (bt_self_component_filter_add_input_port(self_comp, "in", nullptr, &input_port) != | |
143 | BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { | |
144 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, | |
145 | "Failed to add input port"); | |
d73aeddd | 146 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 KS |
147 | } |
148 | ||
149 | if (bt_self_component_filter_add_output_port(self_comp, "out", nullptr, nullptr) != | |
150 | BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { | |
151 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, | |
152 | "Failed to add output port"); | |
d73aeddd | 153 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 KS |
154 | } |
155 | ||
d73aeddd JG |
156 | const auto names_param = bt_value_map_borrow_entry_value_const(params, "names"); |
157 | if (names_param == nullptr) { | |
9f263671 KS |
158 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( |
159 | self, "'names' parameter is required"); | |
d73aeddd | 160 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 | 161 | } |
d73aeddd JG |
162 | |
163 | try { | |
164 | event_name_set event_names{ names_param }; | |
165 | if (event_names.empty()) { | |
9f263671 | 166 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( |
d73aeddd JG |
167 | bt_self_component_filter_as_self_component(self_comp), |
168 | "'names' parameter must not be empty"); | |
169 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
9f263671 | 170 | } |
d73aeddd JG |
171 | |
172 | event_name_filter = | |
173 | lttng::make_unique<class event_name_filter>(input_port, event_names); | |
174 | } catch (const std::bad_alloc&) { | |
175 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( | |
176 | self, "Failed to allocate memory for private component data"); | |
177 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; | |
178 | } catch (const std::exception& ex) { | |
179 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, "%s", ex.what()); | |
180 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
9f263671 | 181 | } |
9f263671 | 182 | |
d73aeddd JG |
183 | /* Ownership of event_name is transferred to the component. */ |
184 | bt_self_component_set_data(self, event_name_filter.release()); | |
185 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; | |
9f263671 KS |
186 | } |
187 | ||
188 | void event_name_finalize(bt_self_component_filter *self_comp) | |
189 | { | |
d73aeddd JG |
190 | class event_name_filter *event_name_filter = |
191 | (class event_name_filter *) bt_self_component_get_data( | |
192 | bt_self_component_filter_as_self_component(self_comp)); | |
193 | ||
194 | delete event_name_filter; | |
9f263671 KS |
195 | } |
196 | ||
197 | bt_message_iterator_class_initialize_method_status | |
198 | event_name_message_iterator_initialize(bt_self_message_iterator *self_message_iterator, | |
199 | bt_self_message_iterator_configuration *, | |
200 | bt_self_component_port_output *) | |
201 | { | |
d73aeddd JG |
202 | const auto& event_name_filter = |
203 | *static_cast<class event_name_filter *>(bt_self_component_get_data( | |
204 | bt_self_message_iterator_borrow_component(self_message_iterator))); | |
9f263671 | 205 | |
d73aeddd | 206 | bt_message_iterator *raw_iterator; |
9f263671 | 207 | if (bt_message_iterator_create_from_message_iterator( |
d73aeddd | 208 | self_message_iterator, event_name_filter.input_port, &raw_iterator) != |
9f263671 | 209 | BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK) { |
9f263671 KS |
210 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
211 | } | |
212 | ||
d73aeddd JG |
213 | lttng::bt2::message_iterator_ref iterator(raw_iterator); |
214 | raw_iterator = nullptr; | |
215 | ||
216 | std::unique_ptr<event_name_iterator_data> iter_data; | |
217 | try { | |
218 | iter_data = lttng::make_unique<event_name_iterator_data>(std::move(iterator), | |
219 | event_name_filter); | |
220 | } catch (const std::bad_alloc&) { | |
221 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( | |
222 | self_message_iterator, "Failed to allocate event_name iterator data"); | |
223 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
224 | } | |
9f263671 | 225 | |
d73aeddd JG |
226 | /* Transfer the ownership of iter_data to the iterator. */ |
227 | bt_self_message_iterator_set_data(self_message_iterator, iter_data.release()); | |
9f263671 KS |
228 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; |
229 | } | |
230 | ||
231 | void event_name_message_iterator_finalize(bt_self_message_iterator *self_message) | |
232 | { | |
d73aeddd JG |
233 | event_name_iterator_data *iter_data = static_cast<event_name_iterator_data *>( |
234 | bt_self_message_iterator_get_data(self_message)); | |
9f263671 | 235 | |
d73aeddd JG |
236 | LTTNG_ASSERT(iter_data); |
237 | delete iter_data; | |
9f263671 KS |
238 | } |
239 | ||
240 | bt_message_iterator_class_next_method_status | |
241 | event_name_message_iterator_next(bt_self_message_iterator *self_message_iterator, | |
d73aeddd | 242 | bt_message_array_const messages_to_deliver_downstream, |
9f263671 | 243 | uint64_t, |
d73aeddd | 244 | uint64_t *_messages_to_deliver_count) |
9f263671 | 245 | { |
d73aeddd JG |
246 | std::uint64_t messages_to_deliver_count = 0; |
247 | auto *iter_data = static_cast<event_name_iterator_data *>( | |
248 | bt_self_message_iterator_get_data(self_message_iterator)); | |
249 | const auto& event_name_filter = | |
250 | *static_cast<class event_name_filter *>(bt_self_component_get_data( | |
251 | bt_self_message_iterator_borrow_component(self_message_iterator))); | |
252 | ||
253 | LTTNG_ASSERT(iter_data); | |
254 | ||
255 | /* Retry until we have at least one message to deliver downstream. */ | |
256 | while (messages_to_deliver_count == 0) { | |
257 | bt_message_array_const upstream_messages; | |
258 | bt_message_iterator_next_status next_status; | |
259 | uint64_t upstream_message_count; | |
260 | ||
261 | next_status = bt_message_iterator_next(iter_data->upstream_iterator.get(), | |
262 | &upstream_messages, | |
263 | &upstream_message_count); | |
9f263671 | 264 | if (next_status != BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) { |
d73aeddd | 265 | return static_cast<bt_message_iterator_class_next_method_status>( |
9f263671 | 266 | next_status); |
9f263671 KS |
267 | } |
268 | ||
d73aeddd | 269 | for (std::uint64_t upstream_index = 0; upstream_index < upstream_message_count; |
9f263671 | 270 | upstream_index++) { |
d73aeddd JG |
271 | lttng::bt2::message_const_ref upstream_message( |
272 | upstream_messages[upstream_index]); | |
273 | ||
274 | if (message_passes(upstream_message.get(), event_name_filter)) { | |
275 | /* Reference transferred to downstream message batch. */ | |
276 | messages_to_deliver_downstream[messages_to_deliver_count] = | |
277 | upstream_message.release(); | |
278 | messages_to_deliver_count++; | |
9f263671 KS |
279 | } |
280 | } | |
281 | } | |
282 | ||
d73aeddd JG |
283 | *_messages_to_deliver_count = messages_to_deliver_count; |
284 | return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; | |
9f263671 | 285 | } |