Force usage of assert() condition when NDEBUG is defined
[lttng-tools.git] / src / common / actions / list.c
1 /*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/dynamic-array.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/mi-lttng.h>
12 #include <common/payload-view.h>
13 #include <common/payload.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/list-internal.h>
16 #include <lttng/action/list.h>
17
18 #define IS_LIST_ACTION(action) \
19 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_LIST)
20
21 struct lttng_action_list {
22 struct lttng_action parent;
23
24 /* The array owns the action elements. */
25 struct lttng_dynamic_pointer_array actions;
26 };
27
28 struct lttng_action_list_comm {
29 uint32_t action_count;
30
31 /*
32 * Variable data: each element serialized sequentially.
33 */
34 char data[];
35 } LTTNG_PACKED;
36
37 static void destroy_lttng_action_list_element(void *ptr)
38 {
39 struct lttng_action *element = (struct lttng_action *) ptr;
40
41 lttng_action_destroy(element);
42 }
43
44 static struct lttng_action_list *action_list_from_action(
45 const struct lttng_action *action)
46 {
47 LTTNG_ASSERT(action);
48
49 return container_of(action, struct lttng_action_list, parent);
50 }
51
52 static const struct lttng_action_list *action_list_from_action_const(
53 const struct lttng_action *action)
54 {
55 LTTNG_ASSERT(action);
56
57 return container_of(action, struct lttng_action_list, parent);
58 }
59
60 static bool lttng_action_list_validate(struct lttng_action *action)
61 {
62 unsigned int i, count;
63 struct lttng_action_list *action_list;
64 bool valid;
65
66 LTTNG_ASSERT(IS_LIST_ACTION(action));
67
68 action_list = action_list_from_action(action);
69
70 count = lttng_dynamic_pointer_array_get_count(&action_list->actions);
71
72 for (i = 0; i < count; i++) {
73 struct lttng_action *child =
74 lttng_dynamic_pointer_array_get_pointer(
75 &action_list->actions, i);
76
77 LTTNG_ASSERT(child);
78
79 if (!lttng_action_validate(child)) {
80 valid = false;
81 goto end;
82 }
83 }
84
85 valid = true;
86
87 end:
88 return valid;
89 }
90
91 static bool lttng_action_list_is_equal(
92 const struct lttng_action *_a, const struct lttng_action *_b)
93 {
94 bool is_equal = false;
95 unsigned int i;
96 unsigned int a_count, b_count;
97
98 if (lttng_action_list_get_count(_a, &a_count) !=
99 LTTNG_ACTION_STATUS_OK) {
100 goto end;
101 }
102
103 if (lttng_action_list_get_count(_b, &b_count) !=
104 LTTNG_ACTION_STATUS_OK) {
105 goto end;
106 }
107
108 if (a_count != b_count) {
109 goto end;
110 }
111
112 for (i = 0; i < a_count; i++) {
113 const struct lttng_action *child_a =
114 lttng_action_list_get_at_index(_a, i);
115 const struct lttng_action *child_b =
116 lttng_action_list_get_at_index(_b, i);
117
118 LTTNG_ASSERT(child_a);
119 LTTNG_ASSERT(child_b);
120
121 if (!lttng_action_is_equal(child_a, child_b)) {
122 goto end;
123 }
124 }
125
126 is_equal = true;
127 end:
128 return is_equal;
129 }
130
131 static int lttng_action_list_serialize(
132 struct lttng_action *action, struct lttng_payload *payload)
133 {
134 struct lttng_action_list *action_list;
135 struct lttng_action_list_comm comm;
136 int ret;
137 unsigned int i, count;
138
139 LTTNG_ASSERT(action);
140 LTTNG_ASSERT(payload);
141 LTTNG_ASSERT(IS_LIST_ACTION(action));
142
143 action_list = action_list_from_action(action);
144
145 DBG("Serializing action list");
146
147 count = lttng_dynamic_pointer_array_get_count(&action_list->actions);
148
149 comm.action_count = count;
150
151 ret = lttng_dynamic_buffer_append(
152 &payload->buffer, &comm, sizeof(comm));
153 if (ret) {
154 ret = -1;
155 goto end;
156 }
157
158 for (i = 0; i < count; i++) {
159 struct lttng_action *child =
160 lttng_dynamic_pointer_array_get_pointer(
161 &action_list->actions, i);
162
163 LTTNG_ASSERT(child);
164
165 ret = lttng_action_serialize(child, payload);
166 if (ret) {
167 goto end;
168 }
169 }
170
171 ret = 0;
172
173 end:
174 return ret;
175 }
176
177 static void lttng_action_list_destroy(struct lttng_action *action)
178 {
179 struct lttng_action_list *action_list;
180
181 if (!action) {
182 goto end;
183 }
184
185 action_list = action_list_from_action(action);
186 lttng_dynamic_pointer_array_reset(&action_list->actions);
187 free(action_list);
188
189 end:
190 return;
191 }
192
193 ssize_t lttng_action_list_create_from_payload(
194 struct lttng_payload_view *view,
195 struct lttng_action **p_action)
196 {
197 ssize_t consumed_len;
198 const struct lttng_action_list_comm *comm;
199 struct lttng_action *list;
200 struct lttng_action *child_action = NULL;
201 enum lttng_action_status status;
202 size_t i;
203
204 list = lttng_action_list_create();
205 if (!list) {
206 consumed_len = -1;
207 goto end;
208 }
209
210 comm = (typeof(comm)) view->buffer.data;
211
212 consumed_len = sizeof(struct lttng_action_list_comm);
213
214 for (i = 0; i < comm->action_count; i++) {
215 ssize_t consumed_len_child;
216 struct lttng_payload_view child_view =
217 lttng_payload_view_from_view(view, consumed_len,
218 view->buffer.size - consumed_len);
219
220 if (!lttng_payload_view_is_valid(&child_view)) {
221 consumed_len = -1;
222 goto end;
223 }
224
225 consumed_len_child = lttng_action_create_from_payload(
226 &child_view, &child_action);
227 if (consumed_len_child < 0) {
228 consumed_len = -1;
229 goto end;
230 }
231
232 status = lttng_action_list_add_action(list, child_action);
233 if (status != LTTNG_ACTION_STATUS_OK) {
234 consumed_len = -1;
235 goto end;
236 }
237
238 /* Transfer ownership to the action list. */
239 lttng_action_put(child_action);
240 child_action = NULL;
241
242 consumed_len += consumed_len_child;
243 }
244
245 *p_action = list;
246 list = NULL;
247
248 end:
249 lttng_action_list_destroy(list);
250 return consumed_len;
251 }
252
253 static enum lttng_action_status lttng_action_list_add_error_query_results(
254 const struct lttng_action *action,
255 struct lttng_error_query_results *results)
256 {
257 unsigned int i, count;
258 enum lttng_action_status action_status;
259 const struct lttng_action_list *list =
260 container_of(action, typeof(*list), parent);
261
262 action_status = lttng_action_list_get_count(action, &count);
263 if (action_status != LTTNG_ACTION_STATUS_OK) {
264 goto end;
265 }
266
267 for (i = 0; i < count; i++) {
268 struct lttng_action *inner_action =
269 lttng_action_list_borrow_mutable_at_index(action, i);
270
271 action_status = lttng_action_add_error_query_results(
272 inner_action, results);
273 if (action_status != LTTNG_ACTION_STATUS_OK) {
274 goto end;
275 }
276 }
277 end:
278 return action_status;
279 }
280
281 LTTNG_HIDDEN
282 enum lttng_error_code lttng_action_list_mi_serialize(
283 const struct lttng_trigger *trigger,
284 const struct lttng_action *action,
285 struct mi_writer *writer,
286 const struct mi_lttng_error_query_callbacks
287 *error_query_callbacks,
288 struct lttng_dynamic_array *action_path_indexes)
289 {
290 int ret;
291 struct lttng_action_list *action_list;
292 unsigned int i, count;
293 enum lttng_error_code ret_code;
294
295 LTTNG_ASSERT(action);
296 LTTNG_ASSERT(IS_LIST_ACTION(action));
297 LTTNG_ASSERT(writer);
298
299 /* Open action list. */
300 ret = mi_lttng_writer_open_element(
301 writer, mi_lttng_element_action_list);
302 if (ret) {
303 goto mi_error;
304 }
305
306 /* Serialize every action of the list. */
307 action_list = action_list_from_action(action);
308 count = lttng_dynamic_pointer_array_get_count(&action_list->actions);
309 for (i = 0; i < count; i++) {
310 const struct lttng_action *child =
311 lttng_action_list_get_at_index(action, i);
312 const uint64_t index = (uint64_t) i;
313
314 LTTNG_ASSERT(child);
315
316 /*
317 * Add the index to the action path.
318 *
319 * This index is replaced on every iteration to walk the action
320 * tree in-order and to re-use the dynamic array instead of
321 * copying it at every level.
322 */
323 ret = lttng_dynamic_array_add_element(
324 action_path_indexes, &index);
325 if (ret) {
326 ret_code = LTTNG_ERR_NOMEM;
327 goto end;
328 }
329
330 ret_code = lttng_action_mi_serialize(trigger, child, writer,
331 error_query_callbacks, action_path_indexes);
332 if (ret_code != LTTNG_OK) {
333 goto end;
334 }
335
336 ret = lttng_dynamic_array_remove_element(action_path_indexes,
337 lttng_dynamic_array_get_count(
338 action_path_indexes) -
339 1);
340 if (ret) {
341 ret_code = LTTNG_ERR_UNK;
342 goto end;
343 }
344 }
345
346 /* Close action_list element. */
347 ret = mi_lttng_writer_close_element(writer);
348 if (ret) {
349 goto mi_error;
350 }
351
352 ret_code = LTTNG_OK;
353 goto end;
354
355 mi_error:
356 ret_code = LTTNG_ERR_MI_IO_FAIL;
357 end:
358 return ret_code;
359 }
360
361 struct lttng_action *lttng_action_list_create(void)
362 {
363 struct lttng_action_list *action_list;
364 struct lttng_action *action;
365
366 action_list = zmalloc(sizeof(struct lttng_action_list));
367 if (!action_list) {
368 action = NULL;
369 goto end;
370 }
371
372 action = &action_list->parent;
373
374 /*
375 * The mi for the list is handled at the lttng_action_mi level to ease
376 * action path management for error query.
377 */
378 lttng_action_init(action, LTTNG_ACTION_TYPE_LIST,
379 lttng_action_list_validate, lttng_action_list_serialize,
380 lttng_action_list_is_equal, lttng_action_list_destroy,
381 NULL, lttng_action_list_add_error_query_results, NULL);
382
383 lttng_dynamic_pointer_array_init(&action_list->actions,
384 destroy_lttng_action_list_element);
385
386 end:
387 return action;
388 }
389
390 enum lttng_action_status lttng_action_list_add_action(
391 struct lttng_action *list, struct lttng_action *action)
392 {
393 struct lttng_action_list *action_list;
394 enum lttng_action_status status;
395 int ret;
396
397 if (!list || !IS_LIST_ACTION(list) || !action) {
398 status = LTTNG_ACTION_STATUS_INVALID;
399 goto end;
400 }
401
402 /*
403 * Don't allow adding lists in lists for now, since we're afraid of
404 * cycles.
405 */
406 if (IS_LIST_ACTION(action)) {
407 status = LTTNG_ACTION_STATUS_INVALID;
408 goto end;
409 }
410
411 action_list = action_list_from_action(list);
412
413 ret = lttng_dynamic_pointer_array_add_pointer(&action_list->actions,
414 action);
415 if (ret < 0) {
416 status = LTTNG_ACTION_STATUS_ERROR;
417 goto end;
418 }
419
420 /* Take ownership of the object. */
421 lttng_action_get(action);
422 status = LTTNG_ACTION_STATUS_OK;
423 end:
424 return status;
425 }
426
427 enum lttng_action_status lttng_action_list_get_count(
428 const struct lttng_action *list, unsigned int *count)
429 {
430 const struct lttng_action_list *action_list;
431 enum lttng_action_status status = LTTNG_ACTION_STATUS_OK;
432
433 if (!list || !IS_LIST_ACTION(list)) {
434 status = LTTNG_ACTION_STATUS_INVALID;
435 *count = 0;
436 goto end;
437 }
438
439 action_list = action_list_from_action_const(list);
440 *count = lttng_dynamic_pointer_array_get_count(&action_list->actions);
441 end:
442 return status;
443 }
444
445 const struct lttng_action *lttng_action_list_get_at_index(
446 const struct lttng_action *list, unsigned int index)
447 {
448 return lttng_action_list_borrow_mutable_at_index(list, index);
449 }
450
451 LTTNG_HIDDEN
452 struct lttng_action *lttng_action_list_borrow_mutable_at_index(
453 const struct lttng_action *list, unsigned int index)
454 {
455 unsigned int count;
456 const struct lttng_action_list *action_list;
457 struct lttng_action *action = NULL;
458
459 if (lttng_action_list_get_count(list, &count) !=
460 LTTNG_ACTION_STATUS_OK) {
461 goto end;
462 }
463
464 if (index >= count) {
465 goto end;
466 }
467
468 action_list = action_list_from_action_const(list);
469 action = lttng_dynamic_pointer_array_get_pointer(&action_list->actions,
470 index);
471 end:
472 return action;
473 }
This page took 0.048589 seconds and 4 git commands to generate.