MI: implement all objects related to trigger machine interface
[lttng-tools.git] / src / common / actions / action.c
... / ...
CommitLineData
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
21LTTNG_HIDDEN
22const 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
44enum lttng_action_type lttng_action_get_type(const struct lttng_action *action)
45{
46 return action ? action->type : LTTNG_ACTION_TYPE_UNKNOWN;
47}
48
49LTTNG_HIDDEN
50void 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
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)
92{
93 if (!action) {
94 return;
95 }
96
97 assert(action->destroy);
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);
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
128int 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 }
146end:
147 return ret;
148}
149
150LTTNG_HIDDEN
151ssize_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
230end:
231 return consumed_len;
232}
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}
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{
274 uatomic_inc(&action->execution_failure_counter);
275}
276
277LTTNG_HIDDEN
278bool 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);
296end:
297 return execute;
298}
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}
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.024321 seconds and 5 git commands to generate.