Fix: futex wait: handle spurious futex wakeups
[lttng-tools.git] / src / common / conditions / session-consumed-size.cpp
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 <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/mi-lttng.hpp>
11 #include <float.h>
12 #include <lttng/condition/condition-internal.hpp>
13 #include <lttng/condition/session-consumed-size-internal.hpp>
14 #include <lttng/constant.h>
15 #include <math.h>
16 #include <time.h>
17
18 #define IS_CONSUMED_SIZE_CONDITION(condition) ( \
19 lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE \
20 )
21
22 #define IS_CONSUMED_SIZE_EVALUATION(evaluation) ( \
23 lttng_evaluation_get_type(evaluation) == LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE \
24 )
25
26 static
27 void lttng_condition_session_consumed_size_destroy(struct lttng_condition *condition)
28 {
29 struct lttng_condition_session_consumed_size *consumed_size;
30
31 consumed_size = lttng::utils::container_of(condition,
32 &lttng_condition_session_consumed_size::parent);
33
34 free(consumed_size->session_name);
35 free(consumed_size);
36 }
37
38 static
39 bool lttng_condition_session_consumed_size_validate(
40 const struct lttng_condition *condition)
41 {
42 bool valid = false;
43 struct lttng_condition_session_consumed_size *consumed;
44
45 if (!condition) {
46 goto end;
47 }
48
49 consumed = lttng::utils::container_of(condition,
50 &lttng_condition_session_consumed_size::parent);
51 if (!consumed->session_name) {
52 ERR("Invalid session consumed size condition: a target session name must be set.");
53 goto end;
54 }
55 if (!consumed->consumed_threshold_bytes.set) {
56 ERR("Invalid session consumed size condition: a threshold must be set.");
57 goto end;
58 }
59
60 valid = true;
61 end:
62 return valid;
63 }
64
65 static
66 int lttng_condition_session_consumed_size_serialize(
67 const struct lttng_condition *condition,
68 struct lttng_payload *payload)
69 {
70 int ret;
71 size_t session_name_len;
72 struct lttng_condition_session_consumed_size *consumed;
73 struct lttng_condition_session_consumed_size_comm consumed_comm;
74
75 if (!condition || !IS_CONSUMED_SIZE_CONDITION(condition)) {
76 ret = -1;
77 goto end;
78 }
79
80 DBG("Serializing session consumed size condition");
81 consumed = lttng::utils::container_of(condition,
82 &lttng_condition_session_consumed_size::parent);
83
84 session_name_len = strlen(consumed->session_name) + 1;
85 if (session_name_len > LTTNG_NAME_MAX) {
86 ret = -1;
87 goto end;
88 }
89
90 consumed_comm.consumed_threshold_bytes =
91 consumed->consumed_threshold_bytes.value;
92 consumed_comm.session_name_len = (uint32_t) session_name_len;
93
94 ret = lttng_dynamic_buffer_append(&payload->buffer, &consumed_comm,
95 sizeof(consumed_comm));
96 if (ret) {
97 goto end;
98 }
99
100 ret = lttng_dynamic_buffer_append(&payload->buffer, consumed->session_name,
101 session_name_len);
102 if (ret) {
103 goto end;
104 }
105 end:
106 return ret;
107 }
108
109 static
110 bool lttng_condition_session_consumed_size_is_equal(const struct lttng_condition *_a,
111 const struct lttng_condition *_b)
112 {
113 bool is_equal = false;
114 struct lttng_condition_session_consumed_size *a, *b;
115
116 a = lttng::utils::container_of(_a, &lttng_condition_session_consumed_size::parent);
117 b = lttng::utils::container_of(_b, &lttng_condition_session_consumed_size::parent);
118
119 if (a->consumed_threshold_bytes.set && b->consumed_threshold_bytes.set) {
120 uint64_t a_value, b_value;
121
122 a_value = a->consumed_threshold_bytes.value;
123 b_value = b->consumed_threshold_bytes.value;
124 if (a_value != b_value) {
125 goto end;
126 }
127 }
128
129 LTTNG_ASSERT(a->session_name);
130 LTTNG_ASSERT(b->session_name);
131 if (strcmp(a->session_name, b->session_name)) {
132 goto end;
133 }
134
135 is_equal = true;
136 end:
137 return is_equal;
138 }
139
140 static
141 enum lttng_error_code lttng_condition_session_consumed_size_mi_serialize(
142 const struct lttng_condition *condition,
143 struct mi_writer *writer)
144 {
145 int ret;
146 enum lttng_error_code ret_code;
147 enum lttng_condition_status status;
148 const char *session_name = NULL;
149 uint64_t threshold_bytes;
150
151 LTTNG_ASSERT(condition);
152 LTTNG_ASSERT(writer);
153 LTTNG_ASSERT(IS_CONSUMED_SIZE_CONDITION(condition));
154
155 status = lttng_condition_session_consumed_size_get_session_name(
156 condition, &session_name);
157 LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK);
158 LTTNG_ASSERT(session_name);
159
160 status = lttng_condition_session_consumed_size_get_threshold(
161 condition, &threshold_bytes);
162 LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK);
163
164 /* Open condition session consumed size element. */
165 ret = mi_lttng_writer_open_element(writer,
166 mi_lttng_element_condition_session_consumed_size);
167 if (ret) {
168 goto mi_error;
169 }
170
171 /* Session name. */
172 ret = mi_lttng_writer_write_element_string(
173 writer, mi_lttng_element_session_name, session_name);
174 if (ret) {
175 goto mi_error;
176 }
177
178 /* Threshold in bytes. */
179 ret = mi_lttng_writer_write_element_unsigned_int(writer,
180 mi_lttng_element_condition_threshold_bytes,
181 threshold_bytes);
182 if (ret) {
183 goto mi_error;
184 }
185
186 /* Close condition session consumed size element. */
187 ret = mi_lttng_writer_close_element(writer);
188 if (ret) {
189 goto mi_error;
190 }
191
192 ret_code = LTTNG_OK;
193 goto end;
194
195 mi_error:
196 ret_code = LTTNG_ERR_MI_IO_FAIL;
197 end:
198 return ret_code;
199 }
200
201 struct lttng_condition *lttng_condition_session_consumed_size_create(void)
202 {
203 struct lttng_condition_session_consumed_size *condition;
204
205 condition = zmalloc<lttng_condition_session_consumed_size>();
206 if (!condition) {
207 return NULL;
208 }
209
210 lttng_condition_init(&condition->parent, LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE);
211 condition->parent.validate = lttng_condition_session_consumed_size_validate;
212 condition->parent.serialize = lttng_condition_session_consumed_size_serialize;
213 condition->parent.equal = lttng_condition_session_consumed_size_is_equal;
214 condition->parent.destroy = lttng_condition_session_consumed_size_destroy;
215 condition->parent.mi_serialize = lttng_condition_session_consumed_size_mi_serialize;
216 return &condition->parent;
217 }
218
219 static
220 ssize_t init_condition_from_payload(struct lttng_condition *condition,
221 struct lttng_payload_view *src_view)
222 {
223 ssize_t ret, condition_size;
224 enum lttng_condition_status status;
225 const char *session_name;
226 struct lttng_buffer_view session_name_view;
227 const struct lttng_condition_session_consumed_size_comm *condition_comm;
228 struct lttng_payload_view condition_comm_view = lttng_payload_view_from_view(
229 src_view, 0, sizeof(*condition_comm));
230
231 if (!lttng_payload_view_is_valid(&condition_comm_view)) {
232 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
233 ret = -1;
234 goto end;
235 }
236
237 condition_comm = (typeof(condition_comm)) condition_comm_view.buffer.data;
238 session_name_view = lttng_buffer_view_from_view(&src_view->buffer,
239 sizeof(*condition_comm), condition_comm->session_name_len);
240
241 if (condition_comm->session_name_len > LTTNG_NAME_MAX) {
242 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
243 ret = -1;
244 goto end;
245 }
246
247 if (!lttng_buffer_view_is_valid(&session_name_view)) {
248 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
249 ret = -1;
250 goto end;
251 }
252
253 status = lttng_condition_session_consumed_size_set_threshold(condition,
254 condition_comm->consumed_threshold_bytes);
255 if (status != LTTNG_CONDITION_STATUS_OK) {
256 ERR("Failed to initialize session consumed size condition threshold");
257 ret = -1;
258 goto end;
259 }
260
261 session_name = session_name_view.data;
262 if (*(session_name + condition_comm->session_name_len - 1) != '\0') {
263 ERR("Malformed session name encountered in condition buffer");
264 ret = -1;
265 goto end;
266 }
267
268 status = lttng_condition_session_consumed_size_set_session_name(condition,
269 session_name);
270 if (status != LTTNG_CONDITION_STATUS_OK) {
271 ERR("Failed to set session consumed size condition's session name");
272 ret = -1;
273 goto end;
274 }
275
276 if (!lttng_condition_validate(condition)) {
277 ret = -1;
278 goto end;
279 }
280
281 condition_size = sizeof(*condition_comm) +
282 (ssize_t) condition_comm->session_name_len;
283 ret = condition_size;
284 end:
285 return ret;
286 }
287
288 ssize_t lttng_condition_session_consumed_size_create_from_payload(
289 struct lttng_payload_view *view,
290 struct lttng_condition **_condition)
291 {
292 ssize_t ret;
293 struct lttng_condition *condition =
294 lttng_condition_session_consumed_size_create();
295
296 if (!_condition || !condition) {
297 ret = -1;
298 goto error;
299 }
300
301 ret = init_condition_from_payload(condition, view);
302 if (ret < 0) {
303 goto error;
304 }
305
306 *_condition = condition;
307 return ret;
308 error:
309 lttng_condition_destroy(condition);
310 return ret;
311 }
312
313 static
314 struct lttng_evaluation *create_evaluation_from_payload(
315 const struct lttng_payload_view *view)
316 {
317 const struct lttng_evaluation_session_consumed_size_comm *comm =
318 (typeof(comm)) view->buffer.data;
319 struct lttng_evaluation *evaluation = NULL;
320
321 if (view->buffer.size < sizeof(*comm)) {
322 goto end;
323 }
324
325 evaluation = lttng_evaluation_session_consumed_size_create(
326 comm->session_consumed);
327 end:
328 return evaluation;
329 }
330
331 ssize_t lttng_evaluation_session_consumed_size_create_from_payload(
332 struct lttng_payload_view *view,
333 struct lttng_evaluation **_evaluation)
334 {
335 ssize_t ret;
336 struct lttng_evaluation *evaluation = NULL;
337
338 if (!_evaluation) {
339 ret = -1;
340 goto error;
341 }
342
343 evaluation = create_evaluation_from_payload(view);
344 if (!evaluation) {
345 ret = -1;
346 goto error;
347 }
348
349 *_evaluation = evaluation;
350 ret = sizeof(struct lttng_evaluation_session_consumed_size_comm);
351 return ret;
352 error:
353 lttng_evaluation_destroy(evaluation);
354 return ret;
355 }
356
357 enum lttng_condition_status
358 lttng_condition_session_consumed_size_get_threshold(
359 const struct lttng_condition *condition,
360 uint64_t *consumed_threshold_bytes)
361 {
362 struct lttng_condition_session_consumed_size *consumed;
363 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
364
365 if (!condition || !IS_CONSUMED_SIZE_CONDITION(condition) || !consumed_threshold_bytes) {
366 status = LTTNG_CONDITION_STATUS_INVALID;
367 goto end;
368 }
369
370 consumed = lttng::utils::container_of(condition,
371 &lttng_condition_session_consumed_size::parent);
372 if (!consumed->consumed_threshold_bytes.set) {
373 status = LTTNG_CONDITION_STATUS_UNSET;
374 goto end;
375 }
376 *consumed_threshold_bytes = consumed->consumed_threshold_bytes.value;
377 end:
378 return status;
379 }
380
381 enum lttng_condition_status
382 lttng_condition_session_consumed_size_set_threshold(
383 struct lttng_condition *condition, uint64_t consumed_threshold_bytes)
384 {
385 struct lttng_condition_session_consumed_size *consumed;
386 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
387
388 if (!condition || !IS_CONSUMED_SIZE_CONDITION(condition)) {
389 status = LTTNG_CONDITION_STATUS_INVALID;
390 goto end;
391 }
392
393 consumed = lttng::utils::container_of(condition,
394 &lttng_condition_session_consumed_size::parent);
395 consumed->consumed_threshold_bytes.set = true;
396 consumed->consumed_threshold_bytes.value = consumed_threshold_bytes;
397 end:
398 return status;
399 }
400
401 enum lttng_condition_status
402 lttng_condition_session_consumed_size_get_session_name(
403 const struct lttng_condition *condition,
404 const char **session_name)
405 {
406 struct lttng_condition_session_consumed_size *consumed;
407 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
408
409 if (!condition || !IS_CONSUMED_SIZE_CONDITION(condition) || !session_name) {
410 status = LTTNG_CONDITION_STATUS_INVALID;
411 goto end;
412 }
413
414 consumed = lttng::utils::container_of(condition,
415 &lttng_condition_session_consumed_size::parent);
416 if (!consumed->session_name) {
417 status = LTTNG_CONDITION_STATUS_UNSET;
418 goto end;
419 }
420 *session_name = consumed->session_name;
421 end:
422 return status;
423 }
424
425 enum lttng_condition_status
426 lttng_condition_session_consumed_size_set_session_name(
427 struct lttng_condition *condition, const char *session_name)
428 {
429 char *session_name_copy;
430 struct lttng_condition_session_consumed_size *consumed;
431 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
432
433 if (!condition || !IS_CONSUMED_SIZE_CONDITION(condition) ||
434 !session_name || strlen(session_name) == 0) {
435 status = LTTNG_CONDITION_STATUS_INVALID;
436 goto end;
437 }
438
439 consumed = lttng::utils::container_of(condition,
440 &lttng_condition_session_consumed_size::parent);
441 session_name_copy = strdup(session_name);
442 if (!session_name_copy) {
443 status = LTTNG_CONDITION_STATUS_ERROR;
444 goto end;
445 }
446
447 if (consumed->session_name) {
448 free(consumed->session_name);
449 }
450 consumed->session_name = session_name_copy;
451 end:
452 return status;
453 }
454
455 static
456 int lttng_evaluation_session_consumed_size_serialize(
457 const struct lttng_evaluation *evaluation,
458 struct lttng_payload *payload)
459 {
460 struct lttng_evaluation_session_consumed_size *consumed;
461 struct lttng_evaluation_session_consumed_size_comm comm;
462
463 consumed = lttng::utils::container_of(evaluation,
464 &lttng_evaluation_session_consumed_size::parent);
465 comm.session_consumed = consumed->session_consumed;
466 return lttng_dynamic_buffer_append(
467 &payload->buffer, &comm, sizeof(comm));
468 }
469
470 static
471 void lttng_evaluation_session_consumed_size_destroy(
472 struct lttng_evaluation *evaluation)
473 {
474 struct lttng_evaluation_session_consumed_size *consumed;
475
476 consumed = lttng::utils::container_of(evaluation,
477 &lttng_evaluation_session_consumed_size::parent);
478 free(consumed);
479 }
480
481 struct lttng_evaluation *lttng_evaluation_session_consumed_size_create(
482 uint64_t consumed)
483 {
484 struct lttng_evaluation_session_consumed_size *consumed_eval;
485
486 consumed_eval = zmalloc<lttng_evaluation_session_consumed_size>();
487 if (!consumed_eval) {
488 goto end;
489 }
490
491 consumed_eval->parent.type = LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE;
492 consumed_eval->session_consumed = consumed;
493 consumed_eval->parent.serialize = lttng_evaluation_session_consumed_size_serialize;
494 consumed_eval->parent.destroy = lttng_evaluation_session_consumed_size_destroy;
495 end:
496 return &consumed_eval->parent;
497 }
498
499 enum lttng_evaluation_status
500 lttng_evaluation_session_consumed_size_get_consumed_size(
501 const struct lttng_evaluation *evaluation,
502 uint64_t *session_consumed)
503 {
504 struct lttng_evaluation_session_consumed_size *consumed;
505 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
506
507 if (!evaluation || !IS_CONSUMED_SIZE_EVALUATION(evaluation) ||
508 !session_consumed) {
509 status = LTTNG_EVALUATION_STATUS_INVALID;
510 goto end;
511 }
512
513 consumed = lttng::utils::container_of(evaluation,
514 &lttng_evaluation_session_consumed_size::parent);
515 *session_consumed = consumed->session_consumed;
516 end:
517 return status;
518 }
This page took 0.039194 seconds and 4 git commands to generate.