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