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