2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
9 #include <common/dynamic-array.h>
10 #include <common/error.h>
11 #include <common/macros.h>
12 #include <common/mi-lttng.h>
13 #include <common/payload-view.h>
14 #include <common/payload.h>
15 #include <lttng/action/action-internal.h>
16 #include <lttng/action/list-internal.h>
17 #include <lttng/action/list.h>
19 #define IS_LIST_ACTION(action) \
20 (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.
38 static void destroy_lttng_action_list_element(void *ptr
)
40 struct lttng_action
*element
= (struct lttng_action
*) ptr
;
42 lttng_action_destroy(element
);
45 static struct lttng_action_list
*action_list_from_action(
46 const struct lttng_action
*action
)
50 return container_of(action
, struct lttng_action_list
, parent
);
53 static const struct lttng_action_list
*action_list_from_action_const(
54 const struct lttng_action
*action
)
58 return container_of(action
, struct lttng_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 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_dynamic_pointer_array_get_pointer(
76 &action_list
->actions
, i
);
80 if (!lttng_action_validate(child
)) {
92 static bool lttng_action_list_is_equal(
93 const struct lttng_action
*_a
, const struct lttng_action
*_b
)
95 bool is_equal
= false;
97 unsigned int a_count
, b_count
;
99 if (lttng_action_list_get_count(_a
, &a_count
) !=
100 LTTNG_ACTION_STATUS_OK
) {
104 if (lttng_action_list_get_count(_b
, &b_count
) !=
105 LTTNG_ACTION_STATUS_OK
) {
109 if (a_count
!= b_count
) {
113 for (i
= 0; i
< a_count
; i
++) {
114 const struct lttng_action
*child_a
=
115 lttng_action_list_get_at_index(_a
, i
);
116 const struct lttng_action
*child_b
=
117 lttng_action_list_get_at_index(_b
, i
);
122 if (!lttng_action_is_equal(child_a
, child_b
)) {
132 static int lttng_action_list_serialize(
133 struct lttng_action
*action
, struct lttng_payload
*payload
)
135 struct lttng_action_list
*action_list
;
136 struct lttng_action_list_comm comm
;
138 unsigned int i
, count
;
142 assert(IS_LIST_ACTION(action
));
144 action_list
= action_list_from_action(action
);
146 DBG("Serializing action list");
148 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
150 comm
.action_count
= count
;
152 ret
= lttng_dynamic_buffer_append(
153 &payload
->buffer
, &comm
, sizeof(comm
));
159 for (i
= 0; i
< count
; i
++) {
160 struct lttng_action
*child
=
161 lttng_dynamic_pointer_array_get_pointer(
162 &action_list
->actions
, i
);
166 ret
= lttng_action_serialize(child
, payload
);
178 static void lttng_action_list_destroy(struct lttng_action
*action
)
180 struct lttng_action_list
*action_list
;
186 action_list
= action_list_from_action(action
);
187 lttng_dynamic_pointer_array_reset(&action_list
->actions
);
194 ssize_t
lttng_action_list_create_from_payload(
195 struct lttng_payload_view
*view
,
196 struct lttng_action
**p_action
)
198 ssize_t consumed_len
;
199 const struct lttng_action_list_comm
*comm
;
200 struct lttng_action
*list
;
201 struct lttng_action
*child_action
= NULL
;
202 enum lttng_action_status status
;
205 list
= lttng_action_list_create();
211 comm
= (typeof(comm
)) view
->buffer
.data
;
213 consumed_len
= sizeof(struct lttng_action_list_comm
);
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
);
221 if (!lttng_payload_view_is_valid(&child_view
)) {
226 consumed_len_child
= lttng_action_create_from_payload(
227 &child_view
, &child_action
);
228 if (consumed_len_child
< 0) {
233 status
= lttng_action_list_add_action(list
, child_action
);
234 if (status
!= LTTNG_ACTION_STATUS_OK
) {
239 /* Transfer ownership to the action list. */
240 lttng_action_put(child_action
);
243 consumed_len
+= consumed_len_child
;
250 lttng_action_list_destroy(list
);
254 static enum lttng_action_status
lttng_action_list_add_error_query_results(
255 const struct lttng_action
*action
,
256 struct lttng_error_query_results
*results
)
258 unsigned int i
, count
;
259 enum lttng_action_status action_status
;
260 const struct lttng_action_list
*list
=
261 container_of(action
, typeof(*list
), parent
);
263 action_status
= lttng_action_list_get_count(action
, &count
);
264 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
268 for (i
= 0; i
< count
; i
++) {
269 struct lttng_action
*inner_action
=
270 lttng_action_list_borrow_mutable_at_index(action
, i
);
272 action_status
= lttng_action_add_error_query_results(
273 inner_action
, results
);
274 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
279 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
;
297 assert(IS_LIST_ACTION(action
));
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(sizeof(struct 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
);
453 struct lttng_action
*lttng_action_list_borrow_mutable_at_index(
454 const struct lttng_action
*list
, unsigned int index
)
457 const struct lttng_action_list
*action_list
;
458 struct lttng_action
*action
= NULL
;
460 if (lttng_action_list_get_count(list
, &count
) !=
461 LTTNG_ACTION_STATUS_OK
) {
465 if (index
>= count
) {
469 action_list
= action_list_from_action_const(list
);
470 action
= lttng_dynamic_pointer_array_get_pointer(&action_list
->actions
,