MI: implement all objects related to trigger machine interface
[lttng-tools.git] / src / common / actions / action.c
CommitLineData
a58c490f 1/*
ab5be9fa 2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
a58c490f 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
a58c490f 5 *
a58c490f
JG
6 */
7
14ec7e87
JR
8#include <assert.h>
9#include <common/error.h>
6a751b95 10#include <common/mi-lttng.h>
a58c490f 11#include <lttng/action/action-internal.h>
ad63a966 12#include <lttng/action/list-internal.h>
a58c490f 13#include <lttng/action/notify-internal.h>
7f4d5b07 14#include <lttng/action/rate-policy-internal.h>
bfb2ec6a 15#include <lttng/action/rotate-session-internal.h>
757c48a2 16#include <lttng/action/snapshot-session-internal.h>
58397d0d 17#include <lttng/action/start-session-internal.h>
931bdbaa 18#include <lttng/action/stop-session-internal.h>
588c4b0d 19#include <lttng/error-query-internal.h>
a58c490f 20
10615eee
JR
21LTTNG_HIDDEN
22const char *lttng_action_type_string(enum lttng_action_type action_type)
2666d352
SM
23{
24 switch (action_type) {
25 case LTTNG_ACTION_TYPE_UNKNOWN:
26 return "UNKNOWN";
7c2fae7c
JG
27 case LTTNG_ACTION_TYPE_LIST:
28 return "LIST";
2666d352
SM
29 case LTTNG_ACTION_TYPE_NOTIFY:
30 return "NOTIFY";
bfb2ec6a
SM
31 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
32 return "ROTATE_SESSION";
757c48a2
SM
33 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
34 return "SNAPSHOT_SESSION";
58397d0d
SM
35 case LTTNG_ACTION_TYPE_START_SESSION:
36 return "START_SESSION";
931bdbaa
SM
37 case LTTNG_ACTION_TYPE_STOP_SESSION:
38 return "STOP_SESSION";
2666d352
SM
39 default:
40 return "???";
41 }
42}
43
17182cfd 44enum lttng_action_type lttng_action_get_type(const struct lttng_action *action)
a58c490f
JG
45{
46 return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN;
47}
48
6acb3f46 49LTTNG_HIDDEN
2d57482c 50void lttng_action_init(struct lttng_action *action,
6acb3f46
SM
51 enum lttng_action_type type,
52 action_validate_cb validate,
53 action_serialize_cb serialize,
3dd04a6a 54 action_equal_cb equal,
2d57482c 55 action_destroy_cb destroy,
588c4b0d 56 action_get_rate_policy_cb get_rate_policy,
6a751b95
JR
57 action_add_error_query_results_cb add_error_query_results,
58 action_mi_serialize_cb mi)
6acb3f46 59{
c852ce4e 60 urcu_ref_init(&action->ref);
6acb3f46
SM
61 action->type = type;
62 action->validate = validate;
63 action->serialize = serialize;
3dd04a6a 64 action->equal = equal;
6acb3f46 65 action->destroy = destroy;
7f4d5b07 66 action->get_rate_policy = get_rate_policy;
588c4b0d 67 action->add_error_query_results = add_error_query_results;
6a751b95 68 action->mi_serialize = mi;
2d57482c
JR
69
70 action->execution_request_counter = 0;
71 action->execution_counter = 0;
72 action->execution_failure_counter = 0;
6acb3f46
SM
73}
74
c852ce4e
JG
75static
76void 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
84LTTNG_HIDDEN
85void lttng_action_get(struct lttng_action *action)
86{
87 urcu_ref_get(&action->ref);
88}
89
90LTTNG_HIDDEN
91void lttng_action_put(struct lttng_action *action)
a58c490f
JG
92{
93 if (!action) {
94 return;
95 }
96
97 assert(action->destroy);
c852ce4e
JG
98 urcu_ref_put(&action->ref, action_destroy_ref);
99}
100
101void lttng_action_destroy(struct lttng_action *action)
102{
103 lttng_action_put(action);
a58c490f
JG
104}
105
106LTTNG_HIDDEN
107bool 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);
123end:
124 return valid;
125}
126
127LTTNG_HIDDEN
3647288f 128int lttng_action_serialize(struct lttng_action *action,
c0a66c84 129 struct lttng_payload *payload)
a58c490f 130{
3647288f
JG
131 int ret;
132 struct lttng_action_comm action_comm = {
133 .action_type = (int8_t) action->type,
134 };
135
c0a66c84 136 ret = lttng_dynamic_buffer_append(&payload->buffer, &action_comm,
3647288f
JG
137 sizeof(action_comm));
138 if (ret) {
a58c490f
JG
139 goto end;
140 }
141
c0a66c84 142 ret = action->serialize(action, payload);
3647288f 143 if (ret) {
a58c490f
JG
144 goto end;
145 }
a58c490f
JG
146end:
147 return ret;
148}
149
150LTTNG_HIDDEN
c0a66c84 151ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view,
869a3c2d 152 struct lttng_action **action)
a58c490f 153{
869a3c2d 154 ssize_t consumed_len, specific_action_consumed_len;
c0a66c84 155 action_create_from_payload_cb create_from_payload_cb;
3e6e0df2
JG
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));
a58c490f 160
869a3c2d
SM
161 if (!view || !action) {
162 consumed_len = -1;
a58c490f
JG
163 goto end;
164 }
165
3e6e0df2
JG
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;
869a3c2d 173
c0a66c84 174 DBG("Create action from payload: action-type=%s",
2666d352
SM
175 lttng_action_type_string(action_comm->action_type));
176
a58c490f
JG
177 switch (action_comm->action_type) {
178 case LTTNG_ACTION_TYPE_NOTIFY:
c0a66c84 179 create_from_payload_cb = lttng_action_notify_create_from_payload;
a58c490f 180 break;
bfb2ec6a 181 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
c0a66c84
JG
182 create_from_payload_cb =
183 lttng_action_rotate_session_create_from_payload;
bfb2ec6a 184 break;
757c48a2
SM
185 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
186 create_from_payload_cb =
187 lttng_action_snapshot_session_create_from_payload;
188 break;
58397d0d 189 case LTTNG_ACTION_TYPE_START_SESSION:
c0a66c84
JG
190 create_from_payload_cb =
191 lttng_action_start_session_create_from_payload;
58397d0d 192 break;
931bdbaa 193 case LTTNG_ACTION_TYPE_STOP_SESSION:
c0a66c84
JG
194 create_from_payload_cb =
195 lttng_action_stop_session_create_from_payload;
931bdbaa 196 break;
7c2fae7c 197 case LTTNG_ACTION_TYPE_LIST:
702f26c8 198 create_from_payload_cb = lttng_action_list_create_from_payload;
0c51e8f3 199 break;
a58c490f 200 default:
c0a66c84 201 ERR("Failed to create action from payload, unhandled action type: action-type=%u (%s)",
2666d352
SM
202 action_comm->action_type,
203 lttng_action_type_string(
204 action_comm->action_type));
869a3c2d 205 consumed_len = -1;
a58c490f
JG
206 goto end;
207 }
208
c0a66c84
JG
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);
869a3c2d 215
c0a66c84
JG
216 specific_action_consumed_len = create_from_payload_cb(
217 &specific_action_view, action);
218 }
869a3c2d
SM
219 if (specific_action_consumed_len < 0) {
220 ERR("Failed to create specific action from buffer.");
221 consumed_len = -1;
a58c490f
JG
222 goto end;
223 }
869a3c2d
SM
224
225 assert(*action);
226
227 consumed_len = sizeof(struct lttng_action_comm) +
228 specific_action_consumed_len;
229
a58c490f 230end:
869a3c2d 231 return consumed_len;
a58c490f 232}
3dd04a6a
JR
233
234LTTNG_HIDDEN
235bool 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);
255end:
256 return is_equal;
257}
2d57482c
JR
258
259LTTNG_HIDDEN
260void lttng_action_increase_execution_request_count(struct lttng_action *action)
261{
262 action->execution_request_counter++;
263}
264
265LTTNG_HIDDEN
266void lttng_action_increase_execution_count(struct lttng_action *action)
267{
268 action->execution_counter++;
269}
270
271LTTNG_HIDDEN
272void lttng_action_increase_execution_failure_count(struct lttng_action *action)
273{
588c4b0d 274 uatomic_inc(&action->execution_failure_counter);
2d57482c
JR
275}
276
277LTTNG_HIDDEN
278bool lttng_action_should_execute(const struct lttng_action *action)
279{
7f4d5b07 280 const struct lttng_rate_policy *policy = NULL;
2d57482c
JR
281 bool execute = false;
282
7f4d5b07 283 if (action->get_rate_policy == NULL) {
2d57482c
JR
284 execute = true;
285 goto end;
286 }
287
7f4d5b07 288 policy = action->get_rate_policy(action);
2d57482c
JR
289 if (policy == NULL) {
290 execute = true;
291 goto end;
292 }
293
7f4d5b07 294 execute = lttng_rate_policy_should_execute(
2d57482c
JR
295 policy, action->execution_request_counter);
296end:
297 return execute;
298}
588c4b0d
JG
299
300LTTNG_HIDDEN
301enum 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
308LTTNG_HIDDEN
309enum 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;
336end:
337 lttng_error_query_result_destroy(error_counter);
338 return action_status;
339}
6a751b95
JR
340
341LTTNG_HIDDEN
342enum 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
416close_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
426mi_error:
427 ret_code = LTTNG_ERR_MI_IO_FAIL;
428end:
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.05374 seconds and 4 git commands to generate.