Commit | Line | Data |
---|---|---|
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 | ||
6a751b95 JR |
8 | #include <common/error.h> |
9 | #include <common/macros.h> | |
10 | #include <common/mi-lttng.h> | |
a58c490f | 11 | #include <float.h> |
6a751b95 JR |
12 | #include <lttng/condition/buffer-usage-internal.h> |
13 | #include <lttng/condition/condition-internal.h> | |
14 | #include <math.h> | |
a58c490f JG |
15 | #include <time.h> |
16 | ||
17 | #define IS_USAGE_CONDITION(condition) ( \ | |
18 | lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW || \ | |
19 | lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH \ | |
20 | ) | |
21 | ||
a58c490f JG |
22 | static |
23 | bool is_usage_evaluation(const struct lttng_evaluation *evaluation) | |
24 | { | |
25 | enum lttng_condition_type type = lttng_evaluation_get_type(evaluation); | |
26 | ||
27 | return type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW || | |
28 | type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH; | |
29 | } | |
30 | ||
31 | static | |
32 | void lttng_condition_buffer_usage_destroy(struct lttng_condition *condition) | |
33 | { | |
34 | struct lttng_condition_buffer_usage *usage; | |
35 | ||
36 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
37 | parent); | |
38 | ||
39 | free(usage->session_name); | |
40 | free(usage->channel_name); | |
41 | free(usage); | |
42 | } | |
43 | ||
44 | static | |
45 | bool lttng_condition_buffer_usage_validate( | |
46 | const struct lttng_condition *condition) | |
47 | { | |
48 | bool valid = false; | |
49 | struct lttng_condition_buffer_usage *usage; | |
50 | ||
51 | if (!condition) { | |
52 | goto end; | |
53 | } | |
54 | ||
55 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
56 | parent); | |
57 | if (!usage->session_name) { | |
58 | ERR("Invalid buffer condition: a target session name must be set."); | |
59 | goto end; | |
60 | } | |
61 | if (!usage->channel_name) { | |
62 | ERR("Invalid buffer condition: a target channel name must be set."); | |
63 | goto end; | |
64 | } | |
70ee6d20 JR |
65 | if (usage->threshold_ratio.set == usage->threshold_bytes.set) { |
66 | ERR("Invalid buffer condition: a threshold must be set or both type cannot be used simultaneously."); | |
a58c490f JG |
67 | goto end; |
68 | } | |
821d5e92 JG |
69 | if (!usage->domain.set) { |
70 | ERR("Invalid buffer usage condition: a domain must be set."); | |
71 | goto end; | |
72 | } | |
a58c490f JG |
73 | |
74 | valid = true; | |
75 | end: | |
76 | return valid; | |
77 | } | |
78 | ||
79 | static | |
3647288f JG |
80 | int lttng_condition_buffer_usage_serialize( |
81 | const struct lttng_condition *condition, | |
c0a66c84 | 82 | struct lttng_payload *payload) |
a58c490f | 83 | { |
3647288f | 84 | int ret; |
a58c490f | 85 | struct lttng_condition_buffer_usage *usage; |
a58c490f | 86 | size_t session_name_len, channel_name_len; |
d33bfbbf | 87 | struct lttng_condition_buffer_usage_comm usage_comm = {}; |
a58c490f JG |
88 | |
89 | if (!condition || !IS_USAGE_CONDITION(condition)) { | |
90 | ret = -1; | |
91 | goto end; | |
92 | } | |
93 | ||
94 | DBG("Serializing buffer usage condition"); | |
95 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
96 | parent); | |
3647288f | 97 | |
a58c490f JG |
98 | session_name_len = strlen(usage->session_name) + 1; |
99 | channel_name_len = strlen(usage->channel_name) + 1; | |
100 | if (session_name_len > LTTNG_NAME_MAX || | |
101 | channel_name_len > LTTNG_NAME_MAX) { | |
102 | ret = -1; | |
103 | goto end; | |
104 | } | |
3647288f JG |
105 | |
106 | usage_comm.threshold_set_in_bytes = !!usage->threshold_bytes.set; | |
107 | usage_comm.session_name_len = session_name_len; | |
108 | usage_comm.channel_name_len = channel_name_len; | |
109 | usage_comm.domain_type = (int8_t) usage->domain.type; | |
110 | ||
111 | if (usage->threshold_bytes.set) { | |
f66473ac | 112 | usage_comm.threshold_bytes = usage->threshold_bytes.value; |
3647288f | 113 | } else { |
f66473ac | 114 | usage_comm.threshold_ratio = usage->threshold_ratio.value; |
3647288f | 115 | } |
a58c490f | 116 | |
c0a66c84 | 117 | ret = lttng_dynamic_buffer_append(&payload->buffer, &usage_comm, |
3647288f JG |
118 | sizeof(usage_comm)); |
119 | if (ret) { | |
120 | goto end; | |
121 | } | |
c0a66c84 JG |
122 | |
123 | ret = lttng_dynamic_buffer_append(&payload->buffer, usage->session_name, | |
3647288f JG |
124 | session_name_len); |
125 | if (ret) { | |
126 | goto end; | |
127 | } | |
c0a66c84 JG |
128 | |
129 | ret = lttng_dynamic_buffer_append(&payload->buffer, usage->channel_name, | |
3647288f JG |
130 | channel_name_len); |
131 | if (ret) { | |
132 | goto end; | |
a58c490f | 133 | } |
a58c490f JG |
134 | end: |
135 | return ret; | |
136 | } | |
137 | ||
138 | static | |
139 | bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition *_a, | |
140 | const struct lttng_condition *_b) | |
141 | { | |
142 | bool is_equal = false; | |
143 | struct lttng_condition_buffer_usage *a, *b; | |
144 | ||
145 | a = container_of(_a, struct lttng_condition_buffer_usage, parent); | |
146 | b = container_of(_b, struct lttng_condition_buffer_usage, parent); | |
147 | ||
148 | if ((a->threshold_ratio.set && !b->threshold_ratio.set) || | |
149 | (a->threshold_bytes.set && !b->threshold_bytes.set)) { | |
150 | goto end; | |
151 | } | |
152 | ||
153 | if (a->threshold_ratio.set && b->threshold_ratio.set) { | |
154 | double a_value, b_value, diff; | |
155 | ||
156 | a_value = a->threshold_ratio.value; | |
157 | b_value = b->threshold_ratio.value; | |
158 | diff = fabs(a_value - b_value); | |
159 | ||
160 | if (diff > DBL_EPSILON) { | |
161 | goto end; | |
162 | } | |
163 | } else if (a->threshold_bytes.set && b->threshold_bytes.set) { | |
164 | uint64_t a_value, b_value; | |
165 | ||
166 | a_value = a->threshold_bytes.value; | |
167 | b_value = b->threshold_bytes.value; | |
168 | if (a_value != b_value) { | |
169 | goto end; | |
170 | } | |
171 | } | |
172 | ||
821d5e92 | 173 | /* Condition is not valid if this is not true. */ |
a0377dfe FD |
174 | LTTNG_ASSERT(a->session_name); |
175 | LTTNG_ASSERT(b->session_name); | |
821d5e92 | 176 | if (strcmp(a->session_name, b->session_name)) { |
a58c490f JG |
177 | goto end; |
178 | } | |
179 | ||
a0377dfe FD |
180 | LTTNG_ASSERT(a->channel_name); |
181 | LTTNG_ASSERT(b->channel_name); | |
821d5e92 | 182 | if (strcmp(a->channel_name, b->channel_name)) { |
a58c490f JG |
183 | goto end; |
184 | } | |
185 | ||
a0377dfe FD |
186 | LTTNG_ASSERT(a->domain.set); |
187 | LTTNG_ASSERT(b->domain.set); | |
821d5e92 | 188 | if (a->domain.type != b->domain.type) { |
a58c490f JG |
189 | goto end; |
190 | } | |
a58c490f JG |
191 | is_equal = true; |
192 | end: | |
193 | return is_equal; | |
194 | } | |
195 | ||
6a751b95 JR |
196 | static enum lttng_error_code lttng_condition_buffer_usage_mi_serialize( |
197 | const struct lttng_condition *condition, | |
198 | struct mi_writer *writer) | |
199 | { | |
200 | int ret; | |
201 | enum lttng_error_code ret_code; | |
202 | enum lttng_condition_status status; | |
203 | const char *session_name = NULL, *channel_name = NULL; | |
204 | enum lttng_domain_type domain_type; | |
205 | bool is_threshold_bytes = false; | |
206 | double threshold_ratio; | |
207 | uint64_t threshold_bytes; | |
208 | const char *condition_type_str = NULL; | |
209 | ||
a0377dfe FD |
210 | LTTNG_ASSERT(condition); |
211 | LTTNG_ASSERT(IS_USAGE_CONDITION(condition)); | |
6a751b95 JR |
212 | |
213 | status = lttng_condition_buffer_usage_get_session_name( | |
214 | condition, &session_name); | |
a0377dfe FD |
215 | LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK); |
216 | LTTNG_ASSERT(session_name); | |
6a751b95 JR |
217 | |
218 | status = lttng_condition_buffer_usage_get_channel_name( | |
219 | condition, &channel_name); | |
a0377dfe FD |
220 | LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK); |
221 | LTTNG_ASSERT(session_name); | |
6a751b95 JR |
222 | |
223 | status = lttng_condition_buffer_usage_get_domain_type( | |
224 | condition, &domain_type); | |
a0377dfe | 225 | LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK); |
6a751b95 JR |
226 | |
227 | status = lttng_condition_buffer_usage_get_threshold( | |
228 | condition, &threshold_bytes); | |
229 | if (status == LTTNG_CONDITION_STATUS_OK) { | |
230 | is_threshold_bytes = true; | |
231 | } else if (status != LTTNG_CONDITION_STATUS_UNSET) { | |
232 | /* Unexpected at this stage. */ | |
233 | ret_code = LTTNG_ERR_INVALID; | |
234 | goto end; | |
235 | } | |
236 | ||
237 | if (!is_threshold_bytes) { | |
238 | status = lttng_condition_buffer_usage_get_threshold_ratio( | |
239 | condition, &threshold_ratio); | |
a0377dfe | 240 | LTTNG_ASSERT(status == LTTNG_CONDITION_STATUS_OK); |
6a751b95 JR |
241 | } |
242 | ||
243 | switch (lttng_condition_get_type(condition)) { | |
244 | case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH: | |
245 | condition_type_str = | |
246 | mi_lttng_element_condition_buffer_usage_high; | |
247 | break; | |
248 | case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW: | |
249 | condition_type_str = | |
250 | mi_lttng_element_condition_buffer_usage_low; | |
251 | break; | |
252 | default: | |
253 | abort(); | |
254 | break; | |
255 | } | |
256 | ||
257 | /* Open the sub type condition element. */ | |
258 | ret = mi_lttng_writer_open_element(writer, condition_type_str); | |
259 | if (ret) { | |
260 | goto mi_error; | |
261 | } | |
262 | ||
263 | /* Session name. */ | |
264 | ret = mi_lttng_writer_write_element_string( | |
265 | writer, mi_lttng_element_session_name, session_name); | |
266 | if (ret) { | |
267 | goto mi_error; | |
268 | } | |
269 | ||
270 | /* Channel name. */ | |
271 | ret = mi_lttng_writer_write_element_string(writer, | |
272 | mi_lttng_element_condition_channel_name, channel_name); | |
273 | if (ret) { | |
274 | goto mi_error; | |
275 | } | |
276 | ||
277 | /* Domain. */ | |
278 | ret = mi_lttng_writer_write_element_string(writer, | |
279 | config_element_domain, | |
280 | mi_lttng_domaintype_string(domain_type)); | |
281 | if (ret) { | |
282 | goto mi_error; | |
283 | } | |
284 | ||
285 | if (is_threshold_bytes) { | |
286 | /* Usage in bytes. */ | |
287 | ret = mi_lttng_writer_write_element_unsigned_int(writer, | |
288 | mi_lttng_element_condition_threshold_bytes, | |
289 | threshold_bytes); | |
290 | if (ret) { | |
291 | goto mi_error; | |
292 | } | |
293 | } else { | |
294 | /* Ratio. */ | |
295 | ret = mi_lttng_writer_write_element_double(writer, | |
296 | mi_lttng_element_condition_threshold_ratio, | |
297 | threshold_ratio); | |
298 | if (ret) { | |
299 | goto mi_error; | |
300 | } | |
301 | } | |
302 | ||
303 | /* Closing sub type condition element. */ | |
304 | ret = mi_lttng_writer_close_element(writer); | |
305 | if (ret) { | |
306 | goto mi_error; | |
307 | } | |
308 | ||
309 | ret_code = LTTNG_OK; | |
310 | goto end; | |
311 | ||
312 | mi_error: | |
313 | ret_code = LTTNG_ERR_MI_IO_FAIL; | |
314 | end: | |
315 | return ret_code; | |
316 | } | |
317 | ||
a58c490f JG |
318 | static |
319 | struct lttng_condition *lttng_condition_buffer_usage_create( | |
320 | enum lttng_condition_type type) | |
321 | { | |
322 | struct lttng_condition_buffer_usage *condition; | |
323 | ||
324 | condition = zmalloc(sizeof(struct lttng_condition_buffer_usage)); | |
325 | if (!condition) { | |
9a09eef5 | 326 | return NULL; |
a58c490f JG |
327 | } |
328 | ||
329 | lttng_condition_init(&condition->parent, type); | |
330 | condition->parent.validate = lttng_condition_buffer_usage_validate; | |
331 | condition->parent.serialize = lttng_condition_buffer_usage_serialize; | |
332 | condition->parent.equal = lttng_condition_buffer_usage_is_equal; | |
333 | condition->parent.destroy = lttng_condition_buffer_usage_destroy; | |
6a751b95 | 334 | condition->parent.mi_serialize = lttng_condition_buffer_usage_mi_serialize; |
a58c490f JG |
335 | return &condition->parent; |
336 | } | |
337 | ||
338 | struct lttng_condition *lttng_condition_buffer_usage_low_create(void) | |
339 | { | |
340 | return lttng_condition_buffer_usage_create( | |
341 | LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW); | |
342 | } | |
343 | ||
344 | struct lttng_condition *lttng_condition_buffer_usage_high_create(void) | |
345 | { | |
346 | return lttng_condition_buffer_usage_create( | |
347 | LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH); | |
348 | } | |
349 | ||
350 | static | |
c0a66c84 JG |
351 | ssize_t init_condition_from_payload(struct lttng_condition *condition, |
352 | struct lttng_payload_view *src_view) | |
a58c490f JG |
353 | { |
354 | ssize_t ret, condition_size; | |
355 | enum lttng_condition_status status; | |
356 | enum lttng_domain_type domain_type; | |
a58c490f JG |
357 | const char *session_name, *channel_name; |
358 | struct lttng_buffer_view names_view; | |
3e6e0df2 JG |
359 | const struct lttng_condition_buffer_usage_comm *condition_comm; |
360 | const struct lttng_payload_view condition_comm_view = | |
361 | lttng_payload_view_from_view( | |
362 | src_view, 0, sizeof(*condition_comm)); | |
a58c490f | 363 | |
3e6e0df2 | 364 | if (!lttng_payload_view_is_valid(&condition_comm_view)) { |
a58c490f JG |
365 | ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header"); |
366 | ret = -1; | |
367 | goto end; | |
368 | } | |
369 | ||
3e6e0df2 | 370 | condition_comm = (typeof(condition_comm)) condition_comm_view.buffer.data; |
c0a66c84 | 371 | names_view = lttng_buffer_view_from_view(&src_view->buffer, |
a58c490f JG |
372 | sizeof(*condition_comm), -1); |
373 | ||
374 | if (condition_comm->session_name_len > LTTNG_NAME_MAX || | |
375 | condition_comm->channel_name_len > LTTNG_NAME_MAX) { | |
376 | ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME"); | |
377 | ret = -1; | |
378 | goto end; | |
379 | } | |
380 | ||
381 | if (names_view.size < | |
382 | (condition_comm->session_name_len + | |
383 | condition_comm->channel_name_len)) { | |
384 | ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names"); | |
385 | ret = -1; | |
386 | goto end; | |
387 | } | |
388 | ||
389 | if (condition_comm->threshold_set_in_bytes) { | |
390 | status = lttng_condition_buffer_usage_set_threshold(condition, | |
f66473ac | 391 | condition_comm->threshold_bytes); |
a58c490f JG |
392 | } else { |
393 | status = lttng_condition_buffer_usage_set_threshold_ratio( | |
f66473ac | 394 | condition, condition_comm->threshold_ratio); |
a58c490f | 395 | } |
c0a66c84 | 396 | |
a58c490f JG |
397 | if (status != LTTNG_CONDITION_STATUS_OK) { |
398 | ERR("Failed to initialize buffer usage condition threshold"); | |
399 | ret = -1; | |
400 | goto end; | |
401 | } | |
402 | ||
403 | if (condition_comm->domain_type <= LTTNG_DOMAIN_NONE || | |
404 | condition_comm->domain_type > LTTNG_DOMAIN_PYTHON) { | |
405 | /* Invalid domain value. */ | |
406 | ERR("Invalid domain type value (%i) found in condition buffer", | |
407 | (int) condition_comm->domain_type); | |
408 | ret = -1; | |
409 | goto end; | |
410 | } | |
411 | ||
412 | domain_type = (enum lttng_domain_type) condition_comm->domain_type; | |
413 | status = lttng_condition_buffer_usage_set_domain_type(condition, | |
414 | domain_type); | |
415 | if (status != LTTNG_CONDITION_STATUS_OK) { | |
416 | ERR("Failed to set buffer usage condition domain"); | |
417 | ret = -1; | |
418 | goto end; | |
419 | } | |
420 | ||
421 | session_name = names_view.data; | |
422 | if (*(session_name + condition_comm->session_name_len - 1) != '\0') { | |
423 | ERR("Malformed session name encountered in condition buffer"); | |
424 | ret = -1; | |
425 | goto end; | |
426 | } | |
427 | ||
428 | channel_name = session_name + condition_comm->session_name_len; | |
429 | if (*(channel_name + condition_comm->channel_name_len - 1) != '\0') { | |
430 | ERR("Malformed channel name encountered in condition buffer"); | |
431 | ret = -1; | |
432 | goto end; | |
433 | } | |
434 | ||
435 | status = lttng_condition_buffer_usage_set_session_name(condition, | |
436 | session_name); | |
437 | if (status != LTTNG_CONDITION_STATUS_OK) { | |
438 | ERR("Failed to set buffer usage session name"); | |
439 | ret = -1; | |
440 | goto end; | |
441 | } | |
442 | ||
443 | status = lttng_condition_buffer_usage_set_channel_name(condition, | |
444 | channel_name); | |
445 | if (status != LTTNG_CONDITION_STATUS_OK) { | |
446 | ERR("Failed to set buffer usage channel name"); | |
447 | ret = -1; | |
448 | goto end; | |
449 | } | |
450 | ||
451 | if (!lttng_condition_validate(condition)) { | |
452 | ret = -1; | |
453 | goto end; | |
454 | } | |
455 | ||
456 | condition_size = sizeof(*condition_comm) + | |
457 | (ssize_t) condition_comm->session_name_len + | |
458 | (ssize_t) condition_comm->channel_name_len; | |
459 | ret = condition_size; | |
460 | end: | |
461 | return ret; | |
462 | } | |
463 | ||
c0a66c84 JG |
464 | ssize_t lttng_condition_buffer_usage_low_create_from_payload( |
465 | struct lttng_payload_view *view, | |
a58c490f JG |
466 | struct lttng_condition **_condition) |
467 | { | |
468 | ssize_t ret; | |
469 | struct lttng_condition *condition = | |
470 | lttng_condition_buffer_usage_low_create(); | |
471 | ||
472 | if (!_condition || !condition) { | |
473 | ret = -1; | |
474 | goto error; | |
475 | } | |
476 | ||
c0a66c84 | 477 | ret = init_condition_from_payload(condition, view); |
a58c490f JG |
478 | if (ret < 0) { |
479 | goto error; | |
480 | } | |
481 | ||
482 | *_condition = condition; | |
483 | return ret; | |
484 | error: | |
485 | lttng_condition_destroy(condition); | |
486 | return ret; | |
487 | } | |
488 | ||
c0a66c84 JG |
489 | ssize_t lttng_condition_buffer_usage_high_create_from_payload( |
490 | struct lttng_payload_view *view, | |
a58c490f JG |
491 | struct lttng_condition **_condition) |
492 | { | |
493 | ssize_t ret; | |
494 | struct lttng_condition *condition = | |
495 | lttng_condition_buffer_usage_high_create(); | |
496 | ||
497 | if (!_condition || !condition) { | |
498 | ret = -1; | |
499 | goto error; | |
500 | } | |
501 | ||
c0a66c84 | 502 | ret = init_condition_from_payload(condition, view); |
a58c490f JG |
503 | if (ret < 0) { |
504 | goto error; | |
505 | } | |
506 | ||
507 | *_condition = condition; | |
508 | return ret; | |
509 | error: | |
510 | lttng_condition_destroy(condition); | |
511 | return ret; | |
512 | } | |
513 | ||
514 | static | |
c0a66c84 | 515 | struct lttng_evaluation *create_evaluation_from_payload( |
a58c490f | 516 | enum lttng_condition_type type, |
c0a66c84 | 517 | struct lttng_payload_view *view) |
a58c490f JG |
518 | { |
519 | const struct lttng_evaluation_buffer_usage_comm *comm = | |
c0a66c84 | 520 | (typeof(comm)) view->buffer.data; |
a58c490f JG |
521 | struct lttng_evaluation *evaluation = NULL; |
522 | ||
c0a66c84 | 523 | if (view->buffer.size < sizeof(*comm)) { |
a58c490f JG |
524 | goto end; |
525 | } | |
526 | ||
527 | evaluation = lttng_evaluation_buffer_usage_create(type, | |
528 | comm->buffer_use, comm->buffer_capacity); | |
529 | end: | |
530 | return evaluation; | |
531 | } | |
532 | ||
c0a66c84 JG |
533 | ssize_t lttng_evaluation_buffer_usage_low_create_from_payload( |
534 | struct lttng_payload_view *view, | |
a58c490f JG |
535 | struct lttng_evaluation **_evaluation) |
536 | { | |
537 | ssize_t ret; | |
538 | struct lttng_evaluation *evaluation = NULL; | |
539 | ||
540 | if (!_evaluation) { | |
541 | ret = -1; | |
542 | goto error; | |
543 | } | |
544 | ||
c0a66c84 | 545 | evaluation = create_evaluation_from_payload( |
a58c490f JG |
546 | LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW, view); |
547 | if (!evaluation) { | |
548 | ret = -1; | |
549 | goto error; | |
550 | } | |
551 | ||
552 | *_evaluation = evaluation; | |
553 | ret = sizeof(struct lttng_evaluation_buffer_usage_comm); | |
554 | return ret; | |
555 | error: | |
556 | lttng_evaluation_destroy(evaluation); | |
557 | return ret; | |
558 | } | |
559 | ||
c0a66c84 JG |
560 | ssize_t lttng_evaluation_buffer_usage_high_create_from_payload( |
561 | struct lttng_payload_view *view, | |
a58c490f JG |
562 | struct lttng_evaluation **_evaluation) |
563 | { | |
564 | ssize_t ret; | |
565 | struct lttng_evaluation *evaluation = NULL; | |
566 | ||
567 | if (!_evaluation) { | |
568 | ret = -1; | |
569 | goto error; | |
570 | } | |
571 | ||
c0a66c84 | 572 | evaluation = create_evaluation_from_payload( |
a58c490f JG |
573 | LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH, view); |
574 | if (!evaluation) { | |
575 | ret = -1; | |
576 | goto error; | |
577 | } | |
578 | ||
579 | *_evaluation = evaluation; | |
580 | ret = sizeof(struct lttng_evaluation_buffer_usage_comm); | |
581 | return ret; | |
582 | error: | |
583 | lttng_evaluation_destroy(evaluation); | |
584 | return ret; | |
585 | } | |
586 | ||
587 | enum lttng_condition_status | |
588 | lttng_condition_buffer_usage_get_threshold_ratio( | |
589 | const struct lttng_condition *condition, | |
590 | double *threshold_ratio) | |
591 | { | |
592 | struct lttng_condition_buffer_usage *usage; | |
593 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
594 | ||
595 | if (!condition || !IS_USAGE_CONDITION(condition) || | |
596 | !threshold_ratio) { | |
597 | status = LTTNG_CONDITION_STATUS_INVALID; | |
598 | goto end; | |
599 | } | |
600 | ||
601 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
602 | parent); | |
603 | if (!usage->threshold_ratio.set) { | |
604 | status = LTTNG_CONDITION_STATUS_UNSET; | |
605 | goto end; | |
606 | } | |
607 | *threshold_ratio = usage->threshold_ratio.value; | |
608 | end: | |
609 | return status; | |
610 | } | |
611 | ||
612 | /* threshold_ratio expressed as [0.0, 1.0]. */ | |
613 | enum lttng_condition_status | |
614 | lttng_condition_buffer_usage_set_threshold_ratio( | |
615 | struct lttng_condition *condition, double threshold_ratio) | |
616 | { | |
617 | struct lttng_condition_buffer_usage *usage; | |
618 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
619 | ||
620 | if (!condition || !IS_USAGE_CONDITION(condition) || | |
621 | threshold_ratio < 0.0 || | |
622 | threshold_ratio > 1.0) { | |
623 | status = LTTNG_CONDITION_STATUS_INVALID; | |
624 | goto end; | |
625 | } | |
626 | ||
627 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
628 | parent); | |
629 | usage->threshold_ratio.set = true; | |
630 | usage->threshold_bytes.set = false; | |
631 | usage->threshold_ratio.value = threshold_ratio; | |
632 | end: | |
633 | return status; | |
634 | } | |
635 | ||
636 | enum lttng_condition_status | |
637 | lttng_condition_buffer_usage_get_threshold( | |
638 | const struct lttng_condition *condition, | |
639 | uint64_t *threshold_bytes) | |
640 | { | |
641 | struct lttng_condition_buffer_usage *usage; | |
642 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
643 | ||
644 | if (!condition || !IS_USAGE_CONDITION(condition) || !threshold_bytes) { | |
645 | status = LTTNG_CONDITION_STATUS_INVALID; | |
646 | goto end; | |
647 | } | |
648 | ||
649 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
650 | parent); | |
651 | if (!usage->threshold_bytes.set) { | |
652 | status = LTTNG_CONDITION_STATUS_UNSET; | |
653 | goto end; | |
654 | } | |
655 | *threshold_bytes = usage->threshold_bytes.value; | |
656 | end: | |
657 | return status; | |
658 | } | |
659 | ||
660 | enum lttng_condition_status | |
661 | lttng_condition_buffer_usage_set_threshold( | |
662 | struct lttng_condition *condition, uint64_t threshold_bytes) | |
663 | { | |
664 | struct lttng_condition_buffer_usage *usage; | |
665 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
666 | ||
667 | if (!condition || !IS_USAGE_CONDITION(condition)) { | |
668 | status = LTTNG_CONDITION_STATUS_INVALID; | |
669 | goto end; | |
670 | } | |
671 | ||
672 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
673 | parent); | |
674 | usage->threshold_ratio.set = false; | |
675 | usage->threshold_bytes.set = true; | |
676 | usage->threshold_bytes.value = threshold_bytes; | |
677 | end: | |
678 | return status; | |
679 | } | |
680 | ||
681 | enum lttng_condition_status | |
682 | lttng_condition_buffer_usage_get_session_name( | |
683 | const struct lttng_condition *condition, | |
684 | const char **session_name) | |
685 | { | |
686 | struct lttng_condition_buffer_usage *usage; | |
687 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
688 | ||
689 | if (!condition || !IS_USAGE_CONDITION(condition) || !session_name) { | |
690 | status = LTTNG_CONDITION_STATUS_INVALID; | |
691 | goto end; | |
692 | } | |
693 | ||
694 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
695 | parent); | |
696 | if (!usage->session_name) { | |
697 | status = LTTNG_CONDITION_STATUS_UNSET; | |
698 | goto end; | |
699 | } | |
700 | *session_name = usage->session_name; | |
701 | end: | |
702 | return status; | |
703 | } | |
704 | ||
705 | enum lttng_condition_status | |
706 | lttng_condition_buffer_usage_set_session_name( | |
707 | struct lttng_condition *condition, const char *session_name) | |
708 | { | |
709 | char *session_name_copy; | |
710 | struct lttng_condition_buffer_usage *usage; | |
711 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
712 | ||
713 | if (!condition || !IS_USAGE_CONDITION(condition) || !session_name || | |
714 | strlen(session_name) == 0) { | |
715 | status = LTTNG_CONDITION_STATUS_INVALID; | |
716 | goto end; | |
717 | } | |
718 | ||
719 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
720 | parent); | |
721 | session_name_copy = strdup(session_name); | |
722 | if (!session_name_copy) { | |
723 | status = LTTNG_CONDITION_STATUS_ERROR; | |
724 | goto end; | |
725 | } | |
726 | ||
727 | if (usage->session_name) { | |
728 | free(usage->session_name); | |
729 | } | |
730 | usage->session_name = session_name_copy; | |
731 | end: | |
732 | return status; | |
733 | } | |
734 | ||
735 | enum lttng_condition_status | |
736 | lttng_condition_buffer_usage_get_channel_name( | |
737 | const struct lttng_condition *condition, | |
738 | const char **channel_name) | |
739 | { | |
740 | struct lttng_condition_buffer_usage *usage; | |
741 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
742 | ||
743 | if (!condition || !IS_USAGE_CONDITION(condition) || !channel_name) { | |
744 | status = LTTNG_CONDITION_STATUS_INVALID; | |
745 | goto end; | |
746 | } | |
747 | ||
748 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
749 | parent); | |
750 | if (!usage->channel_name) { | |
751 | status = LTTNG_CONDITION_STATUS_UNSET; | |
752 | goto end; | |
753 | } | |
754 | *channel_name = usage->channel_name; | |
755 | end: | |
756 | return status; | |
757 | } | |
758 | ||
759 | enum lttng_condition_status | |
760 | lttng_condition_buffer_usage_set_channel_name( | |
761 | struct lttng_condition *condition, const char *channel_name) | |
762 | { | |
763 | char *channel_name_copy; | |
764 | struct lttng_condition_buffer_usage *usage; | |
765 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
766 | ||
767 | if (!condition || !IS_USAGE_CONDITION(condition) || !channel_name || | |
768 | strlen(channel_name) == 0) { | |
769 | status = LTTNG_CONDITION_STATUS_INVALID; | |
770 | goto end; | |
771 | } | |
772 | ||
773 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
774 | parent); | |
775 | channel_name_copy = strdup(channel_name); | |
776 | if (!channel_name_copy) { | |
777 | status = LTTNG_CONDITION_STATUS_ERROR; | |
778 | goto end; | |
779 | } | |
780 | ||
781 | if (usage->channel_name) { | |
782 | free(usage->channel_name); | |
783 | } | |
784 | usage->channel_name = channel_name_copy; | |
785 | end: | |
786 | return status; | |
787 | } | |
788 | ||
789 | enum lttng_condition_status | |
790 | lttng_condition_buffer_usage_get_domain_type( | |
791 | const struct lttng_condition *condition, | |
792 | enum lttng_domain_type *type) | |
793 | { | |
794 | struct lttng_condition_buffer_usage *usage; | |
795 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
796 | ||
797 | if (!condition || !IS_USAGE_CONDITION(condition) || !type) { | |
798 | status = LTTNG_CONDITION_STATUS_INVALID; | |
799 | goto end; | |
800 | } | |
801 | ||
802 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
803 | parent); | |
804 | if (!usage->domain.set) { | |
805 | status = LTTNG_CONDITION_STATUS_UNSET; | |
806 | goto end; | |
807 | } | |
808 | *type = usage->domain.type; | |
809 | end: | |
810 | return status; | |
811 | } | |
812 | ||
813 | enum lttng_condition_status | |
814 | lttng_condition_buffer_usage_set_domain_type( | |
815 | struct lttng_condition *condition, enum lttng_domain_type type) | |
816 | { | |
817 | struct lttng_condition_buffer_usage *usage; | |
818 | enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK; | |
819 | ||
820 | if (!condition || !IS_USAGE_CONDITION(condition) || | |
821 | type == LTTNG_DOMAIN_NONE) { | |
822 | status = LTTNG_CONDITION_STATUS_INVALID; | |
823 | goto end; | |
824 | } | |
825 | ||
826 | usage = container_of(condition, struct lttng_condition_buffer_usage, | |
827 | parent); | |
828 | usage->domain.set = true; | |
829 | usage->domain.type = type; | |
830 | end: | |
831 | return status; | |
832 | } | |
833 | ||
834 | static | |
3647288f | 835 | int lttng_evaluation_buffer_usage_serialize( |
9b63a4aa | 836 | const struct lttng_evaluation *evaluation, |
c0a66c84 | 837 | struct lttng_payload *payload) |
a58c490f | 838 | { |
a58c490f | 839 | struct lttng_evaluation_buffer_usage *usage; |
3647288f | 840 | struct lttng_evaluation_buffer_usage_comm comm; |
a58c490f JG |
841 | |
842 | usage = container_of(evaluation, struct lttng_evaluation_buffer_usage, | |
843 | parent); | |
3647288f JG |
844 | comm.buffer_use = usage->buffer_use; |
845 | comm.buffer_capacity = usage->buffer_capacity; | |
a58c490f | 846 | |
c0a66c84 JG |
847 | return lttng_dynamic_buffer_append( |
848 | &payload->buffer, &comm, sizeof(comm)); | |
a58c490f JG |
849 | } |
850 | ||
851 | static | |
852 | void lttng_evaluation_buffer_usage_destroy( | |
853 | struct lttng_evaluation *evaluation) | |
854 | { | |
855 | struct lttng_evaluation_buffer_usage *usage; | |
856 | ||
857 | usage = container_of(evaluation, struct lttng_evaluation_buffer_usage, | |
858 | parent); | |
859 | free(usage); | |
860 | } | |
861 | ||
a58c490f JG |
862 | struct lttng_evaluation *lttng_evaluation_buffer_usage_create( |
863 | enum lttng_condition_type type, uint64_t use, uint64_t capacity) | |
864 | { | |
865 | struct lttng_evaluation_buffer_usage *usage; | |
866 | ||
867 | usage = zmalloc(sizeof(struct lttng_evaluation_buffer_usage)); | |
868 | if (!usage) { | |
869 | goto end; | |
870 | } | |
871 | ||
872 | usage->parent.type = type; | |
873 | usage->buffer_use = use; | |
874 | usage->buffer_capacity = capacity; | |
875 | usage->parent.serialize = lttng_evaluation_buffer_usage_serialize; | |
876 | usage->parent.destroy = lttng_evaluation_buffer_usage_destroy; | |
877 | end: | |
878 | return &usage->parent; | |
879 | } | |
880 | ||
881 | /* | |
882 | * Get the sampled buffer usage which caused the associated condition to | |
883 | * evaluate to "true". | |
884 | */ | |
885 | enum lttng_evaluation_status | |
886 | lttng_evaluation_buffer_usage_get_usage_ratio( | |
887 | const struct lttng_evaluation *evaluation, double *usage_ratio) | |
888 | { | |
889 | struct lttng_evaluation_buffer_usage *usage; | |
890 | enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK; | |
891 | ||
892 | if (!evaluation || !is_usage_evaluation(evaluation) || !usage_ratio) { | |
893 | status = LTTNG_EVALUATION_STATUS_INVALID; | |
894 | goto end; | |
895 | } | |
896 | ||
897 | usage = container_of(evaluation, struct lttng_evaluation_buffer_usage, | |
898 | parent); | |
899 | *usage_ratio = (double) usage->buffer_use / | |
900 | (double) usage->buffer_capacity; | |
901 | end: | |
902 | return status; | |
903 | } | |
904 | ||
905 | enum lttng_evaluation_status | |
906 | lttng_evaluation_buffer_usage_get_usage( | |
907 | const struct lttng_evaluation *evaluation, | |
908 | uint64_t *usage_bytes) | |
909 | { | |
910 | struct lttng_evaluation_buffer_usage *usage; | |
911 | enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK; | |
912 | ||
913 | if (!evaluation || !is_usage_evaluation(evaluation) || !usage_bytes) { | |
914 | status = LTTNG_EVALUATION_STATUS_INVALID; | |
915 | goto end; | |
916 | } | |
917 | ||
918 | usage = container_of(evaluation, struct lttng_evaluation_buffer_usage, | |
919 | parent); | |
920 | *usage_bytes = usage->buffer_use; | |
921 | end: | |
922 | return status; | |
923 | } |