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 lttng::utils::container_of(action
, <tng_action_list::parent
);
54 static const struct lttng_action_list
*action_list_from_action_const(
55 const struct lttng_action
*action
)
59 return lttng::utils::container_of(action
, <tng_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
;
262 action_status
= lttng_action_list_get_count(action
, &count
);
263 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
267 for (i
= 0; i
< count
; i
++) {
268 struct lttng_action
*inner_action
=
269 lttng_action_list_borrow_mutable_at_index(action
, i
);
271 action_status
= lttng_action_add_error_query_results(
272 inner_action
, results
);
273 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
278 return action_status
;
281 enum 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
)
290 struct lttng_action_list
*action_list
;
291 unsigned int i
, count
;
292 enum lttng_error_code ret_code
;
294 LTTNG_ASSERT(action
);
295 LTTNG_ASSERT(IS_LIST_ACTION(action
));
296 LTTNG_ASSERT(writer
);
298 /* Open action list. */
299 ret
= mi_lttng_writer_open_element(
300 writer
, mi_lttng_element_action_list
);
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
;
316 * Add the index to the action path.
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.
322 ret
= lttng_dynamic_array_add_element(
323 action_path_indexes
, &index
);
325 ret_code
= LTTNG_ERR_NOMEM
;
329 ret_code
= lttng_action_mi_serialize(trigger
, child
, writer
,
330 error_query_callbacks
, action_path_indexes
);
331 if (ret_code
!= LTTNG_OK
) {
335 ret
= lttng_dynamic_array_remove_element(action_path_indexes
,
336 lttng_dynamic_array_get_count(
337 action_path_indexes
) -
340 ret_code
= LTTNG_ERR_UNK
;
345 /* Close action_list element. */
346 ret
= mi_lttng_writer_close_element(writer
);
355 ret_code
= LTTNG_ERR_MI_IO_FAIL
;
360 struct lttng_action
*lttng_action_list_create(void)
362 struct lttng_action_list
*action_list
;
363 struct lttng_action
*action
;
365 action_list
= zmalloc
<lttng_action_list
>();
371 action
= &action_list
->parent
;
374 * The mi for the list is handled at the lttng_action_mi level to ease
375 * action path management for error query.
377 lttng_action_init(action
, LTTNG_ACTION_TYPE_LIST
,
378 lttng_action_list_validate
, lttng_action_list_serialize
,
379 lttng_action_list_is_equal
, lttng_action_list_destroy
,
380 NULL
, lttng_action_list_add_error_query_results
, NULL
);
382 lttng_dynamic_pointer_array_init(&action_list
->actions
,
383 destroy_lttng_action_list_element
);
389 enum lttng_action_status
lttng_action_list_add_action(
390 struct lttng_action
*list
, struct lttng_action
*action
)
392 struct lttng_action_list
*action_list
;
393 enum lttng_action_status status
;
396 if (!list
|| !IS_LIST_ACTION(list
) || !action
) {
397 status
= LTTNG_ACTION_STATUS_INVALID
;
402 * Don't allow adding lists in lists for now, since we're afraid of
405 if (IS_LIST_ACTION(action
)) {
406 status
= LTTNG_ACTION_STATUS_INVALID
;
410 action_list
= action_list_from_action(list
);
412 ret
= lttng_dynamic_pointer_array_add_pointer(&action_list
->actions
,
415 status
= LTTNG_ACTION_STATUS_ERROR
;
419 /* Take ownership of the object. */
420 lttng_action_get(action
);
421 status
= LTTNG_ACTION_STATUS_OK
;
426 enum lttng_action_status
lttng_action_list_get_count(
427 const struct lttng_action
*list
, unsigned int *count
)
429 const struct lttng_action_list
*action_list
;
430 enum lttng_action_status status
= LTTNG_ACTION_STATUS_OK
;
432 if (!list
|| !IS_LIST_ACTION(list
)) {
433 status
= LTTNG_ACTION_STATUS_INVALID
;
438 action_list
= action_list_from_action_const(list
);
439 *count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
444 const struct lttng_action
*lttng_action_list_get_at_index(
445 const struct lttng_action
*list
, unsigned int index
)
447 return lttng_action_list_borrow_mutable_at_index(list
, index
);
450 struct lttng_action
*lttng_action_list_borrow_mutable_at_index(
451 const struct lttng_action
*list
, unsigned int index
)
454 const struct lttng_action_list
*action_list
;
455 struct lttng_action
*action
= NULL
;
457 if (lttng_action_list_get_count(list
, &count
) !=
458 LTTNG_ACTION_STATUS_OK
) {
462 if (index
>= count
) {
466 action_list
= action_list_from_action_const(list
);
467 action
= (lttng_action
*) lttng_dynamic_pointer_array_get_pointer(&action_list
->actions
,