Fix: futex wait: handle spurious futex wakeups
[lttng-tools.git] / src / common / actions / snapshot-session.cpp
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 <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/mi-lttng.hpp>
11 #include <common/payload-view.hpp>
12 #include <common/payload.hpp>
13 #include <common/snapshot.hpp>
14 #include <inttypes.h>
15 #include <lttng/action/action-internal.hpp>
16 #include <lttng/action/rate-policy-internal.hpp>
17 #include <lttng/action/rate-policy.h>
18 #include <lttng/action/snapshot-session-internal.hpp>
19 #include <lttng/action/snapshot-session.h>
20 #include <lttng/snapshot-internal.hpp>
21 #include <lttng/snapshot.h>
22
23 #define IS_SNAPSHOT_SESSION_ACTION(action) \
24 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
25
26 namespace {
27 struct lttng_action_snapshot_session {
28 struct lttng_action parent;
29
30 /* Owned by this. */
31 char *session_name;
32
33 /*
34 * When non-NULL, use this custom output when taking the snapshot,
35 * rather than the session's registered snapshot output.
36 *
37 * Owned by this.
38 */
39 struct lttng_snapshot_output *output;
40 struct lttng_rate_policy *policy;
41 };
42
43 struct lttng_action_snapshot_session_comm {
44 /* All string lengths include the trailing \0. */
45 uint32_t session_name_len;
46 uint32_t snapshot_output_len;
47 uint32_t rate_policy_len;
48
49 /*
50 * Variable data (all strings are null-terminated):
51 *
52 * - session name string
53 * - snapshot output object
54 * - policy object
55 */
56 char data[];
57 } LTTNG_PACKED;
58 } /* namespace */
59
60 static const struct lttng_rate_policy *
61 lttng_action_snapshot_session_internal_get_rate_policy(
62 const struct lttng_action *action);
63
64 static struct lttng_action_snapshot_session *
65 action_snapshot_session_from_action(struct lttng_action *action)
66 {
67 LTTNG_ASSERT(action);
68
69 return lttng::utils::container_of(
70 action, &lttng_action_snapshot_session::parent);
71 }
72
73 static const struct lttng_action_snapshot_session *
74 action_snapshot_session_from_action_const(const struct lttng_action *action)
75 {
76 LTTNG_ASSERT(action);
77
78 return lttng::utils::container_of(
79 action, &lttng_action_snapshot_session::parent);
80 }
81
82 static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
83 {
84 bool valid = false;
85 struct lttng_action_snapshot_session *action_snapshot_session;
86
87 if (!action) {
88 goto end;
89 }
90
91 action_snapshot_session = action_snapshot_session_from_action(action);
92
93 /* A non-empty session name is mandatory. */
94 if (!action_snapshot_session->session_name ||
95 strlen(action_snapshot_session->session_name) == 0) {
96 goto end;
97 }
98
99 if (action_snapshot_session->output &&
100 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
101 goto end;
102 }
103
104 valid = true;
105 end:
106 return valid;
107 }
108
109 static bool lttng_action_snapshot_session_is_equal(
110 const struct lttng_action *_a, const struct lttng_action *_b)
111 {
112 bool is_equal = false;
113 const struct lttng_action_snapshot_session *a, *b;
114
115 a = action_snapshot_session_from_action_const(_a);
116 b = action_snapshot_session_from_action_const(_b);
117
118 /* Action is not valid if this is not true. */
119 LTTNG_ASSERT(a->session_name);
120 LTTNG_ASSERT(b->session_name);
121 if (strcmp(a->session_name, b->session_name)) {
122 goto end;
123 }
124
125 if (a->output && b->output &&
126 !lttng_snapshot_output_is_equal(a->output, b->output)) {
127 goto end;
128 } else if (!!a->output != !!b->output) {
129 goto end;
130 }
131
132 is_equal = lttng_rate_policy_is_equal(a->policy, b->policy);
133 end:
134 return is_equal;
135 }
136
137 static size_t serialize_strlen(const char *str)
138 {
139 return str ? strlen(str) + 1 : 0;
140 }
141
142 static int lttng_action_snapshot_session_serialize(
143 struct lttng_action *action, struct lttng_payload *payload)
144 {
145 struct lttng_action_snapshot_session *action_snapshot_session;
146 struct lttng_action_snapshot_session_comm comm = {};
147 int ret;
148 size_t size_before_comm;
149
150 LTTNG_ASSERT(action);
151 LTTNG_ASSERT(payload);
152
153 size_before_comm = payload->buffer.size;
154
155 action_snapshot_session = action_snapshot_session_from_action(action);
156 comm.session_name_len =
157 serialize_strlen(action_snapshot_session->session_name);
158
159 /* Add header. */
160 ret = lttng_dynamic_buffer_append(
161 &payload->buffer, &comm, sizeof(comm));
162 if (ret) {
163 goto end;
164 }
165
166 LTTNG_ASSERT(action_snapshot_session->session_name);
167 DBG("Serializing snapshot session action: session-name: %s",
168 action_snapshot_session->session_name);
169
170 /* Add session name. */
171 ret = lttng_dynamic_buffer_append(&payload->buffer,
172 action_snapshot_session->session_name,
173 comm.session_name_len);
174 if (ret) {
175 goto end;
176 }
177
178 /* Serialize the snapshot output object, if any. */
179 if (action_snapshot_session->output) {
180 const size_t size_before_output = payload->buffer.size;
181 struct lttng_action_snapshot_session_comm *comm_in_payload;
182
183 ret = lttng_snapshot_output_serialize(
184 action_snapshot_session->output,
185 payload);
186 if (ret) {
187 goto end;
188 }
189
190 comm_in_payload = (typeof(comm_in_payload))(
191 payload->buffer.data + size_before_comm);
192 /* Adjust action length in header. */
193 comm_in_payload->snapshot_output_len =
194 payload->buffer.size - size_before_output;
195 }
196
197 /* Serialize the rate policy. */
198 {
199 const size_t size_before_output = payload->buffer.size;
200 struct lttng_action_snapshot_session_comm *comm_in_payload;
201
202 ret = lttng_rate_policy_serialize(
203 action_snapshot_session->policy, payload);
204 if (ret) {
205 ret = -1;
206 goto end;
207 }
208
209 comm_in_payload = (typeof(comm_in_payload))(
210 payload->buffer.data + size_before_comm);
211 /* Adjust rate policy length in header. */
212 comm_in_payload->rate_policy_len =
213 payload->buffer.size - size_before_output;
214 }
215
216 end:
217 return ret;
218 }
219
220 static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
221 {
222 struct lttng_action_snapshot_session *action_snapshot_session;
223
224 if (!action) {
225 goto end;
226 }
227
228 action_snapshot_session = action_snapshot_session_from_action(action);
229
230 free(action_snapshot_session->session_name);
231 lttng_snapshot_output_destroy(action_snapshot_session->output);
232 lttng_rate_policy_destroy(action_snapshot_session->policy);
233 free(action_snapshot_session);
234
235 end:
236 return;
237 }
238
239 ssize_t lttng_action_snapshot_session_create_from_payload(
240 struct lttng_payload_view *view,
241 struct lttng_action **p_action)
242 {
243 ssize_t consumed_len;
244 const char *variable_data;
245 struct lttng_action *action;
246 enum lttng_action_status status;
247 struct lttng_snapshot_output *snapshot_output = NULL;
248 struct lttng_rate_policy *policy = NULL;
249 const struct lttng_action_snapshot_session_comm *comm;
250 const struct lttng_payload_view snapshot_session_comm_view =
251 lttng_payload_view_from_view(
252 view, 0, sizeof(*comm));
253
254 action = lttng_action_snapshot_session_create();
255 if (!action) {
256 goto error;
257 }
258
259 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
260 /* Payload not large enough to contain the header. */
261 goto error;
262 }
263
264 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
265 variable_data = (const char *) &comm->data;
266
267 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
268
269 if (!lttng_buffer_view_contains_string(
270 &view->buffer, variable_data, comm->session_name_len)) {
271 goto error;
272 }
273
274 status = lttng_action_snapshot_session_set_session_name(
275 action, variable_data);
276 if (status != LTTNG_ACTION_STATUS_OK) {
277 goto error;
278 }
279
280 variable_data += comm->session_name_len;
281 consumed_len += comm->session_name_len;
282
283 /* If there is a snapshot output object, deserialize it. */
284 if (comm->snapshot_output_len > 0) {
285 ssize_t snapshot_output_consumed_len;
286 enum lttng_action_status action_status;
287 struct lttng_payload_view snapshot_output_buffer_view =
288 lttng_payload_view_from_view(view, consumed_len,
289 comm->snapshot_output_len);
290
291 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
292 ERR("Failed to create buffer view for snapshot output.");
293 goto error;
294 }
295
296 snapshot_output_consumed_len =
297 lttng_snapshot_output_create_from_payload(
298 &snapshot_output_buffer_view,
299 &snapshot_output);
300 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
301 ERR("Failed to deserialize snapshot output object: "
302 "consumed-len: %zd, expected-len: %" PRIu32,
303 snapshot_output_consumed_len,
304 comm->snapshot_output_len);
305 goto error;
306 }
307
308 action_status = lttng_action_snapshot_session_set_output(
309 action, snapshot_output);
310 if (action_status != LTTNG_ACTION_STATUS_OK) {
311 goto error;
312 }
313
314 /* Ownership has been transferred to the action. */
315 snapshot_output = NULL;
316 }
317
318 variable_data += comm->snapshot_output_len;
319 consumed_len += comm->snapshot_output_len;
320
321 /* Rate policy. */
322 if (comm->rate_policy_len <= 0) {
323 ERR("Rate policy should be present.");
324 goto error;
325 }
326 {
327 ssize_t rate_policy_consumed_len;
328 struct lttng_payload_view policy_view =
329 lttng_payload_view_from_view(view, consumed_len,
330 comm->rate_policy_len);
331
332 if (!lttng_payload_view_is_valid(&policy_view)) {
333 ERR("Failed to create buffer view for rate policy.");
334 goto error;
335 }
336
337 rate_policy_consumed_len =
338 lttng_rate_policy_create_from_payload(
339 &policy_view, &policy);
340 if (rate_policy_consumed_len < 0) {
341 goto error;
342 }
343
344 if (rate_policy_consumed_len != comm->rate_policy_len) {
345 ERR("Failed to deserialize rate policy object: "
346 "consumed-len: %zd, expected-len: %" PRIu32,
347 rate_policy_consumed_len,
348 comm->rate_policy_len);
349 goto error;
350 }
351
352 status = lttng_action_snapshot_session_set_rate_policy(
353 action, policy);
354 if (status != LTTNG_ACTION_STATUS_OK) {
355 goto error;
356 }
357 }
358
359 variable_data += comm->rate_policy_len;
360 consumed_len += comm->rate_policy_len;
361
362 *p_action = action;
363 action = NULL;
364
365 goto end;
366
367 error:
368 consumed_len = -1;
369
370 end:
371 lttng_rate_policy_destroy(policy);
372 lttng_action_snapshot_session_destroy(action);
373 lttng_snapshot_output_destroy(snapshot_output);
374
375 return consumed_len;
376 }
377
378 static enum lttng_error_code lttng_action_snapshot_session_mi_serialize(
379 const struct lttng_action *action, struct mi_writer *writer)
380 {
381 int ret;
382 enum lttng_error_code ret_code;
383 enum lttng_action_status status;
384 const char *session_name = NULL;
385 const struct lttng_snapshot_output *output = NULL;
386 const struct lttng_rate_policy *policy = NULL;
387
388 LTTNG_ASSERT(action);
389 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action));
390
391 status = lttng_action_snapshot_session_get_session_name(
392 action, &session_name);
393 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
394 LTTNG_ASSERT(session_name != NULL);
395
396 status = lttng_action_snapshot_session_get_rate_policy(action, &policy);
397 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
398 LTTNG_ASSERT(policy != NULL);
399
400 /* Open action snapshot session element. */
401 ret = mi_lttng_writer_open_element(
402 writer, mi_lttng_element_action_snapshot_session);
403 if (ret) {
404 goto mi_error;
405 }
406
407 /* Session name. */
408 ret = mi_lttng_writer_write_element_string(
409 writer, mi_lttng_element_session_name, session_name);
410 if (ret) {
411 goto mi_error;
412 }
413
414 /* Output if any. */
415 status = lttng_action_snapshot_session_get_output(action, &output);
416 if (status == LTTNG_ACTION_STATUS_OK) {
417 LTTNG_ASSERT(output != NULL);
418 ret_code = lttng_snapshot_output_mi_serialize(output, writer);
419 if (ret_code != LTTNG_OK) {
420 goto end;
421 }
422 } else if (status != LTTNG_ACTION_STATUS_UNSET) {
423 /* This should not happen at this point. */
424 abort();
425 }
426
427 /* Rate policy. */
428 ret_code = lttng_rate_policy_mi_serialize(policy, writer);
429 if (ret_code != LTTNG_OK) {
430 goto end;
431 }
432
433 /* Close action_snapshot_session element. */
434 ret = mi_lttng_writer_close_element(writer);
435 if (ret) {
436 goto mi_error;
437 }
438
439 ret_code = LTTNG_OK;
440 goto end;
441
442 mi_error:
443 ret_code = LTTNG_ERR_MI_IO_FAIL;
444 end:
445 return ret_code;
446 }
447
448 struct lttng_action *lttng_action_snapshot_session_create(void)
449 {
450 struct lttng_action_snapshot_session *action_snapshot = NULL;
451 struct lttng_rate_policy *policy = NULL;
452 enum lttng_action_status status;
453
454 /* Create a every N = 1 rate policy. */
455 policy = lttng_rate_policy_every_n_create(1);
456 if (!policy) {
457 goto end;
458 }
459
460 action_snapshot = zmalloc<lttng_action_snapshot_session>();
461 if (!action_snapshot) {
462 goto end;
463 }
464
465 lttng_action_init(&action_snapshot->parent,
466 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
467 lttng_action_snapshot_session_validate,
468 lttng_action_snapshot_session_serialize,
469 lttng_action_snapshot_session_is_equal,
470 lttng_action_snapshot_session_destroy,
471 lttng_action_snapshot_session_internal_get_rate_policy,
472 lttng_action_generic_add_error_query_results,
473 lttng_action_snapshot_session_mi_serialize);
474
475 status = lttng_action_snapshot_session_set_rate_policy(
476 &action_snapshot->parent, policy);
477 if (status != LTTNG_ACTION_STATUS_OK) {
478 lttng_action_destroy(&action_snapshot->parent);
479 action_snapshot = NULL;
480 goto end;
481 }
482
483 end:
484 lttng_rate_policy_destroy(policy);
485 return action_snapshot ? &action_snapshot->parent : nullptr;
486 }
487
488 enum lttng_action_status lttng_action_snapshot_session_set_session_name(
489 struct lttng_action *action, const char *session_name)
490 {
491 struct lttng_action_snapshot_session *action_snapshot_session;
492 enum lttng_action_status status;
493
494 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
495 strlen(session_name) == 0) {
496 status = LTTNG_ACTION_STATUS_INVALID;
497 goto end;
498 }
499
500 action_snapshot_session = action_snapshot_session_from_action(action);
501
502 free(action_snapshot_session->session_name);
503
504 action_snapshot_session->session_name = strdup(session_name);
505 if (!action_snapshot_session->session_name) {
506 status = LTTNG_ACTION_STATUS_ERROR;
507 goto end;
508 }
509
510 status = LTTNG_ACTION_STATUS_OK;
511 end:
512 return status;
513 }
514
515 enum lttng_action_status lttng_action_snapshot_session_get_session_name(
516 const struct lttng_action *action, const char **session_name)
517 {
518 const struct lttng_action_snapshot_session *action_snapshot_session;
519 enum lttng_action_status status;
520
521 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
522 status = LTTNG_ACTION_STATUS_INVALID;
523 goto end;
524 }
525
526 action_snapshot_session = action_snapshot_session_from_action_const(action);
527
528 if (action_snapshot_session->session_name) {
529 *session_name = action_snapshot_session->session_name;
530 status = LTTNG_ACTION_STATUS_OK;
531 } else {
532 status = LTTNG_ACTION_STATUS_UNSET;
533 }
534
535 end:
536
537 return status;
538 }
539
540 enum lttng_action_status lttng_action_snapshot_session_set_output(
541 struct lttng_action *action,
542 struct lttng_snapshot_output *output)
543 {
544 struct lttng_action_snapshot_session *action_snapshot_session;
545 enum lttng_action_status status;
546
547 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
548 status = LTTNG_ACTION_STATUS_INVALID;
549 goto end;
550 }
551
552 action_snapshot_session = action_snapshot_session_from_action(action);
553
554 lttng_snapshot_output_destroy(action_snapshot_session->output);
555 action_snapshot_session->output = output;
556
557 status = LTTNG_ACTION_STATUS_OK;
558
559 end:
560 return status;
561 }
562
563 enum lttng_action_status lttng_action_snapshot_session_get_output(
564 const struct lttng_action *action,
565 const struct lttng_snapshot_output **output)
566 {
567 const struct lttng_action_snapshot_session *action_snapshot_session;
568 enum lttng_action_status status;
569
570 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action)|| !output) {
571 status = LTTNG_ACTION_STATUS_INVALID;
572 goto end;
573 }
574
575 action_snapshot_session = action_snapshot_session_from_action_const(action);
576
577 if (action_snapshot_session->output) {
578 *output = action_snapshot_session->output;
579 status = LTTNG_ACTION_STATUS_OK;
580 } else {
581 status = LTTNG_ACTION_STATUS_UNSET;
582 }
583
584 end:
585 return status;
586 }
587
588 enum lttng_action_status lttng_action_snapshot_session_set_rate_policy(
589 struct lttng_action *action,
590 const struct lttng_rate_policy *policy)
591 {
592 enum lttng_action_status status;
593 struct lttng_action_snapshot_session *snapshot_session_action;
594 struct lttng_rate_policy *copy = NULL;
595
596 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
597 status = LTTNG_ACTION_STATUS_INVALID;
598 goto end;
599 }
600
601 copy = lttng_rate_policy_copy(policy);
602 if (!copy) {
603 status = LTTNG_ACTION_STATUS_ERROR;
604 goto end;
605 }
606
607 snapshot_session_action = action_snapshot_session_from_action(action);
608
609 /* Free the previous rate policy .*/
610 lttng_rate_policy_destroy(snapshot_session_action->policy);
611
612 /* Assign the policy. */
613 snapshot_session_action->policy = copy;
614 status = LTTNG_ACTION_STATUS_OK;
615 copy = NULL;
616
617 end:
618 lttng_rate_policy_destroy(copy);
619 return status;
620 }
621
622 enum lttng_action_status lttng_action_snapshot_session_get_rate_policy(
623 const struct lttng_action *action,
624 const struct lttng_rate_policy **policy)
625 {
626 enum lttng_action_status status;
627 const struct lttng_action_snapshot_session *snapshot_session_action;
628
629 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
630 status = LTTNG_ACTION_STATUS_INVALID;
631 goto end;
632 }
633
634 snapshot_session_action =
635 action_snapshot_session_from_action_const(action);
636
637 *policy = snapshot_session_action->policy;
638 status = LTTNG_ACTION_STATUS_OK;
639 end:
640 return status;
641 }
642
643 static const struct lttng_rate_policy *
644 lttng_action_snapshot_session_internal_get_rate_policy(
645 const struct lttng_action *action)
646 {
647 const struct lttng_action_snapshot_session *_action;
648 _action = action_snapshot_session_from_action_const(action);
649
650 return _action->policy;
651 }
This page took 0.043229 seconds and 4 git commands to generate.