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/payload.h>
11 #include <common/payload-view.h>
12 #include <common/error.h>
13 #include <common/macros.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/list-internal.h>
16 #include <lttng/action/list.h>
18 #define IS_GROUP_ACTION(action) \
19 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_GROUP)
21 struct lttng_action_list
{
22 struct lttng_action parent
;
24 /* The array owns the action elements. */
25 struct lttng_dynamic_pointer_array actions
;
28 struct lttng_action_list_comm
{
29 uint32_t action_count
;
32 * Variable data: each element serialized sequentially.
37 static void destroy_lttng_action_list_element(void *ptr
)
39 struct lttng_action
*element
= (struct lttng_action
*) ptr
;
41 lttng_action_destroy(element
);
44 static struct lttng_action_list
*action_list_from_action(
45 const struct lttng_action
*action
)
49 return container_of(action
, struct lttng_action_list
, parent
);
52 static const struct lttng_action_list
*action_list_from_action_const(
53 const struct lttng_action
*action
)
57 return container_of(action
, struct lttng_action_list
, parent
);
60 static bool lttng_action_list_validate(struct lttng_action
*action
)
62 unsigned int i
, count
;
63 struct lttng_action_list
*action_list
;
66 assert(IS_GROUP_ACTION(action
));
68 action_list
= action_list_from_action(action
);
70 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
72 for (i
= 0; i
< count
; i
++) {
73 struct lttng_action
*child
=
74 lttng_dynamic_pointer_array_get_pointer(
75 &action_list
->actions
, i
);
79 if (!lttng_action_validate(child
)) {
91 static bool lttng_action_list_is_equal(
92 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
) !=
99 LTTNG_ACTION_STATUS_OK
) {
103 if (lttng_action_list_get_count(_b
, &b_count
) !=
104 LTTNG_ACTION_STATUS_OK
) {
108 if (a_count
!= b_count
) {
112 for (i
= 0; i
< a_count
; i
++) {
113 const struct lttng_action
*child_a
=
114 lttng_action_list_get_at_index(_a
, i
);
115 const struct lttng_action
*child_b
=
116 lttng_action_list_get_at_index(_b
, i
);
121 if (!lttng_action_is_equal(child_a
, child_b
)) {
131 static int lttng_action_list_serialize(
132 struct lttng_action
*action
, struct lttng_payload
*payload
)
134 struct lttng_action_list
*action_list
;
135 struct lttng_action_list_comm comm
;
137 unsigned int i
, count
;
141 assert(IS_GROUP_ACTION(action
));
143 action_list
= action_list_from_action(action
);
145 DBG("Serializing action list");
147 count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
149 comm
.action_count
= count
;
151 ret
= lttng_dynamic_buffer_append(
152 &payload
->buffer
, &comm
, sizeof(comm
));
158 for (i
= 0; i
< count
; i
++) {
159 struct lttng_action
*child
=
160 lttng_dynamic_pointer_array_get_pointer(
161 &action_list
->actions
, i
);
165 ret
= lttng_action_serialize(child
, payload
);
177 static void lttng_action_list_destroy(struct lttng_action
*action
)
179 struct lttng_action_list
*action_list
;
185 action_list
= action_list_from_action(action
);
186 lttng_dynamic_pointer_array_reset(&action_list
->actions
);
193 ssize_t
lttng_action_list_create_from_payload(
194 struct lttng_payload_view
*view
,
195 struct lttng_action
**p_action
)
197 ssize_t consumed_len
;
198 const struct lttng_action_list_comm
*comm
;
199 struct lttng_action
*group
;
200 struct lttng_action
*child_action
= NULL
;
201 enum lttng_action_status status
;
204 group
= lttng_action_list_create();
210 comm
= (typeof(comm
)) view
->buffer
.data
;
212 consumed_len
= sizeof(struct lttng_action_list_comm
);
214 for (i
= 0; i
< comm
->action_count
; i
++) {
215 ssize_t consumed_len_child
;
216 struct lttng_payload_view child_view
=
217 lttng_payload_view_from_view(view
, consumed_len
,
218 view
->buffer
.size
- consumed_len
);
220 if (!lttng_payload_view_is_valid(&child_view
)) {
225 consumed_len_child
= lttng_action_create_from_payload(
226 &child_view
, &child_action
);
227 if (consumed_len_child
< 0) {
232 status
= lttng_action_list_add_action(group
, child_action
);
233 if (status
!= LTTNG_ACTION_STATUS_OK
) {
238 /* Transfer ownership to the action list. */
239 lttng_action_put(child_action
);
242 consumed_len
+= consumed_len_child
;
249 lttng_action_list_destroy(group
);
253 static enum lttng_action_status
lttng_action_list_add_error_query_results(
254 const struct lttng_action
*action
,
255 struct lttng_error_query_results
*results
)
257 unsigned int i
, count
;
258 enum lttng_action_status action_status
;
259 const struct lttng_action_list
*group
=
260 container_of(action
, typeof(*group
), parent
);
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 struct lttng_action
*lttng_action_list_create(void)
283 struct lttng_action_list
*action_list
;
284 struct lttng_action
*action
;
286 action_list
= zmalloc(sizeof(struct lttng_action_list
));
292 action
= &action_list
->parent
;
294 lttng_action_init(action
, LTTNG_ACTION_TYPE_GROUP
,
295 lttng_action_list_validate
,
296 lttng_action_list_serialize
,
297 lttng_action_list_is_equal
, lttng_action_list_destroy
,
299 lttng_action_list_add_error_query_results
);
301 lttng_dynamic_pointer_array_init(&action_list
->actions
,
302 destroy_lttng_action_list_element
);
308 enum lttng_action_status
lttng_action_list_add_action(
309 struct lttng_action
*group
, struct lttng_action
*action
)
311 struct lttng_action_list
*action_list
;
312 enum lttng_action_status status
;
315 if (!group
|| !IS_GROUP_ACTION(group
) || !action
) {
316 status
= LTTNG_ACTION_STATUS_INVALID
;
321 * Don't allow adding groups in groups for now, since we're afraid of
324 if (IS_GROUP_ACTION(action
)) {
325 status
= LTTNG_ACTION_STATUS_INVALID
;
329 action_list
= action_list_from_action(group
);
331 ret
= lttng_dynamic_pointer_array_add_pointer(&action_list
->actions
,
334 status
= LTTNG_ACTION_STATUS_ERROR
;
338 /* Take ownership of the object. */
339 lttng_action_get(action
);
340 status
= LTTNG_ACTION_STATUS_OK
;
345 enum lttng_action_status
lttng_action_list_get_count(
346 const struct lttng_action
*group
, unsigned int *count
)
348 const struct lttng_action_list
*action_list
;
349 enum lttng_action_status status
= LTTNG_ACTION_STATUS_OK
;
351 if (!group
|| !IS_GROUP_ACTION(group
)) {
352 status
= LTTNG_ACTION_STATUS_INVALID
;
357 action_list
= action_list_from_action_const(group
);
358 *count
= lttng_dynamic_pointer_array_get_count(&action_list
->actions
);
363 const struct lttng_action
*lttng_action_list_get_at_index(
364 const struct lttng_action
*group
, unsigned int index
)
366 return lttng_action_list_borrow_mutable_at_index(group
, index
);
370 struct lttng_action
*lttng_action_list_borrow_mutable_at_index(
371 const struct lttng_action
*group
, unsigned int index
)
374 const struct lttng_action_list
*action_list
;
375 struct lttng_action
*action
= NULL
;
377 if (lttng_action_list_get_count(group
, &count
) !=
378 LTTNG_ACTION_STATUS_OK
) {
382 if (index
>= count
) {
386 action_list
= action_list_from_action_const(group
);
387 action
= lttng_dynamic_pointer_array_get_pointer(&action_list
->actions
,