MI: implement all objects related to trigger machine interface
[lttng-tools.git] / src / common / actions / action.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <assert.h>
9 #include <common/error.h>
10 #include <common/mi-lttng.h>
11 #include <lttng/action/action-internal.h>
12 #include <lttng/action/list-internal.h>
13 #include <lttng/action/notify-internal.h>
14 #include <lttng/action/rate-policy-internal.h>
15 #include <lttng/action/rotate-session-internal.h>
16 #include <lttng/action/snapshot-session-internal.h>
17 #include <lttng/action/start-session-internal.h>
18 #include <lttng/action/stop-session-internal.h>
19 #include <lttng/error-query-internal.h>
20
21 LTTNG_HIDDEN
22 const char *lttng_action_type_string(enum lttng_action_type action_type)
23 {
24 switch (action_type) {
25 case LTTNG_ACTION_TYPE_UNKNOWN:
26 return "UNKNOWN";
27 case LTTNG_ACTION_TYPE_LIST:
28 return "LIST";
29 case LTTNG_ACTION_TYPE_NOTIFY:
30 return "NOTIFY";
31 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
32 return "ROTATE_SESSION";
33 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
34 return "SNAPSHOT_SESSION";
35 case LTTNG_ACTION_TYPE_START_SESSION:
36 return "START_SESSION";
37 case LTTNG_ACTION_TYPE_STOP_SESSION:
38 return "STOP_SESSION";
39 default:
40 return "???";
41 }
42 }
43
44 enum lttng_action_type lttng_action_get_type(const struct lttng_action *action)
45 {
46 return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN;
47 }
48
49 LTTNG_HIDDEN
50 void lttng_action_init(struct lttng_action *action,
51 enum lttng_action_type type,
52 action_validate_cb validate,
53 action_serialize_cb serialize,
54 action_equal_cb equal,
55 action_destroy_cb destroy,
56 action_get_rate_policy_cb get_rate_policy,
57 action_add_error_query_results_cb add_error_query_results,
58 action_mi_serialize_cb mi)
59 {
60 urcu_ref_init(&action->ref);
61 action->type = type;
62 action->validate = validate;
63 action->serialize = serialize;
64 action->equal = equal;
65 action->destroy = destroy;
66 action->get_rate_policy = get_rate_policy;
67 action->add_error_query_results = add_error_query_results;
68 action->mi_serialize = mi;
69
70 action->execution_request_counter = 0;
71 action->execution_counter = 0;
72 action->execution_failure_counter = 0;
73 }
74
75 static
76 void action_destroy_ref(struct urcu_ref *ref)
77 {
78 struct lttng_action *action =
79 container_of(ref, struct lttng_action, ref);
80
81 action->destroy(action);
82 }
83
84 LTTNG_HIDDEN
85 void lttng_action_get(struct lttng_action *action)
86 {
87 urcu_ref_get(&action->ref);
88 }
89
90 LTTNG_HIDDEN
91 void lttng_action_put(struct lttng_action *action)
92 {
93 if (!action) {
94 return;
95 }
96
97 assert(action->destroy);
98 urcu_ref_put(&action->ref, action_destroy_ref);
99 }
100
101 void lttng_action_destroy(struct lttng_action *action)
102 {
103 lttng_action_put(action);
104 }
105
106 LTTNG_HIDDEN
107 bool lttng_action_validate(struct lttng_action *action)
108 {
109 bool valid;
110
111 if (!action) {
112 valid = false;
113 goto end;
114 }
115
116 if (!action->validate) {
117 /* Sub-class guarantees that it can never be invalid. */
118 valid = true;
119 goto end;
120 }
121
122 valid = action->validate(action);
123 end:
124 return valid;
125 }
126
127 LTTNG_HIDDEN
128 int lttng_action_serialize(struct lttng_action *action,
129 struct lttng_payload *payload)
130 {
131 int ret;
132 struct lttng_action_comm action_comm = {
133 .action_type = (int8_t) action->type,
134 };
135
136 ret = lttng_dynamic_buffer_append(&payload->buffer, &action_comm,
137 sizeof(action_comm));
138 if (ret) {
139 goto end;
140 }
141
142 ret = action->serialize(action, payload);
143 if (ret) {
144 goto end;
145 }
146 end:
147 return ret;
148 }
149
150 LTTNG_HIDDEN
151 ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view,
152 struct lttng_action **action)
153 {
154 ssize_t consumed_len, specific_action_consumed_len;
155 action_create_from_payload_cb create_from_payload_cb;
156 const struct lttng_action_comm *action_comm;
157 const struct lttng_payload_view action_comm_view =
158 lttng_payload_view_from_view(
159 view, 0, sizeof(*action_comm));
160
161 if (!view || !action) {
162 consumed_len = -1;
163 goto end;
164 }
165
166 if (!lttng_payload_view_is_valid(&action_comm_view)) {
167 /* Payload not large enough to contain the header. */
168 consumed_len = -1;
169 goto end;
170 }
171
172 action_comm = (const struct lttng_action_comm *) action_comm_view.buffer.data;
173
174 DBG("Create action from payload: action-type=%s",
175 lttng_action_type_string(action_comm->action_type));
176
177 switch (action_comm->action_type) {
178 case LTTNG_ACTION_TYPE_NOTIFY:
179 create_from_payload_cb = lttng_action_notify_create_from_payload;
180 break;
181 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
182 create_from_payload_cb =
183 lttng_action_rotate_session_create_from_payload;
184 break;
185 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
186 create_from_payload_cb =
187 lttng_action_snapshot_session_create_from_payload;
188 break;
189 case LTTNG_ACTION_TYPE_START_SESSION:
190 create_from_payload_cb =
191 lttng_action_start_session_create_from_payload;
192 break;
193 case LTTNG_ACTION_TYPE_STOP_SESSION:
194 create_from_payload_cb =
195 lttng_action_stop_session_create_from_payload;
196 break;
197 case LTTNG_ACTION_TYPE_LIST:
198 create_from_payload_cb = lttng_action_list_create_from_payload;
199 break;
200 default:
201 ERR("Failed to create action from payload, unhandled action type: action-type=%u (%s)",
202 action_comm->action_type,
203 lttng_action_type_string(
204 action_comm->action_type));
205 consumed_len = -1;
206 goto end;
207 }
208
209 {
210 /* Create buffer view for the action-type-specific data. */
211 struct lttng_payload_view specific_action_view =
212 lttng_payload_view_from_view(view,
213 sizeof(struct lttng_action_comm),
214 -1);
215
216 specific_action_consumed_len = create_from_payload_cb(
217 &specific_action_view, action);
218 }
219 if (specific_action_consumed_len < 0) {
220 ERR("Failed to create specific action from buffer.");
221 consumed_len = -1;
222 goto end;
223 }
224
225 assert(*action);
226
227 consumed_len = sizeof(struct lttng_action_comm) +
228 specific_action_consumed_len;
229
230 end:
231 return consumed_len;
232 }
233
234 LTTNG_HIDDEN
235 bool lttng_action_is_equal(const struct lttng_action *a,
236 const struct lttng_action *b)
237 {
238 bool is_equal = false;
239
240 if (!a || !b) {
241 goto end;
242 }
243
244 if (a->type != b->type) {
245 goto end;
246 }
247
248 if (a == b) {
249 is_equal = true;
250 goto end;
251 }
252
253 assert(a->equal);
254 is_equal = a->equal(a, b);
255 end:
256 return is_equal;
257 }
258
259 LTTNG_HIDDEN
260 void lttng_action_increase_execution_request_count(struct lttng_action *action)
261 {
262 action->execution_request_counter++;
263 }
264
265 LTTNG_HIDDEN
266 void lttng_action_increase_execution_count(struct lttng_action *action)
267 {
268 action->execution_counter++;
269 }
270
271 LTTNG_HIDDEN
272 void lttng_action_increase_execution_failure_count(struct lttng_action *action)
273 {
274 uatomic_inc(&action->execution_failure_counter);
275 }
276
277 LTTNG_HIDDEN
278 bool lttng_action_should_execute(const struct lttng_action *action)
279 {
280 const struct lttng_rate_policy *policy = NULL;
281 bool execute = false;
282
283 if (action->get_rate_policy == NULL) {
284 execute = true;
285 goto end;
286 }
287
288 policy = action->get_rate_policy(action);
289 if (policy == NULL) {
290 execute = true;
291 goto end;
292 }
293
294 execute = lttng_rate_policy_should_execute(
295 policy, action->execution_request_counter);
296 end:
297 return execute;
298 }
299
300 LTTNG_HIDDEN
301 enum lttng_action_status lttng_action_add_error_query_results(
302 const struct lttng_action *action,
303 struct lttng_error_query_results *results)
304 {
305 return action->add_error_query_results(action, results);
306 }
307
308 LTTNG_HIDDEN
309 enum lttng_action_status lttng_action_generic_add_error_query_results(
310 const struct lttng_action *action,
311 struct lttng_error_query_results *results)
312 {
313 enum lttng_action_status action_status;
314 struct lttng_error_query_result *error_counter = NULL;
315 const uint64_t execution_failure_counter =
316 uatomic_read(&action->execution_failure_counter);
317
318 error_counter = lttng_error_query_result_counter_create(
319 "total execution failures",
320 "Aggregated count of errors encountered when executing the action",
321 execution_failure_counter);
322 if (!error_counter) {
323 action_status = LTTNG_ACTION_STATUS_ERROR;
324 goto end;
325 }
326
327 if (lttng_error_query_results_add_result(
328 results, error_counter)) {
329 action_status = LTTNG_ACTION_STATUS_ERROR;
330 goto end;
331 }
332
333 /* Ownership transferred to the results. */
334 error_counter = NULL;
335 action_status = LTTNG_ACTION_STATUS_OK;
336 end:
337 lttng_error_query_result_destroy(error_counter);
338 return action_status;
339 }
340
341 LTTNG_HIDDEN
342 enum lttng_error_code lttng_action_mi_serialize(const struct lttng_trigger *trigger,
343 const struct lttng_action *action,
344 struct mi_writer *writer,
345 const struct mi_lttng_error_query_callbacks
346 *error_query_callbacks,
347 struct lttng_dynamic_array *action_path_indexes)
348 {
349 int ret;
350 enum lttng_error_code ret_code;
351 struct lttng_action_path *action_path = NULL;
352 struct lttng_error_query_results *error_query_results = NULL;
353
354 assert(action);
355 assert(writer);
356
357 /* Open action. */
358 ret = mi_lttng_writer_open_element(writer, mi_lttng_element_action);
359 if (ret) {
360 goto mi_error;
361 }
362
363 if (action->type == LTTNG_ACTION_TYPE_LIST) {
364 /*
365 * Recursion is safe since action lists can't be nested for
366 * the moment.
367 */
368 ret_code = lttng_action_list_mi_serialize(trigger, action, writer,
369 error_query_callbacks, action_path_indexes);
370 if (ret_code != LTTNG_OK) {
371 goto end;
372 }
373
374 /* Nothing else to do. */
375 goto close_action_element;
376 }
377
378 assert(action->mi_serialize);
379 ret_code = action->mi_serialize(action, writer);
380 if (ret_code != LTTNG_OK) {
381 goto end;
382 }
383
384 /* Error query for the action. */
385 if (error_query_callbacks && error_query_callbacks->action_cb) {
386 const uint64_t *action_path_indexes_raw_pointer = NULL;
387 const size_t action_path_indexes_size =
388 lttng_dynamic_array_get_count(
389 action_path_indexes);
390
391 if (action_path_indexes_size != 0) {
392 action_path_indexes_raw_pointer =
393 (const uint64_t *) action_path_indexes
394 ->buffer.data;
395 }
396
397 action_path = lttng_action_path_create(
398 action_path_indexes_raw_pointer,
399 action_path_indexes_size);
400 assert(action_path);
401
402 ret_code = error_query_callbacks->action_cb(
403 trigger, action_path, &error_query_results);
404 if (ret_code != LTTNG_OK) {
405 goto end;
406 }
407
408 /* Serialize the error query results. */
409 ret_code = lttng_error_query_results_mi_serialize(
410 error_query_results, writer);
411 if (ret_code != LTTNG_OK) {
412 goto end;
413 }
414 }
415
416 close_action_element:
417 /* Close action. */
418 ret = mi_lttng_writer_close_element(writer);
419 if (ret) {
420 goto mi_error;
421 }
422
423 ret_code = LTTNG_OK;
424 goto end;
425
426 mi_error:
427 ret_code = LTTNG_ERR_MI_IO_FAIL;
428 end:
429 lttng_action_path_destroy(action_path);
430 lttng_error_query_results_destroy(error_query_results);
431 return ret_code;
432 }
This page took 0.039559 seconds and 5 git commands to generate.