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