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>
14 #include <lttng/action/action-internal.hpp>
15 #include <lttng/action/list-internal.hpp>
16 #include <lttng/action/list.h>
18 #define IS_LIST_ACTION(action) \
19 (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(
47 const struct lttng_action
*action
)
51 return container_of(action
, struct lttng_action_list
, parent
);
54 static const struct lttng_action_list
*action_list_from_action_const(
55 const struct lttng_action
*action
)
59 return container_of(action
, struct lttng_action_list
, parent
);
62 static bool lttng_action_list_validate(struct lttng_action
*action
)
64 unsigned int i
, count
;
65 struct lttng_action_list
*action_list
;
68 LTTNG_ASSERT(IS_LIST_ACTION(action
));
70 action_list
= action_list_from_action(action
);
72 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
74 for (i
= 0; i
< count
; i
++) {
75 struct lttng_action
*child
=
76 (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(
77 &action_list
->actions
, i
);
81 if (!lttng_action_validate(child
)) {
93 static bool lttng_action_list_is_equal(
94 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
96 bool is_equal
= false;
98 unsigned int a_count
, b_count
;
100 if (lttng_action_list_get_count(_a
, &a_count
) !=
101 LTTNG_ACTION_STATUS_OK
) {
105 if (lttng_action_list_get_count(_b
, &b_count
) !=
106 LTTNG_ACTION_STATUS_OK
) {
110 if (a_count
!= b_count
) {
114 for (i
= 0; i
< a_count
; i
++) {
115 const struct lttng_action
*child_a
=
116 lttng_action_list_get_at_index(_a
, i
);
117 const struct lttng_action
*child_b
=
118 lttng_action_list_get_at_index(_b
, i
);
120 LTTNG_ASSERT(child_a
);
121 LTTNG_ASSERT(child_b
);
123 if (!lttng_action_is_equal(child_a
, child_b
)) {
133 static int lttng_action_list_serialize(
134 struct lttng_action
*action
, struct lttng_payload
*payload
)
136 struct lttng_action_list
*action_list
;
137 struct lttng_action_list_comm comm
;
139 unsigned int i
, count
;
141 LTTNG_ASSERT(action
);
142 LTTNG_ASSERT(payload
);
143 LTTNG_ASSERT(IS_LIST_ACTION(action
));
145 action_list
= action_list_from_action(action
);
147 DBG("Serializing action list");
149 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
151 comm
.action_count
= count
;
153 ret
= lttng_dynamic_buffer_append(
154 &payload
->buffer
, &comm
, sizeof(comm
));
160 for (i
= 0; i
< count
; i
++) {
161 struct lttng_action
*child
=
162 (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(
163 &action_list
->actions
, i
);
167 ret
= lttng_action_serialize(child
, payload
);
179 static void lttng_action_list_destroy(struct lttng_action
*action
)
181 struct lttng_action_list
*action_list
;
187 action_list
= action_list_from_action(action
);
188 lttng_dynamic_pointer_array_reset(&action_list
->actions
);
195 ssize_t
lttng_action_list_create_from_payload(
196 struct lttng_payload_view
*view
,
197 struct lttng_action
**p_action
)
199 ssize_t consumed_len
;
200 const struct lttng_action_list_comm
*comm
;
201 struct lttng_action
*list
;
202 struct lttng_action
*child_action
= NULL
;
203 enum lttng_action_status status
;
206 list
= lttng_action_list_create();
212 comm
= (typeof(comm
)) view
->buffer
.data
;
214 consumed_len
= sizeof(struct lttng_action_list_comm
);
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
);
222 if (!lttng_payload_view_is_valid(&child_view
)) {
227 consumed_len_child
= lttng_action_create_from_payload(
228 &child_view
, &child_action
);
229 if (consumed_len_child
< 0) {
234 status
= lttng_action_list_add_action(list
, child_action
);
235 if (status
!= LTTNG_ACTION_STATUS_OK
) {
240 /* Transfer ownership to the action list. */
241 lttng_action_put(child_action
);
244 consumed_len
+= consumed_len_child
;
251 lttng_action_list_destroy(list
);
255 static enum lttng_action_status
lttng_action_list_add_error_query_results(
256 const struct lttng_action
*action
,
257 struct lttng_error_query_results
*results
)
259 unsigned int i
, count
;
260 enum lttng_action_status action_status
;
261 const struct lttng_action_list
*list
=
262 container_of(action
, typeof(*list
), parent
);
264 action_status
= lttng_action_list_get_count(action
, &count
);
265 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
269 for (i
= 0; i
< count
; i
++) {
270 struct lttng_action
*inner_action
=
271 lttng_action_list_borrow_mutable_at_index(action
, i
);
273 action_status
= lttng_action_add_error_query_results(
274 inner_action
, results
);
275 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
280 return action_status
;
283 enum 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
)
292 struct lttng_action_list
*action_list
;
293 unsigned int i
, count
;
294 enum lttng_error_code ret_code
;
296 LTTNG_ASSERT(action
);
297 LTTNG_ASSERT(IS_LIST_ACTION(action
));
298 LTTNG_ASSERT(writer
);
300 /* Open action list. */
301 ret
= mi_lttng_writer_open_element(
302 writer
, mi_lttng_element_action_list
);
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
;
318 * Add the index to the action path.
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.
324 ret
= lttng_dynamic_array_add_element(
325 action_path_indexes
, &index
);
327 ret_code
= LTTNG_ERR_NOMEM
;
331 ret_code
= lttng_action_mi_serialize(trigger
, child
, writer
,
332 error_query_callbacks
, action_path_indexes
);
333 if (ret_code
!= LTTNG_OK
) {
337 ret
= lttng_dynamic_array_remove_element(action_path_indexes
,
338 lttng_dynamic_array_get_count(
339 action_path_indexes
) -
342 ret_code
= LTTNG_ERR_UNK
;
347 /* Close action_list element. */
348 ret
= mi_lttng_writer_close_element(writer
);
357 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
362 struct lttng_action
*lttng_action_list_create(void)
364 struct lttng_action_list
*action_list
;
365 struct lttng_action
*action
;
367 action_list
= zmalloc
<lttng_action_list
>();
373 action
= &action_list
->parent
;
376 * The mi for the list is handled at the lttng_action_mi level to ease
377 * action path management for error query.
379 lttng_action_init(action
, LTTNG_ACTION_TYPE_LIST
,
380 lttng_action_list_validate
, lttng_action_list_serialize
,
381 lttng_action_list_is_equal
, lttng_action_list_destroy
,
382 NULL
, lttng_action_list_add_error_query_results
, NULL
);
384 lttng_dynamic_pointer_array_init(&action_list
->actions
,
385 destroy_lttng_action_list_element
);
391 enum lttng_action_status
lttng_action_list_add_action(
392 struct lttng_action
*list
, struct lttng_action
*action
)
394 struct lttng_action_list
*action_list
;
395 enum lttng_action_status status
;
398 if (!list
|| !IS_LIST_ACTION(list
) || !action
) {
399 status
= LTTNG_ACTION_STATUS_INVALID
;
404 * Don't allow adding lists in lists for now, since we're afraid of
407 if (IS_LIST_ACTION(action
)) {
408 status
= LTTNG_ACTION_STATUS_INVALID
;
412 action_list
= action_list_from_action(list
);
414 ret
= lttng_dynamic_pointer_array_add_pointer(&action_list
->actions
,
417 status
= LTTNG_ACTION_STATUS_ERROR
;
421 /* Take ownership of the object. */
422 lttng_action_get(action
);
423 status
= LTTNG_ACTION_STATUS_OK
;
428 enum lttng_action_status
lttng_action_list_get_count(
429 const struct lttng_action
*list
, unsigned int *count
)
431 const struct lttng_action_list
*action_list
;
432 enum lttng_action_status status
= LTTNG_ACTION_STATUS_OK
;
434 if (!list
|| !IS_LIST_ACTION(list
)) {
435 status
= LTTNG_ACTION_STATUS_INVALID
;
440 action_list
= action_list_from_action_const(list
);
441 *count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
446 const struct lttng_action
*lttng_action_list_get_at_index(
447 const struct lttng_action
*list
, unsigned int index
)
449 return lttng_action_list_borrow_mutable_at_index(list
, index
);
452 struct lttng_action
*lttng_action_list_borrow_mutable_at_index(
453 const struct lttng_action
*list
, unsigned int index
)
456 const struct lttng_action_list
*action_list
;
457 struct lttng_action
*action
= NULL
;
459 if (lttng_action_list_get_count(list
, &count
) !=
460 LTTNG_ACTION_STATUS_OK
) {
464 if (index
>= count
) {
468 action_list
= action_list_from_action_const(list
);
469 action
= (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(&action_list
->actions
,