actions: introduce action group
[lttng-tools.git] / src / common / actions / group.c
1 /*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/dynamic-array.h>
10 #include <common/sessiond-comm/payload.h>
11 #include <common/sessiond-comm/payload-view.h>
12 #include <common/error.h>
13 #include <common/macros.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/group-internal.h>
16 #include <lttng/action/group.h>
17
18 #define IS_GROUP_ACTION(action) \
19 (lttng_action_get_type_const(action) == LTTNG_ACTION_TYPE_GROUP)
20
21 struct lttng_action_group {
22 struct lttng_action parent;
23
24 /* The array owns the action elements. */
25 struct lttng_dynamic_pointer_array actions;
26 };
27
28 struct lttng_action_group_comm {
29 uint32_t action_count;
30
31 /*
32 * Variable data: each element serialized sequentially.
33 */
34 char data[];
35 } LTTNG_PACKED;
36
37 static void destroy_lttng_action_group_element(void *ptr)
38 {
39 struct lttng_action *element = (struct lttng_action *) ptr;
40
41 lttng_action_destroy(element);
42 }
43
44 static struct lttng_action_group *action_group_from_action(
45 const struct lttng_action *action)
46 {
47 assert(action);
48
49 return container_of(action, struct lttng_action_group, parent);
50 }
51
52 static const struct lttng_action_group *action_group_from_action_const(
53 const struct lttng_action *action)
54 {
55 assert(action);
56
57 return container_of(action, struct lttng_action_group, parent);
58 }
59
60 static bool lttng_action_group_validate(struct lttng_action *action)
61 {
62 unsigned int i, count;
63 struct lttng_action_group *action_group;
64 bool valid;
65
66 assert(IS_GROUP_ACTION(action));
67
68 action_group = action_group_from_action(action);
69
70 count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
71
72 for (i = 0; i < count; i++) {
73 struct lttng_action *child =
74 lttng_dynamic_pointer_array_get_pointer(
75 &action_group->actions, i);
76
77 assert(child);
78
79 if (!lttng_action_validate(child)) {
80 valid = false;
81 goto end;
82 }
83 }
84
85 valid = true;
86
87 end:
88 return valid;
89 }
90
91 static bool lttng_action_group_is_equal(
92 const struct lttng_action *_a, const struct lttng_action *_b)
93 {
94 bool is_equal = false;
95 unsigned int i;
96 unsigned int a_count, b_count;
97
98 if (lttng_action_group_get_count(_a, &a_count) !=
99 LTTNG_ACTION_STATUS_OK) {
100 goto end;
101 }
102
103 if (lttng_action_group_get_count(_b, &b_count) !=
104 LTTNG_ACTION_STATUS_OK) {
105 goto end;
106 }
107
108 if (a_count != b_count) {
109 goto end;
110 }
111
112 for (i = 0; i < a_count; i++) {
113 const struct lttng_action *child_a =
114 lttng_action_group_get_at_index(_a, i);
115 const struct lttng_action *child_b =
116 lttng_action_group_get_at_index(_b, i);
117
118 assert(child_a);
119 assert(child_b);
120
121 if (!lttng_action_is_equal(child_a, child_b)) {
122 goto end;
123 }
124 }
125
126 is_equal = true;
127 end:
128 return is_equal;
129 }
130
131 static int lttng_action_group_serialize(
132 struct lttng_action *action, struct lttng_payload *payload)
133 {
134 struct lttng_action_group *action_group;
135 struct lttng_action_group_comm comm;
136 int ret;
137 unsigned int i, count;
138
139 assert(action);
140 assert(payload);
141 assert(IS_GROUP_ACTION(action));
142
143 action_group = action_group_from_action(action);
144
145 DBG("Serializing action group");
146
147 count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
148
149 comm.action_count = count;
150
151 ret = lttng_dynamic_buffer_append(
152 &payload->buffer, &comm, sizeof(comm));
153 if (ret) {
154 ret = -1;
155 goto end;
156 }
157
158 for (i = 0; i < count; i++) {
159 struct lttng_action *child =
160 lttng_dynamic_pointer_array_get_pointer(
161 &action_group->actions, i);
162
163 assert(child);
164
165 ret = lttng_action_serialize(child, payload);
166 if (ret) {
167 goto end;
168 }
169 }
170
171 ret = 0;
172
173 end:
174 return ret;
175 }
176
177 static void lttng_action_group_destroy(struct lttng_action *action)
178 {
179 struct lttng_action_group *action_group;
180
181 if (!action) {
182 goto end;
183 }
184
185 action_group = action_group_from_action(action);
186 lttng_dynamic_pointer_array_reset(&action_group->actions);
187 free(action_group);
188
189 end:
190 return;
191 }
192
193 ssize_t lttng_action_group_create_from_payload(
194 struct lttng_payload_view *view,
195 struct lttng_action **p_action)
196 {
197 ssize_t consumed_len;
198 const struct lttng_action_group_comm *comm;
199 struct lttng_action *group;
200 struct lttng_action *child_action = NULL;
201 enum lttng_action_status status;
202 size_t i;
203
204 group = lttng_action_group_create();
205 if (!group) {
206 consumed_len = -1;
207 goto end;
208 }
209
210 comm = (typeof(comm)) view->buffer.data;
211
212 consumed_len = sizeof(struct lttng_action_group_comm);
213
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);
219
220 consumed_len_child = lttng_action_create_from_payload(
221 &child_view, &child_action);
222 if (consumed_len_child < 0) {
223 consumed_len = -1;
224 goto end;
225 }
226
227 status = lttng_action_group_add_action(group, child_action);
228 if (status != LTTNG_ACTION_STATUS_OK) {
229 consumed_len = -1;
230 goto end;
231 }
232
233 /* Transfer ownership to the action group. */
234 lttng_action_put(child_action);
235 child_action = NULL;
236
237 consumed_len += consumed_len_child;
238 }
239
240 *p_action = group;
241 group = NULL;
242
243 end:
244 lttng_action_group_destroy(group);
245 return consumed_len;
246 }
247
248 struct lttng_action *lttng_action_group_create(void)
249 {
250 struct lttng_action_group *action_group;
251 struct lttng_action *action;
252
253 action_group = zmalloc(sizeof(struct lttng_action_group));
254 if (!action_group) {
255 action = NULL;
256 goto end;
257 }
258
259 action = &action_group->parent;
260
261 lttng_action_init(action, LTTNG_ACTION_TYPE_GROUP,
262 lttng_action_group_validate,
263 lttng_action_group_serialize,
264 lttng_action_group_is_equal,
265 lttng_action_group_destroy);
266
267 lttng_dynamic_pointer_array_init(&action_group->actions,
268 destroy_lttng_action_group_element);
269
270 end:
271 return action;
272 }
273
274 enum lttng_action_status lttng_action_group_add_action(
275 struct lttng_action *group, struct lttng_action *action)
276 {
277 struct lttng_action_group *action_group;
278 enum lttng_action_status status;
279 int ret;
280
281 if (!group || !IS_GROUP_ACTION(action) || !action) {
282 status = LTTNG_ACTION_STATUS_INVALID;
283 goto end;
284 }
285
286 /*
287 * Don't allow adding groups in groups for now, since we're afraid of
288 * cycles.
289 */
290 if (IS_GROUP_ACTION(action)) {
291 status = LTTNG_ACTION_STATUS_INVALID;
292 goto end;
293 }
294
295 action_group = action_group_from_action(group);
296
297 ret = lttng_dynamic_pointer_array_add_pointer(&action_group->actions,
298 action);
299 if (ret < 0) {
300 status = LTTNG_ACTION_STATUS_ERROR;
301 goto end;
302 }
303
304 /* Take ownership of the object. */
305 lttng_action_get(action);
306 status = LTTNG_ACTION_STATUS_OK;
307 end:
308 return status;
309 }
310
311 enum lttng_action_status lttng_action_group_get_count(
312 const struct lttng_action *group, unsigned int *count)
313 {
314 const struct lttng_action_group *action_group;
315 enum lttng_action_status status = LTTNG_ACTION_STATUS_OK;
316
317 if (!group || !IS_GROUP_ACTION(group)) {
318 status = LTTNG_ACTION_STATUS_INVALID;
319 *count = 0;
320 goto end;
321 }
322
323 action_group = action_group_from_action_const(group);
324 *count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
325 end:
326 return status;
327 }
328
329 const struct lttng_action *lttng_action_group_get_at_index(
330 const struct lttng_action *group, unsigned int index)
331 {
332 unsigned int count;
333 const struct lttng_action_group *action_group;
334 const struct lttng_action * action = NULL;
335
336 if (lttng_action_group_get_count(group, &count) !=
337 LTTNG_ACTION_STATUS_OK) {
338 goto end;
339 }
340
341 if (index >= count) {
342 goto end;
343 }
344
345 action_group = action_group_from_action_const(group);
346 action = lttng_dynamic_pointer_array_get_pointer(&action_group->actions,
347 index);
348 end:
349 return action;
350 }
This page took 0.035624 seconds and 4 git commands to generate.