Commit | Line | Data |
---|---|---|
43c59509 PP |
1 | #include <stdlib.h> |
2 | #include <stdio.h> | |
3 | #include <stdint.h> | |
4 | #include <inttypes.h> | |
5 | #include <string.h> | |
6 | #include <stdbool.h> | |
7 | #include <babeltrace2/babeltrace.h> | |
8 | ||
9 | /* Filter component's private data */ | |
10 | struct distill { | |
11 | /* Names of the classes of the events to discard (owned by this) */ | |
12 | const bt_value *names_value; | |
13 | ||
14 | /* Component's input port (weak) */ | |
15 | bt_self_component_port_input *in_port; | |
16 | }; | |
17 | ||
18 | /* | |
19 | * Initializes the filter component. | |
20 | */ | |
21 | static | |
22 | bt_component_class_initialize_method_status distill_initialize( | |
23 | bt_self_component_filter *self_component_filter, | |
24 | bt_self_component_filter_configuration *configuration, | |
25 | const bt_value *params, void *initialize_method_data) | |
26 | { | |
27 | /* Allocate a private data structure */ | |
28 | struct distill *distill = malloc(sizeof(*distill)); | |
29 | ||
30 | /* | |
31 | * Keep a reference of the `names` array value parameter so that the | |
32 | * "next" method of a message iterator can access it to decide | |
33 | * whether or not to discard an event message. | |
34 | */ | |
35 | distill->names_value = | |
36 | bt_value_map_borrow_entry_value_const(params, "names"); | |
37 | bt_value_get_ref(distill->names_value); | |
38 | ||
39 | /* Set the component's user data to our private data structure */ | |
40 | bt_self_component_set_data( | |
41 | bt_self_component_filter_as_self_component(self_component_filter), | |
42 | distill); | |
43 | ||
44 | /* | |
45 | * Add an input port named `in` to the filter component. | |
46 | * | |
47 | * This is needed so that this filter component can be connected to | |
48 | * a filter or a source component. With a connected upstream | |
49 | * component, this filter component's message iterator can create a | |
50 | * message iterator to consume messages. | |
51 | * | |
52 | * Add an output port named `out` to the filter component. | |
53 | * | |
54 | * This is needed so that this filter component can be connected to | |
55 | * a filter or a sink component. Once a downstream component is | |
56 | * connected, it can create our message iterator. | |
57 | */ | |
58 | bt_self_component_filter_add_input_port(self_component_filter, | |
59 | "in", NULL, &distill->in_port); | |
60 | bt_self_component_filter_add_output_port(self_component_filter, | |
61 | "out", NULL, NULL); | |
62 | ||
63 | return BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK; | |
64 | } | |
65 | ||
66 | /* | |
67 | * Finalizes the filter component. | |
68 | */ | |
69 | static | |
70 | void distill_finalize(bt_self_component_filter *self_component_filter) | |
71 | { | |
72 | /* Retrieve our private data from the component's user data */ | |
73 | struct distill *distill = bt_self_component_get_data( | |
74 | bt_self_component_filter_as_self_component(self_component_filter)); | |
75 | ||
76 | /* Put all references */ | |
77 | bt_value_put_ref(distill->names_value); | |
78 | ||
79 | /* Free the allocated structure */ | |
80 | free(distill); | |
81 | } | |
82 | ||
83 | /* Message iterator's private data */ | |
84 | struct distill_message_iterator { | |
85 | /* (Weak) link to the component's private data */ | |
86 | struct distill *distill; | |
87 | ||
88 | /* Upstream message iterator (owned by this) */ | |
89 | bt_message_iterator *message_iterator; | |
90 | }; | |
91 | ||
92 | /* | |
93 | * Initializes the message iterator. | |
94 | */ | |
95 | static | |
96 | bt_message_iterator_class_initialize_method_status | |
97 | distill_message_iterator_initialize( | |
98 | bt_self_message_iterator *self_message_iterator, | |
99 | bt_self_message_iterator_configuration *configuration, | |
100 | bt_self_component_port_output *self_port) | |
101 | { | |
102 | /* Allocate a private data structure */ | |
103 | struct distill_message_iterator *distill_iter = | |
104 | malloc(sizeof(*distill_iter)); | |
105 | ||
106 | /* Retrieve the component's private data from its user data */ | |
107 | struct distill *distill = bt_self_component_get_data( | |
108 | bt_self_message_iterator_borrow_component(self_message_iterator)); | |
109 | ||
110 | /* Keep a link to the component's private data */ | |
111 | distill_iter->distill = distill; | |
112 | ||
437ed44d | 113 | /* Create the upstream message iterator */ |
43c59509 PP |
114 | bt_message_iterator_create_from_message_iterator(self_message_iterator, |
115 | distill->in_port, &distill_iter->message_iterator); | |
116 | ||
117 | /* Set the message iterator's user data to our private data structure */ | |
118 | bt_self_message_iterator_set_data(self_message_iterator, distill_iter); | |
119 | ||
120 | return BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK; | |
121 | } | |
122 | ||
123 | /* | |
124 | * Finalizes the message iterator. | |
125 | */ | |
126 | static | |
127 | void distill_message_iterator_finalize( | |
128 | bt_self_message_iterator *self_message_iterator) | |
129 | { | |
130 | /* Retrieve our private data from the message iterator's user data */ | |
131 | struct distill_message_iterator *distill_iter = | |
132 | bt_self_message_iterator_get_data(self_message_iterator); | |
133 | ||
134 | /* Free the allocated structure */ | |
135 | free(distill_iter); | |
136 | } | |
137 | ||
138 | /* | |
139 | * Returns `true` if `message` passes, that is, one of: | |
140 | * | |
141 | * * It's not an event message. | |
142 | * * The event message does not need to be discarded based on its event | |
143 | * class's name. | |
144 | */ | |
145 | static | |
146 | bool message_passes(struct distill_message_iterator *distill_iter, | |
147 | const bt_message *message) | |
148 | { | |
149 | bool passes = true; | |
150 | ||
151 | /* Move as is if it's not an event message */ | |
152 | if (bt_message_get_type(message) != BT_MESSAGE_TYPE_EVENT) { | |
153 | passes = false; | |
154 | goto end; | |
155 | } | |
156 | ||
157 | /* Borrow the event message's event and its class */ | |
158 | const bt_event *event = | |
159 | bt_message_event_borrow_event_const(message); | |
160 | const bt_event_class *event_class = bt_event_borrow_class_const(event); | |
161 | ||
162 | /* Get the event class's name */ | |
163 | const char *name = bt_event_class_get_name(event_class); | |
164 | ||
165 | for (uint64_t i = 0; i < bt_value_array_get_length( | |
166 | distill_iter->distill->names_value); i++) { | |
167 | const char *discard_name = bt_value_string_get( | |
168 | bt_value_array_borrow_element_by_index_const( | |
169 | distill_iter->distill->names_value, i)); | |
170 | ||
171 | if (strcmp(name, discard_name) == 0) { | |
172 | passes = false; | |
173 | goto end; | |
174 | } | |
175 | } | |
176 | ||
177 | end: | |
178 | return passes; | |
179 | } | |
180 | ||
181 | /* | |
182 | * Returns the next message to the message iterator's user. | |
183 | * | |
184 | * This method can fill the `messages` array with up to `capacity` | |
185 | * messages. | |
186 | * | |
187 | * To keep this example simple, we put a single message into `messages` | |
188 | * and set `*count` to 1 (if the message iterator is not ended). | |
189 | */ | |
190 | static | |
191 | bt_message_iterator_class_next_method_status distill_message_iterator_next( | |
192 | bt_self_message_iterator *self_message_iterator, | |
193 | bt_message_array_const messages, uint64_t capacity, | |
194 | uint64_t *count) | |
195 | { | |
196 | /* Retrieve our private data from the message iterator's user data */ | |
197 | struct distill_message_iterator *distill_iter = | |
198 | bt_self_message_iterator_get_data(self_message_iterator); | |
199 | ||
200 | /* Consume a batch of messages from the upstream message iterator */ | |
201 | bt_message_array_const upstream_messages; | |
202 | uint64_t upstream_message_count; | |
203 | bt_message_iterator_next_status next_status; | |
204 | ||
205 | consume_upstream_messages: | |
206 | next_status = bt_message_iterator_next(distill_iter->message_iterator, | |
207 | &upstream_messages, &upstream_message_count); | |
208 | ||
209 | /* Initialize the return status to a success */ | |
210 | bt_message_iterator_class_next_method_status status = | |
211 | BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK; | |
212 | ||
213 | switch (next_status) { | |
214 | case BT_MESSAGE_ITERATOR_NEXT_STATUS_END: | |
215 | /* End of iteration: put the message iterator's reference */ | |
216 | bt_message_iterator_put_ref(distill_iter->message_iterator); | |
217 | status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END; | |
218 | goto end; | |
219 | case BT_MESSAGE_ITERATOR_NEXT_STATUS_AGAIN: | |
220 | status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_AGAIN; | |
221 | goto end; | |
222 | case BT_MESSAGE_ITERATOR_NEXT_STATUS_MEMORY_ERROR: | |
223 | status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR; | |
224 | goto end; | |
225 | case BT_MESSAGE_ITERATOR_NEXT_STATUS_ERROR: | |
226 | status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR; | |
227 | goto end; | |
228 | default: | |
229 | break; | |
230 | } | |
231 | ||
232 | /* Output message array index */ | |
233 | uint64_t i = 0; | |
234 | ||
235 | /* For each consumed message */ | |
236 | for (uint64_t upstream_i = 0; upstream_i < upstream_message_count; | |
237 | upstream_i++) { | |
238 | /* Current message */ | |
239 | const bt_message *upstream_message = upstream_messages[upstream_i]; | |
240 | ||
241 | /* Check if the upstream message passes */ | |
242 | if (message_passes(distill_iter, upstream_message)) { | |
243 | /* Move upstream message to output message array */ | |
244 | messages[i] = upstream_message; | |
245 | i++; | |
246 | continue; | |
247 | } | |
248 | ||
249 | /* Discard upstream message: put its reference */ | |
250 | bt_message_put_ref(upstream_message); | |
251 | } | |
252 | ||
253 | if (i == 0) { | |
254 | /* | |
255 | * We discarded all the upstream messages: get a new batch of | |
256 | * messages, because this method _cannot_ return | |
257 | * `BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK` and put no | |
258 | * messages into its output message array. | |
259 | */ | |
260 | goto consume_upstream_messages; | |
261 | } | |
262 | ||
263 | *count = i; | |
264 | ||
265 | end: | |
266 | return status; | |
267 | } | |
268 | ||
269 | /* Mandatory */ | |
270 | BT_PLUGIN_MODULE(); | |
271 | ||
272 | /* Define the `distill` plugin */ | |
273 | BT_PLUGIN(distill); | |
274 | ||
275 | /* Define the `theone` filter component class */ | |
276 | BT_PLUGIN_FILTER_COMPONENT_CLASS(theone, distill_message_iterator_next); | |
277 | ||
278 | /* Set some of the `theone` filter component class's optional methods */ | |
279 | BT_PLUGIN_FILTER_COMPONENT_CLASS_INITIALIZE_METHOD(theone, distill_initialize); | |
280 | BT_PLUGIN_FILTER_COMPONENT_CLASS_FINALIZE_METHOD(theone, distill_finalize); | |
281 | BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD( | |
282 | theone, distill_message_iterator_initialize); | |
283 | BT_PLUGIN_FILTER_COMPONENT_CLASS_MESSAGE_ITERATOR_CLASS_FINALIZE_METHOD(theone, | |
284 | distill_message_iterator_finalize); |