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 | ||
07c4863f | 59 | event_name_set(event_name_set&& original) noexcept : |
d73aeddd JG |
60 | lttng::utils::random_access_container_wrapper<const bt_value *, |
61 | const char *, | |
62 | event_name_set_operations>( | |
07c4863f | 63 | original._container) |
d73aeddd JG |
64 | { |
65 | } | |
66 | ||
07c4863f | 67 | explicit event_name_set(const bt_value *names) : |
d73aeddd JG |
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 | ||
07c4863f | 105 | ~event_name_iterator_data() = default; |
d73aeddd JG |
106 | |
107 | const lttng::bt2::message_iterator_ref upstream_iterator; | |
108 | const class event_name_filter& event_name_filter; | |
9f263671 KS |
109 | }; |
110 | ||
d73aeddd JG |
111 | namespace { |
112 | bool message_passes(const bt_message *message, const event_name_filter& event_name_filter) | |
113 | { | |
114 | if (bt_message_get_type(message) != BT_MESSAGE_TYPE_EVENT) { | |
115 | return true; | |
116 | } | |
117 | ||
118 | const bt_event *event = bt_message_event_borrow_event_const(message); | |
119 | const bt_event_class *event_class = bt_event_borrow_class_const(event); | |
120 | const char *event_name = bt_event_class_get_name(event_class); | |
121 | ||
122 | if (event_name == nullptr) { | |
123 | return false; | |
124 | } | |
125 | ||
126 | return event_name_filter.event_name_is_allowed(event_name); | |
127 | } | |
128 | } /* namespace */ | |
129 | ||
9f263671 KS |
130 | bt_component_class_initialize_method_status |
131 | event_name_initialize(bt_self_component_filter *self_comp, | |
132 | bt_self_component_filter_configuration *, | |
133 | const bt_value *params, | |
134 | void *) | |
135 | { | |
9f263671 | 136 | bt_self_component_port_input *input_port; |
d73aeddd JG |
137 | std::unique_ptr<class event_name_filter> event_name_filter; |
138 | ||
9f263671 KS |
139 | auto self = bt_self_component_filter_as_self_component(self_comp); |
140 | if (bt_self_component_filter_add_input_port(self_comp, "in", nullptr, &input_port) != | |
141 | BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { | |
142 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, | |
143 | "Failed to add input port"); | |
d73aeddd | 144 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 KS |
145 | } |
146 | ||
147 | if (bt_self_component_filter_add_output_port(self_comp, "out", nullptr, nullptr) != | |
148 | BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) { | |
149 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, | |
150 | "Failed to add output port"); | |
d73aeddd | 151 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 KS |
152 | } |
153 | ||
d73aeddd JG |
154 | const auto names_param = bt_value_map_borrow_entry_value_const(params, "names"); |
155 | if (names_param == nullptr) { | |
9f263671 KS |
156 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( |
157 | self, "'names' parameter is required"); | |
d73aeddd | 158 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
9f263671 | 159 | } |
d73aeddd JG |
160 | |
161 | try { | |
07c4863f | 162 | const event_name_set event_names{ names_param }; |
d73aeddd | 163 | if (event_names.empty()) { |
9f263671 | 164 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( |
d73aeddd JG |
165 | bt_self_component_filter_as_self_component(self_comp), |
166 | "'names' parameter must not be empty"); | |
167 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
9f263671 | 168 | } |
d73aeddd JG |
169 | |
170 | event_name_filter = | |
171 | lttng::make_unique<class event_name_filter>(input_port, event_names); | |
172 | } catch (const std::bad_alloc&) { | |
173 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( | |
174 | self, "Failed to allocate memory for private component data"); | |
175 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR; | |
176 | } catch (const std::exception& ex) { | |
177 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self, "%s", ex.what()); | |
178 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
9f263671 | 179 | } |
9f263671 | 180 | |
d73aeddd JG |
181 | /* Ownership of event_name is transferred to the component. */ |
182 | bt_self_component_set_data(self, event_name_filter.release()); | |
183 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; | |
9f263671 KS |
184 | } |
185 | ||
186 | void event_name_finalize(bt_self_component_filter *self_comp) | |
187 | { | |
d73aeddd JG |
188 | class event_name_filter *event_name_filter = |
189 | (class event_name_filter *) bt_self_component_get_data( | |
190 | bt_self_component_filter_as_self_component(self_comp)); | |
191 | ||
192 | delete event_name_filter; | |
9f263671 KS |
193 | } |
194 | ||
195 | bt_message_iterator_class_initialize_method_status | |
196 | event_name_message_iterator_initialize(bt_self_message_iterator *self_message_iterator, | |
197 | bt_self_message_iterator_configuration *, | |
198 | bt_self_component_port_output *) | |
199 | { | |
d73aeddd JG |
200 | const auto& event_name_filter = |
201 | *static_cast<class event_name_filter *>(bt_self_component_get_data( | |
202 | bt_self_message_iterator_borrow_component(self_message_iterator))); | |
9f263671 | 203 | |
d73aeddd | 204 | bt_message_iterator *raw_iterator; |
9f263671 | 205 | if (bt_message_iterator_create_from_message_iterator( |
d73aeddd | 206 | self_message_iterator, event_name_filter.input_port, &raw_iterator) != |
9f263671 | 207 | BT_MESSAGE_ITERATOR_CREATE_FROM_MESSAGE_ITERATOR_STATUS_OK) { |
9f263671 KS |
208 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; |
209 | } | |
210 | ||
d73aeddd JG |
211 | lttng::bt2::message_iterator_ref iterator(raw_iterator); |
212 | raw_iterator = nullptr; | |
213 | ||
214 | std::unique_ptr<event_name_iterator_data> iter_data; | |
215 | try { | |
216 | iter_data = lttng::make_unique<event_name_iterator_data>(std::move(iterator), | |
217 | event_name_filter); | |
218 | } catch (const std::bad_alloc&) { | |
219 | BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( | |
220 | self_message_iterator, "Failed to allocate event_name iterator data"); | |
221 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR; | |
222 | } | |
9f263671 | 223 | |
d73aeddd JG |
224 | /* Transfer the ownership of iter_data to the iterator. */ |
225 | bt_self_message_iterator_set_data(self_message_iterator, iter_data.release()); | |
9f263671 KS |
226 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; |
227 | } | |
228 | ||
229 | void event_name_message_iterator_finalize(bt_self_message_iterator *self_message) | |
230 | { | |
d73aeddd JG |
231 | event_name_iterator_data *iter_data = static_cast<event_name_iterator_data *>( |
232 | bt_self_message_iterator_get_data(self_message)); | |
9f263671 | 233 | |
d73aeddd JG |
234 | LTTNG_ASSERT(iter_data); |
235 | delete iter_data; | |
9f263671 KS |
236 | } |
237 | ||
238 | bt_message_iterator_class_next_method_status | |
239 | event_name_message_iterator_next(bt_self_message_iterator *self_message_iterator, | |
d73aeddd | 240 | bt_message_array_const messages_to_deliver_downstream, |
9f263671 | 241 | uint64_t, |
d73aeddd | 242 | uint64_t *_messages_to_deliver_count) |
9f263671 | 243 | { |
d73aeddd JG |
244 | std::uint64_t messages_to_deliver_count = 0; |
245 | auto *iter_data = static_cast<event_name_iterator_data *>( | |
246 | bt_self_message_iterator_get_data(self_message_iterator)); | |
247 | const auto& event_name_filter = | |
248 | *static_cast<class event_name_filter *>(bt_self_component_get_data( | |
249 | bt_self_message_iterator_borrow_component(self_message_iterator))); | |
250 | ||
251 | LTTNG_ASSERT(iter_data); | |
252 | ||
253 | /* Retry until we have at least one message to deliver downstream. */ | |
254 | while (messages_to_deliver_count == 0) { | |
255 | bt_message_array_const upstream_messages; | |
256 | bt_message_iterator_next_status next_status; | |
257 | uint64_t upstream_message_count; | |
258 | ||
259 | next_status = bt_message_iterator_next(iter_data->upstream_iterator.get(), | |
260 | &upstream_messages, | |
261 | &upstream_message_count); | |
9f263671 | 262 | if (next_status != BT_MESSAGE_ITERATOR_NEXT_STATUS_OK) { |
d73aeddd | 263 | return static_cast<bt_message_iterator_class_next_method_status>( |
9f263671 | 264 | next_status); |
9f263671 KS |
265 | } |
266 | ||
d73aeddd | 267 | for (std::uint64_t upstream_index = 0; upstream_index < upstream_message_count; |
9f263671 | 268 | upstream_index++) { |
d73aeddd JG |
269 | lttng::bt2::message_const_ref upstream_message( |
270 | upstream_messages[upstream_index]); | |
271 | ||
272 | if (message_passes(upstream_message.get(), event_name_filter)) { | |
273 | /* Reference transferred to downstream message batch. */ | |
274 | messages_to_deliver_downstream[messages_to_deliver_count] = | |
275 | upstream_message.release(); | |
276 | messages_to_deliver_count++; | |
9f263671 KS |
277 | } |
278 | } | |
279 | } | |
280 | ||
d73aeddd JG |
281 | *_messages_to_deliver_count = messages_to_deliver_count; |
282 | return BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; | |
9f263671 | 283 | } |