2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
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>
15 #include <lttng/action/action-internal.hpp>
16 #include <lttng/action/list-internal.hpp>
17 #include <lttng/action/list.h>
19 #define IS_LIST_ACTION(action) (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_LIST)
22 struct lttng_action_list
{
23 struct lttng_action parent
;
25 /* The array owns the action elements. */
26 struct lttng_dynamic_pointer_array actions
;
29 struct lttng_action_list_comm
{
30 uint32_t action_count
;
33 * Variable data: each element serialized sequentially.
39 static void destroy_lttng_action_list_element(void *ptr
)
41 struct lttng_action
*element
= (struct lttng_action
*) ptr
;
43 lttng_action_destroy(element
);
46 static struct lttng_action_list
*action_list_from_action(const struct lttng_action
*action
)
50 return lttng::utils::container_of(action
, <tng_action_list::parent
);
53 static const struct lttng_action_list
*
54 action_list_from_action_const(const struct lttng_action
*action
)
58 return lttng::utils::container_of(action
, <tng_action_list::parent
);
61 static bool lttng_action_list_validate(struct lttng_action
*action
)
63 unsigned int i
, count
;
64 struct lttng_action_list
*action_list
;
67 LTTNG_ASSERT(IS_LIST_ACTION(action
));
69 action_list
= action_list_from_action(action
);
71 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
73 for (i
= 0; i
< count
; i
++) {
74 struct lttng_action
*child
=
75 (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(
76 &action_list
->actions
, i
);
80 if (!lttng_action_validate(child
)) {
92 static bool lttng_action_list_is_equal(const struct lttng_action
*_a
, const struct lttng_action
*_b
)
94 bool is_equal
= false;
96 unsigned int a_count
, b_count
;
98 if (lttng_action_list_get_count(_a
, &a_count
) != LTTNG_ACTION_STATUS_OK
) {
102 if (lttng_action_list_get_count(_b
, &b_count
) != LTTNG_ACTION_STATUS_OK
) {
106 if (a_count
!= b_count
) {
110 for (i
= 0; i
< a_count
; i
++) {
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
);
114 LTTNG_ASSERT(child_a
);
115 LTTNG_ASSERT(child_b
);
117 if (!lttng_action_is_equal(child_a
, child_b
)) {
127 static int lttng_action_list_serialize(struct lttng_action
*action
, struct lttng_payload
*payload
)
129 struct lttng_action_list
*action_list
;
130 struct lttng_action_list_comm comm
;
132 unsigned int i
, count
;
134 LTTNG_ASSERT(action
);
135 LTTNG_ASSERT(payload
);
136 LTTNG_ASSERT(IS_LIST_ACTION(action
));
138 action_list
= action_list_from_action(action
);
140 DBG("Serializing action list");
142 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
144 comm
.action_count
= count
;
146 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &comm
, sizeof(comm
));
152 for (i
= 0; i
< count
; i
++) {
153 struct lttng_action
*child
=
154 (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(
155 &action_list
->actions
, i
);
159 ret
= lttng_action_serialize(child
, payload
);
171 static void lttng_action_list_destroy(struct lttng_action
*action
)
173 struct lttng_action_list
*action_list
;
179 action_list
= action_list_from_action(action
);
180 lttng_dynamic_pointer_array_reset(&action_list
->actions
);
187 ssize_t
lttng_action_list_create_from_payload(struct lttng_payload_view
*view
,
188 struct lttng_action
**p_action
)
190 ssize_t consumed_len
;
191 const struct lttng_action_list_comm
*comm
;
192 struct lttng_action
*list
;
193 struct lttng_action
*child_action
= nullptr;
194 enum lttng_action_status status
;
197 list
= lttng_action_list_create();
203 comm
= (typeof(comm
)) view
->buffer
.data
;
205 consumed_len
= sizeof(struct lttng_action_list_comm
);
207 for (i
= 0; i
< comm
->action_count
; i
++) {
208 ssize_t consumed_len_child
;
209 struct lttng_payload_view child_view
= lttng_payload_view_from_view(
210 view
, consumed_len
, view
->buffer
.size
- consumed_len
);
212 if (!lttng_payload_view_is_valid(&child_view
)) {
217 consumed_len_child
= lttng_action_create_from_payload(&child_view
, &child_action
);
218 if (consumed_len_child
< 0) {
223 status
= lttng_action_list_add_action(list
, child_action
);
224 if (status
!= LTTNG_ACTION_STATUS_OK
) {
229 /* Transfer ownership to the action list. */
230 lttng_action_put(child_action
);
231 child_action
= nullptr;
233 consumed_len
+= consumed_len_child
;
240 lttng_action_list_destroy(list
);
244 static enum lttng_action_status
245 lttng_action_list_add_error_query_results(const struct lttng_action
*action
,
246 struct lttng_error_query_results
*results
)
248 unsigned int i
, count
;
249 enum lttng_action_status action_status
;
251 action_status
= lttng_action_list_get_count(action
, &count
);
252 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
256 for (i
= 0; i
< count
; i
++) {
257 struct lttng_action
*inner_action
=
258 lttng_action_list_borrow_mutable_at_index(action
, i
);
260 action_status
= lttng_action_add_error_query_results(inner_action
, results
);
261 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
266 return action_status
;
269 enum lttng_error_code
270 lttng_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
)
277 struct lttng_action_list
*action_list
;
278 unsigned int i
, count
;
279 enum lttng_error_code ret_code
;
281 LTTNG_ASSERT(action
);
282 LTTNG_ASSERT(IS_LIST_ACTION(action
));
283 LTTNG_ASSERT(writer
);
285 /* Open action list. */
286 ret
= mi_lttng_writer_open_element(writer
, mi_lttng_element_action_list
);
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
++) {
295 const struct lttng_action
*child
= lttng_action_list_get_at_index(action
, i
);
296 const uint64_t index
= (uint64_t) i
;
301 * Add the index to the action path.
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.
307 ret
= lttng_dynamic_array_add_element(action_path_indexes
, &index
);
309 ret_code
= LTTNG_ERR_NOMEM
;
313 ret_code
= lttng_action_mi_serialize(
314 trigger
, child
, writer
, error_query_callbacks
, action_path_indexes
);
315 if (ret_code
!= LTTNG_OK
) {
319 ret
= lttng_dynamic_array_remove_element(
321 lttng_dynamic_array_get_count(action_path_indexes
) - 1);
323 ret_code
= LTTNG_ERR_UNK
;
328 /* Close action_list element. */
329 ret
= mi_lttng_writer_close_element(writer
);
338 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
343 struct lttng_action
*lttng_action_list_create(void)
345 struct lttng_action_list
*action_list
;
346 struct lttng_action
*action
;
348 action_list
= zmalloc
<lttng_action_list
>();
354 action
= &action_list
->parent
;
357 * The mi for the list is handled at the lttng_action_mi level to ease
358 * action path management for error query.
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
,
367 lttng_action_list_add_error_query_results
,
370 lttng_dynamic_pointer_array_init(&action_list
->actions
, destroy_lttng_action_list_element
);
376 enum lttng_action_status
lttng_action_list_add_action(struct lttng_action
*list
,
377 struct lttng_action
*action
)
379 struct lttng_action_list
*action_list
;
380 enum lttng_action_status status
;
383 if (!list
|| !IS_LIST_ACTION(list
) || !action
) {
384 status
= LTTNG_ACTION_STATUS_INVALID
;
389 * Don't allow adding lists in lists for now, since we're afraid of
392 if (IS_LIST_ACTION(action
)) {
393 status
= LTTNG_ACTION_STATUS_INVALID
;
397 action_list
= action_list_from_action(list
);
399 ret
= lttng_dynamic_pointer_array_add_pointer(&action_list
->actions
, action
);
401 status
= LTTNG_ACTION_STATUS_ERROR
;
405 /* Take ownership of the object. */
406 lttng_action_get(action
);
407 status
= LTTNG_ACTION_STATUS_OK
;
412 enum lttng_action_status
lttng_action_list_get_count(const struct lttng_action
*list
,
415 const struct lttng_action_list
*action_list
;
416 enum lttng_action_status status
= LTTNG_ACTION_STATUS_OK
;
418 if (!list
|| !IS_LIST_ACTION(list
)) {
419 status
= LTTNG_ACTION_STATUS_INVALID
;
424 action_list
= action_list_from_action_const(list
);
425 *count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
430 const struct lttng_action
*lttng_action_list_get_at_index(const struct lttng_action
*list
,
433 return lttng_action_list_borrow_mutable_at_index(list
, index
);
436 struct lttng_action
*lttng_action_list_borrow_mutable_at_index(const struct lttng_action
*list
,
440 const struct lttng_action_list
*action_list
;
441 struct lttng_action
*action
= nullptr;
443 if (lttng_action_list_get_count(list
, &count
) != LTTNG_ACTION_STATUS_OK
) {
447 if (index
>= count
) {
451 action_list
= action_list_from_action_const(list
);
452 action
= (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(&action_list
->actions
,