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