Document libbabeltrace2's C API
[babeltrace.git] / doc / api / libbabeltrace2 / examples / distill.c
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
113 /* Create the uptream message iterator */
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);
This page took 0.04524 seconds and 4 git commands to generate.