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