Commit | Line | Data |
---|---|---|
ebdb334b JR |
1 | /* |
2 | * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
8 | #include <assert.h> | |
9 | #include <string.h> | |
10 | ||
11 | #include <common/error.h> | |
12 | #include <common/macros.h> | |
13 | #include <common/optional.h> | |
14 | #include <common/payload.h> | |
15 | ||
16 | #include <lttng/lttng.h> | |
17 | #include <lttng/map/map-internal.h> | |
18 | ||
19 | enum lttng_map_status lttng_map_set_name(struct lttng_map *map, | |
20 | const char *name) | |
21 | { | |
22 | char *name_copy = NULL; | |
23 | enum lttng_map_status status; | |
24 | ||
25 | if (!map || !name || strlen(name) == 0) { | |
26 | status = LTTNG_MAP_STATUS_INVALID; | |
27 | goto end; | |
28 | } | |
29 | ||
30 | name_copy = strdup(name); | |
31 | if (!name_copy) { | |
32 | status = LTTNG_MAP_STATUS_ERROR; | |
33 | goto end; | |
34 | } | |
35 | ||
36 | free(map->name); | |
37 | ||
38 | map->name = name_copy; | |
39 | name_copy = NULL; | |
40 | ||
41 | status = LTTNG_MAP_STATUS_OK; | |
42 | end: | |
43 | return status; | |
44 | } | |
45 | ||
46 | enum lttng_map_status lttng_map_get_name(const struct lttng_map *map, | |
47 | const char **name) | |
48 | { | |
49 | enum lttng_map_status status; | |
50 | ||
51 | if (!map || !name) { | |
52 | status = LTTNG_MAP_STATUS_INVALID; | |
53 | goto end; | |
54 | } | |
55 | ||
56 | if (!map->name) { | |
57 | status = LTTNG_MAP_STATUS_UNSET; | |
58 | } | |
59 | ||
60 | *name = map->name; | |
61 | status = LTTNG_MAP_STATUS_OK; | |
62 | end: | |
63 | return status; | |
64 | } | |
65 | ||
66 | enum lttng_map_status lttng_map_create(const char *name, | |
67 | unsigned int dimension_count, | |
68 | uint64_t *dimension_sizes, | |
69 | enum lttng_domain_type domain, | |
70 | enum lttng_buffer_type buffer_type, | |
71 | enum lttng_map_bitness bitness, | |
72 | enum lttng_map_boundary_policy boundary_policy, | |
73 | bool coalesce_hits, | |
74 | struct lttng_map **map_out) | |
75 | { | |
76 | enum lttng_map_status status; | |
77 | struct lttng_map *map; | |
78 | ||
79 | if (dimension_count != 1) { | |
80 | status = LTTNG_MAP_STATUS_INVALID; | |
81 | goto end; | |
82 | } | |
83 | ||
84 | map = zmalloc(sizeof(struct lttng_map)); | |
85 | if (!map) { | |
86 | status = LTTNG_MAP_STATUS_ERROR; | |
87 | goto end; | |
88 | } | |
89 | ||
90 | if (name) { | |
91 | status = lttng_map_set_name(map, name); | |
92 | if (status != LTTNG_MAP_STATUS_OK) { | |
93 | goto free_map; | |
94 | } | |
95 | } else { | |
96 | map->name = NULL; | |
97 | } | |
98 | ||
99 | map->dimension_count = dimension_count; | |
100 | map->dimension_sizes = zmalloc( | |
101 | sizeof(*map->dimension_sizes) * dimension_count); | |
102 | if (!map->dimension_sizes) { | |
103 | status = LTTNG_MAP_STATUS_ERROR; | |
104 | goto free_name; | |
105 | } | |
106 | ||
107 | memcpy(map->dimension_sizes, dimension_sizes, | |
108 | sizeof(*map->dimension_sizes) * dimension_count); | |
109 | ||
110 | map->domain = domain; | |
111 | map->buffer_type = buffer_type; | |
112 | map->bitness = bitness; | |
113 | map->boundary_policy = boundary_policy; | |
114 | map->coalesce_hits = coalesce_hits; | |
115 | ||
116 | lttng_map_set_is_enabled(map, true); | |
117 | ||
118 | urcu_ref_init(&map->ref); | |
119 | ||
120 | *map_out = map; | |
121 | ||
122 | status = LTTNG_MAP_STATUS_OK; | |
123 | ||
124 | goto end; | |
125 | free_name: | |
126 | free(map->name); | |
127 | free_map: | |
128 | free(map); | |
129 | end: | |
130 | return status; | |
131 | } | |
132 | ||
133 | unsigned int lttng_map_get_dimension_count( | |
134 | const struct lttng_map *map) | |
135 | { | |
136 | assert(map); | |
137 | ||
138 | return map->dimension_count; | |
139 | } | |
140 | ||
141 | enum lttng_map_status lttng_map_get_dimension_length( | |
142 | const struct lttng_map *map, unsigned int dimension, | |
143 | uint64_t *dimension_length) | |
144 | { | |
145 | enum lttng_map_status status; | |
146 | ||
147 | assert(map); | |
148 | ||
149 | if (dimension >= map->dimension_count) { | |
150 | status = LTTNG_MAP_STATUS_INVALID; | |
151 | goto end; | |
152 | } | |
153 | ||
154 | *dimension_length = map->dimension_sizes[dimension]; | |
155 | ||
156 | status = LTTNG_MAP_STATUS_OK; | |
157 | end: | |
158 | return status; | |
159 | } | |
160 | ||
161 | enum lttng_map_bitness lttng_map_get_bitness( | |
162 | const struct lttng_map *map) | |
163 | { | |
164 | assert(map); | |
165 | ||
166 | return map->bitness; | |
167 | } | |
168 | ||
169 | enum lttng_domain_type lttng_map_get_domain( | |
170 | const struct lttng_map *map) | |
171 | { | |
172 | assert(map); | |
173 | ||
174 | return map->domain; | |
175 | } | |
176 | ||
177 | enum lttng_buffer_type lttng_map_get_buffer_type( | |
178 | const struct lttng_map *map) | |
179 | { | |
180 | assert(map); | |
181 | ||
182 | return map->buffer_type; | |
183 | } | |
184 | ||
185 | enum lttng_map_boundary_policy lttng_map_get_boundary_policy( | |
186 | const struct lttng_map *map) | |
187 | { | |
188 | assert(map); | |
189 | ||
190 | return map->boundary_policy; | |
191 | } | |
192 | ||
193 | bool lttng_map_get_coalesce_hits(const struct lttng_map *map) | |
194 | { | |
195 | assert(map); | |
196 | ||
197 | return map->coalesce_hits; | |
198 | } | |
199 | ||
200 | LTTNG_HIDDEN | |
201 | int lttng_map_serialize(const struct lttng_map *map, | |
202 | struct lttng_payload *payload) | |
203 | { | |
204 | int ret; | |
205 | size_t header_offset, size_before_payload, size_name; | |
206 | struct lttng_map_comm map_comm = {}; | |
207 | struct lttng_map_comm *header; | |
208 | ||
209 | if (map->name != NULL) { | |
210 | size_name = strlen(map->name) + 1; | |
211 | } else { | |
212 | size_name = 0; | |
213 | } | |
214 | ||
215 | map_comm.name_length = size_name; | |
216 | map_comm.is_enabled = LTTNG_OPTIONAL_GET(map->is_enabled); | |
217 | map_comm.bitness = map->bitness; | |
218 | map_comm.domain = map->domain; | |
219 | map_comm.buffer_type = map->buffer_type; | |
220 | map_comm.boundary_policy = map->boundary_policy; | |
221 | map_comm.dimension_count = map->dimension_count; | |
222 | map_comm.coalesce_hits = map->coalesce_hits; | |
223 | ||
224 | header_offset = payload->buffer.size; | |
225 | ||
226 | ret = lttng_dynamic_buffer_append(&payload->buffer, &map_comm, | |
227 | sizeof(map_comm)); | |
228 | if (ret) { | |
229 | goto end; | |
230 | } | |
231 | ||
232 | size_before_payload = payload->buffer.size; | |
233 | ||
234 | /* map name */ | |
235 | ret = lttng_dynamic_buffer_append( | |
236 | &payload->buffer, map->name, size_name); | |
237 | if (ret) { | |
238 | goto end; | |
239 | } | |
240 | ||
241 | ret = lttng_dynamic_buffer_append( | |
242 | &payload->buffer, map->dimension_sizes, | |
243 | sizeof(*map->dimension_sizes) * map->dimension_count); | |
244 | if (ret) { | |
245 | goto end; | |
246 | } | |
247 | ||
248 | /* Update payload size. */ | |
249 | header = (typeof(header)) (payload->buffer.data + header_offset); | |
250 | header->length = payload->buffer.size - size_before_payload; | |
251 | ||
252 | end: | |
253 | return ret; | |
254 | } | |
255 | ||
256 | LTTNG_HIDDEN | |
257 | ssize_t lttng_map_create_from_payload( | |
258 | struct lttng_payload_view *src_view, | |
259 | struct lttng_map **map) | |
260 | { | |
261 | ssize_t ret, offset = 0; | |
262 | const struct lttng_map_comm *map_comm; | |
263 | enum lttng_map_status status; | |
264 | unsigned int dimension_count; | |
265 | uint64_t *dimension_sizes = NULL; | |
266 | bool coalesce_hits; | |
267 | const char *name = NULL; | |
268 | enum lttng_domain_type domain; | |
269 | enum lttng_buffer_type buffer_type; | |
270 | enum lttng_map_bitness bitness; | |
271 | enum lttng_map_boundary_policy boundary_policy; | |
272 | ||
273 | if (!src_view || !map) { | |
274 | ret = -1; | |
275 | goto end; | |
276 | } | |
277 | ||
278 | map_comm = (typeof(map_comm)) src_view->buffer.data; | |
279 | offset += sizeof(*map_comm); | |
280 | ||
281 | domain = map_comm->domain; | |
282 | buffer_type = map_comm->buffer_type; | |
283 | bitness = map_comm->bitness; | |
284 | boundary_policy = map_comm->boundary_policy; | |
285 | dimension_count = map_comm->dimension_count; | |
286 | coalesce_hits = map_comm->coalesce_hits; | |
287 | ||
288 | if (map_comm->name_length != 0) { | |
289 | struct lttng_payload_view name_view = | |
290 | lttng_payload_view_from_view( | |
291 | src_view, offset, | |
292 | map_comm->name_length); | |
293 | ||
294 | name = name_view.buffer.data; | |
295 | if (!lttng_buffer_view_contains_string(&name_view.buffer, | |
296 | name, map_comm->name_length)){ | |
297 | ret = -1; | |
298 | goto end; | |
299 | } | |
300 | offset += map_comm->name_length; | |
301 | } | |
302 | ||
303 | size_t map_dim_sizes_len = sizeof(*(*map)->dimension_sizes) * dimension_count; | |
304 | ||
305 | struct lttng_payload_view dimension_sizes_view = | |
306 | lttng_payload_view_from_view(src_view, offset, | |
307 | map_dim_sizes_len); | |
308 | ||
309 | dimension_sizes = zmalloc(map_dim_sizes_len); | |
310 | if (!dimension_sizes) { | |
311 | ret = -1; | |
312 | goto end; | |
313 | } | |
314 | ||
315 | memcpy(dimension_sizes, dimension_sizes_view.buffer.data, | |
316 | map_dim_sizes_len); | |
317 | ||
318 | offset += map_dim_sizes_len; | |
319 | ||
320 | status = lttng_map_create(name, dimension_count, | |
321 | dimension_sizes, domain, buffer_type, bitness, | |
322 | boundary_policy, coalesce_hits, map); | |
323 | if (status != LTTNG_MAP_STATUS_OK) { | |
324 | ret = -1; | |
325 | goto end; | |
326 | } | |
327 | ||
328 | lttng_map_set_is_enabled(*map, map_comm->is_enabled); | |
329 | ||
330 | ret = offset; | |
331 | ||
332 | end: | |
333 | free(dimension_sizes); | |
334 | return ret; | |
335 | } | |
336 | ||
337 | LTTNG_HIDDEN | |
338 | void lttng_map_set_is_enabled(struct lttng_map *map, bool enabled) | |
339 | { | |
340 | assert(map); | |
341 | ||
342 | LTTNG_OPTIONAL_SET(&map->is_enabled, enabled); | |
343 | } | |
344 | ||
345 | int lttng_map_get_is_enabled(const struct lttng_map *map) | |
346 | { | |
347 | assert(map); | |
348 | return (int) LTTNG_OPTIONAL_GET(map->is_enabled); | |
349 | } | |
350 | ||
351 | LTTNG_HIDDEN | |
352 | void lttng_map_get(struct lttng_map *map) | |
353 | { | |
354 | urcu_ref_get(&map->ref); | |
355 | } | |
356 | ||
357 | static void map_destroy_ref(struct urcu_ref *ref) | |
358 | { | |
359 | struct lttng_map *map = container_of(ref, struct lttng_map, ref); | |
360 | ||
361 | free(map->dimension_sizes); | |
362 | free(map->name); | |
363 | free(map); | |
364 | ||
365 | } | |
366 | ||
367 | LTTNG_HIDDEN | |
368 | void lttng_map_put(struct lttng_map *map) | |
369 | { | |
370 | if (!map) { | |
371 | return; | |
372 | } | |
373 | ||
374 | urcu_ref_put(&map->ref , map_destroy_ref); | |
375 | } | |
376 | ||
377 | ||
378 | void lttng_map_destroy(struct lttng_map *map) | |
379 | { | |
380 | lttng_map_put(map); | |
381 | } | |
382 | ||
383 | static void delete_map_array_element(void *ptr) | |
384 | { | |
385 | struct lttng_map *map = ptr; | |
386 | ||
387 | lttng_map_put(map); | |
388 | } | |
389 | ||
390 | LTTNG_HIDDEN | |
391 | struct lttng_map_list *lttng_map_list_create(void) | |
392 | { | |
393 | struct lttng_map_list *map_list = NULL; | |
394 | ||
395 | map_list = zmalloc(sizeof(*map_list)); | |
396 | if (!map_list) { | |
397 | goto end; | |
398 | } | |
399 | ||
400 | lttng_dynamic_pointer_array_init(&map_list->array, | |
401 | delete_map_array_element); | |
402 | ||
403 | end: | |
404 | return map_list; | |
405 | } | |
406 | ||
407 | LTTNG_HIDDEN | |
408 | enum lttng_map_status lttng_map_list_add(struct lttng_map_list *map_list, | |
409 | struct lttng_map *map) | |
410 | { | |
411 | enum lttng_map_status status; | |
412 | int ret; | |
413 | ||
414 | assert(map_list); | |
415 | assert(map); | |
416 | ||
417 | lttng_map_get(map); | |
418 | ||
419 | ret = lttng_dynamic_pointer_array_add_pointer(&map_list->array, map); | |
420 | if (ret) { | |
421 | lttng_map_put(map); | |
422 | status = LTTNG_MAP_STATUS_ERROR; | |
423 | goto end; | |
424 | } | |
425 | status = LTTNG_MAP_STATUS_OK; | |
426 | end: | |
427 | return status; | |
428 | ||
429 | } | |
430 | ||
431 | LTTNG_HIDDEN | |
432 | ssize_t lttng_map_list_create_from_payload(struct lttng_payload_view *src_view, | |
433 | struct lttng_map_list **map_list) | |
434 | { | |
435 | unsigned int i; | |
436 | ssize_t ret, offset = 0; | |
437 | const struct lttng_map_list_comm *map_list_comm; | |
438 | struct lttng_map_list *local_map_list = NULL; | |
439 | ||
440 | map_list_comm = (typeof(map_list_comm)) src_view->buffer.data; | |
441 | offset += sizeof(*map_list_comm); | |
442 | ||
443 | local_map_list = lttng_map_list_create(); | |
444 | if (!local_map_list) { | |
445 | ret = -1; | |
446 | goto end; | |
447 | } | |
448 | ||
449 | for (i = 0; i < map_list_comm->count; i++) { | |
450 | struct lttng_map *map = NULL; | |
451 | struct lttng_payload_view map_view = | |
452 | lttng_payload_view_from_view(src_view, offset, -1); | |
453 | ssize_t map_size; | |
454 | ||
455 | map_size = lttng_map_create_from_payload(&map_view, &map); | |
456 | if (map_size < 0) { | |
457 | ret = map_size; | |
458 | goto end; | |
459 | } | |
460 | ||
461 | /* Transfer ownership of the map to the collection. */ | |
462 | ret = lttng_map_list_add(local_map_list, map); | |
463 | lttng_map_put(map); | |
464 | if (ret < 0) { | |
465 | ret = -1; | |
466 | goto end; | |
467 | } | |
468 | ||
469 | offset += map_size; | |
470 | } | |
471 | ||
472 | /* Pass ownership to caller. */ | |
473 | *map_list = local_map_list; | |
474 | local_map_list = NULL; | |
475 | ||
476 | ret = offset; | |
477 | end: | |
478 | lttng_map_list_destroy(local_map_list); | |
479 | return ret; | |
480 | } | |
481 | ||
482 | LTTNG_HIDDEN | |
483 | int lttng_map_list_serialize(const struct lttng_map_list *map_list, | |
484 | struct lttng_payload *payload) | |
485 | { | |
486 | int ret; | |
487 | unsigned int i, count; | |
488 | enum lttng_map_status status; | |
489 | struct lttng_map_list_comm map_list_comm = {}; | |
490 | ||
491 | status = lttng_map_list_get_count(map_list, &count); | |
492 | if (status != LTTNG_MAP_STATUS_OK) { | |
493 | ret = LTTNG_ERR_INVALID; | |
494 | goto end; | |
495 | } | |
496 | ||
497 | map_list_comm.count = count; | |
498 | ret = lttng_dynamic_buffer_append(&payload->buffer, &map_list_comm, | |
499 | sizeof(map_list_comm)); | |
500 | if (ret) { | |
501 | goto end; | |
502 | } | |
503 | for (i = 0; i < count; i++) { | |
504 | const struct lttng_map *map = | |
505 | lttng_map_list_get_at_index(map_list, i); | |
506 | ||
507 | assert(map); | |
508 | ||
509 | ret = lttng_map_serialize(map, payload); | |
510 | if (ret) { | |
511 | goto end; | |
512 | } | |
513 | } | |
514 | ||
515 | end: | |
516 | return ret; | |
517 | } | |
518 | ||
519 | const struct lttng_map *lttng_map_list_get_at_index( | |
520 | const struct lttng_map_list *map_list, unsigned int index) | |
521 | { | |
522 | struct lttng_map *map = NULL; | |
523 | ||
524 | assert(map_list); | |
525 | if (index >= lttng_dynamic_pointer_array_get_count(&map_list->array)) { | |
526 | goto end; | |
527 | } | |
528 | ||
529 | map = (struct lttng_map *) | |
530 | lttng_dynamic_pointer_array_get_pointer( | |
531 | &map_list->array, index); | |
532 | end: | |
533 | return map; | |
534 | } | |
535 | ||
536 | enum lttng_map_status lttng_map_list_get_count( | |
537 | const struct lttng_map_list *map_list, unsigned int *count) | |
538 | { | |
539 | enum lttng_map_status status = LTTNG_MAP_STATUS_OK; | |
540 | ||
541 | if (!map_list || !count) { | |
542 | status = LTTNG_MAP_STATUS_INVALID; | |
543 | goto end; | |
544 | } | |
545 | ||
546 | *count = lttng_dynamic_pointer_array_get_count(&map_list->array); | |
547 | status = LTTNG_MAP_STATUS_OK; | |
548 | end: | |
549 | return status; | |
550 | } | |
551 | ||
552 | void lttng_map_list_destroy(struct lttng_map_list *map_list) | |
553 | { | |
554 | if (!map_list) { | |
555 | return; | |
556 | } | |
557 | ||
558 | lttng_dynamic_pointer_array_reset(&map_list->array); | |
559 | free(map_list); | |
560 | } | |
561 | ||
562 | struct lttng_map_key_value_pair *lttng_map_key_value_pair_create(const char *key, | |
563 | int64_t value) | |
564 | { | |
565 | struct lttng_map_key_value_pair *key_value; | |
566 | ||
567 | key_value = zmalloc(sizeof(struct lttng_map_key_value_pair)); | |
568 | if (!key_value) { | |
569 | goto end; | |
570 | } | |
571 | ||
572 | key_value->key = strdup(key); | |
573 | if (!key_value->key) { | |
574 | free(key_value); | |
575 | key_value = NULL; | |
576 | goto end; | |
577 | } | |
578 | key_value->value = value; | |
579 | ||
580 | end: | |
581 | return key_value; | |
582 | } | |
583 | ||
584 | enum lttng_map_status lttng_map_key_value_pair_get_key( | |
585 | const struct lttng_map_key_value_pair *key_value, | |
586 | const char **key) | |
587 | { | |
588 | assert(key_value); | |
589 | assert(key_value->key); | |
590 | ||
591 | *key = key_value->key; | |
592 | return LTTNG_MAP_STATUS_OK; | |
593 | } | |
594 | ||
595 | enum lttng_map_status lttng_map_key_value_pair_get_value( | |
596 | const struct lttng_map_key_value_pair *key_value, | |
597 | int64_t *value) | |
598 | { | |
599 | assert(key_value); | |
600 | *value = key_value->value; | |
601 | return LTTNG_MAP_STATUS_OK; | |
602 | } | |
603 | ||
604 | LTTNG_HIDDEN | |
605 | void lttng_map_key_value_pair_set_has_overflowed( | |
606 | struct lttng_map_key_value_pair *key_value) | |
607 | { | |
608 | assert(key_value); | |
609 | ||
610 | key_value->has_overflowed = true; | |
611 | } | |
612 | ||
613 | LTTNG_HIDDEN | |
614 | void lttng_map_key_value_pair_set_has_underflowed( | |
615 | struct lttng_map_key_value_pair *key_value) | |
616 | { | |
617 | assert(key_value); | |
618 | ||
619 | key_value->has_underflowed = true; | |
620 | } | |
621 | ||
622 | bool lttng_map_key_value_pair_get_has_overflowed( | |
623 | const struct lttng_map_key_value_pair *key_value) | |
624 | { | |
625 | assert(key_value); | |
626 | ||
627 | return key_value->has_overflowed; | |
628 | } | |
629 | ||
630 | bool lttng_map_key_value_pair_get_has_underflowed( | |
631 | const struct lttng_map_key_value_pair *key_value) | |
632 | { | |
633 | assert(key_value); | |
634 | ||
635 | return key_value->has_underflowed; | |
636 | } | |
637 | ||
638 | LTTNG_HIDDEN | |
639 | ssize_t lttng_map_key_value_pair_create_from_payload( | |
640 | struct lttng_payload_view *src_view, | |
641 | struct lttng_map_key_value_pair **key_value) | |
642 | { | |
643 | const struct lttng_map_key_value_pair_comm *kv_pair_comm; | |
644 | struct lttng_map_key_value_pair *kv_pair; | |
645 | ssize_t ret, offset = 0; | |
646 | const char *key; | |
647 | int64_t value; | |
648 | ||
649 | if (!src_view || !key_value) { | |
650 | ret = -1; | |
651 | goto end; | |
652 | } | |
653 | ||
654 | kv_pair_comm = (typeof(kv_pair_comm)) src_view->buffer.data; | |
655 | offset += sizeof(*kv_pair_comm); | |
656 | ||
657 | if (kv_pair_comm->key_length == 0) { | |
658 | ret = -1; | |
659 | goto end; | |
660 | } | |
661 | ||
662 | value = kv_pair_comm->value; | |
663 | ||
664 | struct lttng_payload_view key_view = | |
665 | lttng_payload_view_from_view(src_view, offset, | |
666 | kv_pair_comm->key_length); | |
667 | key = key_view.buffer.data; | |
668 | if (!lttng_buffer_view_contains_string(&key_view.buffer, | |
669 | key, kv_pair_comm->key_length)) { | |
670 | ret = -1; | |
671 | goto end; | |
672 | } | |
673 | ||
674 | offset += kv_pair_comm->key_length; | |
675 | ||
676 | kv_pair = lttng_map_key_value_pair_create(key, value); | |
677 | if (!kv_pair) { | |
678 | ret = -1; | |
679 | goto end; | |
680 | } | |
681 | ||
682 | kv_pair->has_overflowed = kv_pair_comm->has_overflowed; | |
683 | kv_pair->has_underflowed = kv_pair_comm->has_underflowed; | |
684 | ||
685 | *key_value = kv_pair; | |
686 | ||
687 | ret = offset; | |
688 | ||
689 | end: | |
690 | return ret; | |
691 | } | |
692 | ||
693 | LTTNG_HIDDEN | |
694 | int lttng_map_key_value_pair_serialize( | |
695 | const struct lttng_map_key_value_pair *key_value, | |
696 | struct lttng_payload *payload) | |
697 | { | |
698 | int ret; | |
699 | size_t key_len; | |
700 | struct lttng_map_key_value_pair_comm kv_pair_comm = {0}; | |
701 | ||
702 | assert(key_value); | |
703 | assert(key_value->key); | |
704 | ||
705 | key_len = strlen(key_value->key) + 1; | |
706 | ||
707 | kv_pair_comm.key_length = key_len; | |
708 | kv_pair_comm.value = key_value->value; | |
709 | kv_pair_comm.has_overflowed = key_value->has_overflowed; | |
710 | kv_pair_comm.has_underflowed = key_value->has_underflowed; | |
711 | ||
712 | ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_comm, | |
713 | sizeof(kv_pair_comm)); | |
714 | if (ret) { | |
715 | goto end; | |
716 | } | |
717 | ||
718 | /* Append key.*/ | |
719 | ret = lttng_dynamic_buffer_append( | |
720 | &payload->buffer, key_value->key, key_len); | |
721 | if (ret) { | |
722 | goto end; | |
723 | } | |
724 | ||
725 | end: | |
726 | return ret; | |
727 | } | |
728 | ||
729 | void lttng_map_key_value_pair_destroy(struct lttng_map_key_value_pair *key_value) | |
730 | { | |
731 | if (!key_value) { | |
732 | return; | |
733 | } | |
734 | ||
735 | free(key_value->key); | |
736 | free(key_value); | |
737 | } | |
738 | ||
739 | static void delete_map_key_value_pair_array_element(void *ptr) | |
740 | { | |
741 | struct lttng_map_key_value_pair *key_value = ptr; | |
742 | lttng_map_key_value_pair_destroy(key_value); | |
743 | } | |
744 | ||
745 | LTTNG_HIDDEN | |
746 | struct lttng_map_key_value_pair_list *lttng_map_key_value_pair_list_create( | |
747 | enum lttng_map_key_value_pair_list_type type, | |
748 | bool summed_all_cpus) | |
749 | { | |
750 | struct lttng_map_key_value_pair_list *map_key_values = NULL; | |
751 | ||
752 | map_key_values = zmalloc(sizeof(*map_key_values)); | |
753 | if (!map_key_values) { | |
754 | goto end; | |
755 | } | |
756 | ||
757 | map_key_values->type = type; | |
758 | map_key_values->summed_all_cpus = summed_all_cpus; | |
759 | ||
760 | lttng_dynamic_pointer_array_init(&map_key_values->array, | |
761 | delete_map_key_value_pair_array_element); | |
762 | ||
763 | end: | |
764 | return map_key_values; | |
765 | } | |
766 | ||
767 | LTTNG_HIDDEN | |
768 | enum lttng_map_status lttng_map_key_value_pair_list_set_identifier( | |
769 | struct lttng_map_key_value_pair_list *kv_pair_list, | |
770 | uint64_t identifier) | |
771 | { | |
772 | enum lttng_map_status status; | |
773 | assert(kv_pair_list); | |
774 | ||
775 | switch (kv_pair_list->type) { | |
776 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID: | |
777 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID: | |
778 | kv_pair_list->id = identifier; | |
779 | status = LTTNG_MAP_STATUS_OK; | |
780 | break; | |
781 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED: | |
782 | ERR("Cannot set an identifier for an UST per-pid aggregation key value pair list"); | |
783 | status = LTTNG_MAP_STATUS_INVALID; | |
784 | break; | |
785 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL: | |
786 | ERR("Cannot set an identifier for a kernel key value pair list"); | |
787 | status = LTTNG_MAP_STATUS_INVALID; | |
788 | break; | |
789 | default: | |
790 | ERR("Unknown key value par list type %d", kv_pair_list->type); | |
791 | abort(); | |
792 | } | |
793 | ||
794 | return status; | |
795 | } | |
796 | ||
797 | bool lttng_map_key_value_pair_list_get_summed_all_cpu( | |
798 | const struct lttng_map_key_value_pair_list *kv_pair_list) | |
799 | { | |
800 | assert(kv_pair_list); | |
801 | ||
802 | return kv_pair_list->summed_all_cpus; | |
803 | } | |
804 | ||
805 | LTTNG_HIDDEN | |
806 | enum lttng_map_status lttng_map_key_value_pair_list_set_cpu( | |
807 | struct lttng_map_key_value_pair_list *kv_pair_list, | |
808 | uint64_t cpu) | |
809 | { | |
810 | assert(kv_pair_list); | |
811 | ||
812 | kv_pair_list->cpu = cpu; | |
813 | ||
814 | return LTTNG_MAP_STATUS_OK; | |
815 | } | |
816 | ||
817 | uint64_t lttng_map_key_value_pair_list_get_cpu( | |
818 | const struct lttng_map_key_value_pair_list *kv_pair_list) | |
819 | { | |
820 | assert(kv_pair_list); | |
821 | ||
822 | return kv_pair_list->cpu; | |
823 | } | |
824 | ||
825 | enum lttng_map_key_value_pair_list_type lttng_map_key_value_pair_list_get_type( | |
826 | const struct lttng_map_key_value_pair_list *kv_pair_list) | |
827 | { | |
828 | assert(kv_pair_list); | |
829 | ||
830 | return kv_pair_list->type; | |
831 | } | |
832 | ||
833 | LTTNG_HIDDEN | |
834 | enum lttng_map_status lttng_map_key_value_pair_list_append_key_value( | |
835 | struct lttng_map_key_value_pair_list *kv_pair_list, | |
836 | struct lttng_map_key_value_pair *key_value) | |
837 | { | |
838 | int ret; | |
839 | enum lttng_map_status status; | |
840 | ||
841 | assert(kv_pair_list); | |
842 | assert(key_value); | |
843 | ||
844 | ret = lttng_dynamic_pointer_array_add_pointer(&kv_pair_list->array, | |
845 | key_value); | |
846 | if (ret) { | |
847 | status = LTTNG_MAP_STATUS_ERROR; | |
848 | goto end; | |
849 | } | |
850 | ||
851 | status = LTTNG_MAP_STATUS_OK; | |
852 | ||
853 | end: | |
854 | return status; | |
855 | } | |
856 | ||
857 | uint64_t lttng_map_key_value_pair_list_get_identifer( | |
858 | const struct lttng_map_key_value_pair_list *kv_pair_list) | |
859 | { | |
860 | assert(kv_pair_list); | |
861 | ||
862 | switch (kv_pair_list->type) { | |
863 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID: | |
864 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID: | |
865 | break; | |
866 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID_AGGREGATED: | |
867 | ERR("No identifier for UST per-pid aggregation key value pair lists"); | |
868 | abort(); | |
869 | break; | |
870 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_KERNEL: | |
871 | ERR("No identifier for kernel key value pair lists"); | |
872 | abort(); | |
873 | break; | |
874 | default: | |
875 | ERR("Unknown key value par list type %d", kv_pair_list->type); | |
876 | abort(); | |
877 | } | |
878 | ||
879 | return kv_pair_list->id; | |
880 | } | |
881 | ||
882 | const struct lttng_map_key_value_pair *lttng_map_key_value_pair_list_get_at_index( | |
883 | const struct lttng_map_key_value_pair_list *kv_pair_list, | |
884 | unsigned int index) | |
885 | { | |
886 | struct lttng_map_key_value_pair *key_value = NULL; | |
887 | ||
888 | assert(kv_pair_list); | |
889 | if (index >= lttng_dynamic_pointer_array_get_count(&kv_pair_list->array)) { | |
890 | goto end; | |
891 | } | |
892 | ||
893 | key_value = (struct lttng_map_key_value_pair *) | |
894 | lttng_dynamic_pointer_array_get_pointer( | |
895 | &kv_pair_list->array, index); | |
896 | end: | |
897 | return key_value; | |
898 | } | |
899 | ||
900 | enum lttng_map_status lttng_map_key_value_pair_list_get_count( | |
901 | const struct lttng_map_key_value_pair_list *kv_pair_list, | |
902 | unsigned int *count) | |
903 | { | |
904 | enum lttng_map_status status; | |
905 | ||
906 | if (!kv_pair_list || !count) { | |
907 | status = LTTNG_MAP_STATUS_INVALID;; | |
908 | goto end; | |
909 | } | |
910 | ||
911 | *count = lttng_dynamic_pointer_array_get_count(&kv_pair_list->array); | |
912 | ||
913 | status = LTTNG_MAP_STATUS_OK; | |
914 | end: | |
915 | return status; | |
916 | } | |
917 | ||
918 | void lttng_map_key_value_pair_list_destroy(struct lttng_map_key_value_pair_list *kv_pair_list) | |
919 | { | |
920 | if (!kv_pair_list) { | |
921 | return; | |
922 | } | |
923 | ||
924 | lttng_dynamic_pointer_array_reset(&kv_pair_list->array); | |
925 | free(kv_pair_list); | |
926 | } | |
927 | ||
928 | int lttng_map_key_value_pair_list_serialize( | |
929 | const struct lttng_map_key_value_pair_list *kv_pair_list, | |
930 | struct lttng_payload *payload) | |
931 | { | |
932 | int ret; | |
933 | unsigned int i, count; | |
934 | enum lttng_map_status status; | |
935 | struct lttng_map_key_value_pair_list_comm kv_pair_list_comm = {}; | |
936 | ||
937 | kv_pair_list_comm.id = kv_pair_list->id; | |
938 | kv_pair_list_comm.cpu = kv_pair_list->cpu; | |
939 | kv_pair_list_comm.type = (uint8_t) kv_pair_list->type; | |
940 | kv_pair_list_comm.summed_all_cpus = (uint8_t) kv_pair_list->summed_all_cpus; | |
941 | ||
942 | status = lttng_map_key_value_pair_list_get_count(kv_pair_list, &count); | |
943 | if (status != LTTNG_MAP_STATUS_OK) { | |
944 | ret = LTTNG_ERR_INVALID; | |
945 | goto end; | |
946 | } | |
947 | ||
948 | kv_pair_list_comm.count = count; | |
949 | ret = lttng_dynamic_buffer_append(&payload->buffer, &kv_pair_list_comm, | |
950 | sizeof(kv_pair_list_comm)); | |
951 | if (ret) { | |
952 | goto end; | |
953 | } | |
954 | for (i = 0; i < count; i++) { | |
955 | const struct lttng_map_key_value_pair *kv_pair = | |
956 | lttng_map_key_value_pair_list_get_at_index(kv_pair_list, i); | |
957 | ||
958 | assert(kv_pair); | |
959 | ||
960 | ret = lttng_map_key_value_pair_serialize(kv_pair, payload); | |
961 | if (ret) { | |
962 | goto end; | |
963 | } | |
964 | } | |
965 | ||
966 | end: | |
967 | return ret; | |
968 | } | |
969 | ||
970 | LTTNG_HIDDEN | |
971 | ssize_t lttng_map_key_value_pair_list_create_from_payload( | |
972 | struct lttng_payload_view *src_view, | |
973 | struct lttng_map_key_value_pair_list **kv_pair_list) | |
974 | { | |
975 | ssize_t ret, offset = 0; | |
976 | unsigned int i; | |
977 | enum lttng_map_status status; | |
978 | const struct lttng_map_key_value_pair_list_comm *kv_pair_list_comm; | |
979 | struct lttng_map_key_value_pair_list *local_key_values = NULL; | |
980 | ||
981 | kv_pair_list_comm = (typeof(kv_pair_list_comm)) src_view->buffer.data; | |
982 | offset += sizeof(*kv_pair_list_comm); | |
983 | ||
984 | local_key_values = lttng_map_key_value_pair_list_create( | |
985 | kv_pair_list_comm->type, kv_pair_list_comm->summed_all_cpus); | |
986 | if (!local_key_values) { | |
987 | ret = -1; | |
988 | goto end; | |
989 | } | |
990 | ||
991 | local_key_values->cpu = kv_pair_list_comm->cpu; | |
992 | ||
993 | switch (lttng_map_key_value_pair_list_get_type(local_key_values)) { | |
994 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID: | |
995 | case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID: | |
996 | status = lttng_map_key_value_pair_list_set_identifier(local_key_values, | |
997 | kv_pair_list_comm->id); | |
998 | if (status != LTTNG_MAP_STATUS_OK) { | |
999 | ret = -1; | |
1000 | goto end; | |
1001 | } | |
1002 | break; | |
1003 | default: | |
1004 | break; | |
1005 | } | |
1006 | ||
1007 | for (i = 0; i < kv_pair_list_comm->count; i++) { | |
1008 | struct lttng_map_key_value_pair *kv_pair = NULL; | |
1009 | struct lttng_payload_view kv_view = | |
1010 | lttng_payload_view_from_view(src_view, offset, -1); | |
1011 | ssize_t kv_size; | |
1012 | ||
1013 | kv_size = lttng_map_key_value_pair_create_from_payload( | |
1014 | &kv_view, &kv_pair); | |
1015 | if (kv_size < 0) { | |
1016 | ret = kv_size; | |
1017 | goto end; | |
1018 | } | |
1019 | ||
1020 | /* Transfer ownership of the key-value to the collection. */ | |
1021 | status = lttng_map_key_value_pair_list_append_key_value(local_key_values, | |
1022 | kv_pair); | |
1023 | if (status != LTTNG_MAP_STATUS_OK) { | |
1024 | ret = -1; | |
1025 | goto end; | |
1026 | } | |
1027 | ||
1028 | offset += kv_size; | |
1029 | } | |
1030 | ||
1031 | /* Pass ownership to caller. */ | |
1032 | *kv_pair_list = local_key_values; | |
1033 | local_key_values = NULL; | |
1034 | ||
1035 | ret = offset; | |
1036 | end: | |
1037 | lttng_map_key_value_pair_list_destroy(local_key_values); | |
1038 | return ret; | |
1039 | } | |
1040 | ||
1041 | static void delete_map_key_value_pair_list_array_element(void *ptr) | |
1042 | { | |
1043 | struct lttng_map_key_value_pair_list *kv_list = ptr; | |
1044 | lttng_map_key_value_pair_list_destroy(kv_list); | |
1045 | } | |
1046 | ||
1047 | LTTNG_HIDDEN | |
1048 | struct lttng_map_content *lttng_map_content_create( | |
1049 | enum lttng_buffer_type type) | |
1050 | { | |
1051 | struct lttng_map_content *map_content = NULL; | |
1052 | ||
1053 | map_content = zmalloc(sizeof(*map_content)); | |
1054 | if (!map_content) { | |
1055 | goto end; | |
1056 | } | |
1057 | ||
1058 | map_content->type = type; | |
1059 | ||
1060 | lttng_dynamic_pointer_array_init(&map_content->array, | |
1061 | delete_map_key_value_pair_list_array_element); | |
1062 | ||
1063 | end: | |
1064 | return map_content; | |
1065 | } | |
1066 | ||
1067 | enum lttng_map_status lttng_map_content_get_count( | |
1068 | const struct lttng_map_content *map_content, | |
1069 | unsigned int *count) | |
1070 | { | |
1071 | enum lttng_map_status status = LTTNG_MAP_STATUS_OK; | |
1072 | ||
1073 | if (!map_content || !count) { | |
1074 | status = LTTNG_MAP_STATUS_INVALID; | |
1075 | goto end; | |
1076 | } | |
1077 | ||
1078 | *count = lttng_dynamic_pointer_array_get_count(&map_content->array); | |
1079 | status = LTTNG_MAP_STATUS_OK; | |
1080 | end: | |
1081 | return status; | |
1082 | } | |
1083 | ||
1084 | enum lttng_buffer_type lttng_map_content_get_buffer_type( | |
1085 | const struct lttng_map_content *map_content) | |
1086 | { | |
1087 | assert(map_content); | |
1088 | ||
1089 | return map_content->type; | |
1090 | } | |
1091 | ||
1092 | LTTNG_HIDDEN | |
1093 | enum lttng_map_status lttng_map_content_append_key_value_list( | |
1094 | struct lttng_map_content *map_content, | |
1095 | struct lttng_map_key_value_pair_list *kv_list) | |
1096 | { | |
1097 | int ret; | |
1098 | enum lttng_map_status status; | |
1099 | ||
1100 | assert(map_content); | |
1101 | assert(kv_list); | |
1102 | ||
1103 | ret = lttng_dynamic_pointer_array_add_pointer(&map_content->array, | |
1104 | kv_list); | |
1105 | if (ret) { | |
1106 | status = LTTNG_MAP_STATUS_ERROR; | |
1107 | goto end; | |
1108 | } | |
1109 | ||
1110 | status = LTTNG_MAP_STATUS_OK; | |
1111 | ||
1112 | end: | |
1113 | return status; | |
1114 | } | |
1115 | ||
1116 | const struct lttng_map_key_value_pair_list *lttng_map_content_get_at_index( | |
1117 | const struct lttng_map_content *map_content, | |
1118 | unsigned int index) | |
1119 | { | |
1120 | struct lttng_map_key_value_pair_list *kv_pair_list = NULL; | |
1121 | ||
1122 | assert(map_content); | |
1123 | if (index >= lttng_dynamic_pointer_array_get_count(&map_content->array)) { | |
1124 | goto end; | |
1125 | } | |
1126 | ||
1127 | kv_pair_list = (struct lttng_map_key_value_pair_list *) | |
1128 | lttng_dynamic_pointer_array_get_pointer( | |
1129 | &map_content->array, index); | |
1130 | end: | |
1131 | return kv_pair_list; | |
1132 | } | |
1133 | ||
1134 | LTTNG_HIDDEN | |
1135 | ssize_t lttng_map_content_create_from_payload( | |
1136 | struct lttng_payload_view *src_view, | |
1137 | struct lttng_map_content **map_content) | |
1138 | { | |
1139 | ssize_t ret, offset = 0; | |
1140 | unsigned int i; | |
1141 | struct lttng_map_content_comm *map_content_comm; | |
1142 | struct lttng_map_content *local_map_content; | |
1143 | ||
1144 | map_content_comm = (typeof(map_content_comm)) src_view->buffer.data; | |
1145 | offset += sizeof(*map_content_comm); | |
1146 | ||
1147 | local_map_content = lttng_map_content_create(map_content_comm->type); | |
1148 | if (!local_map_content) { | |
1149 | ret = -1; | |
1150 | goto end; | |
1151 | } | |
1152 | ||
1153 | for (i = 0; i < map_content_comm->count; i++) { | |
1154 | struct lttng_map_key_value_pair_list *kv_pair_list = NULL; | |
1155 | struct lttng_payload_view kv_list_view = | |
1156 | lttng_payload_view_from_view(src_view, offset, -1); | |
1157 | ssize_t kv_list_size; | |
1158 | ||
1159 | kv_list_size = lttng_map_key_value_pair_list_create_from_payload( | |
1160 | &kv_list_view, &kv_pair_list); | |
1161 | if (kv_list_size < 0) { | |
1162 | ret = kv_list_size; | |
1163 | goto end; | |
1164 | } | |
1165 | ||
1166 | /* Transfer ownership of the key-value to the collection. */ | |
1167 | ret = lttng_map_content_append_key_value_list(local_map_content, | |
1168 | kv_pair_list); | |
1169 | if (ret < 0) { | |
1170 | ret = -1; | |
1171 | goto end; | |
1172 | } | |
1173 | ||
1174 | offset += kv_list_size; | |
1175 | } | |
1176 | ||
1177 | /* Pass ownership to caller. */ | |
1178 | *map_content = local_map_content; | |
1179 | local_map_content = NULL; | |
1180 | ||
1181 | ret = offset; | |
1182 | end: | |
1183 | lttng_map_content_destroy(local_map_content); | |
1184 | return ret; | |
1185 | } | |
1186 | ||
1187 | LTTNG_HIDDEN | |
1188 | int lttng_map_content_serialize( | |
1189 | const struct lttng_map_content *map_content, | |
1190 | struct lttng_payload *payload) | |
1191 | { | |
1192 | int ret; | |
1193 | unsigned int i, count; | |
1194 | enum lttng_map_status status; | |
1195 | struct lttng_map_content_comm map_content_comm = {}; | |
1196 | ||
1197 | status = lttng_map_content_get_count(map_content, &count); | |
1198 | if (status != LTTNG_MAP_STATUS_OK) { | |
1199 | ret = LTTNG_ERR_INVALID; | |
1200 | goto end; | |
1201 | } | |
1202 | ||
1203 | map_content_comm.count = count; | |
1204 | map_content_comm.type = lttng_map_content_get_buffer_type(map_content); | |
1205 | ||
1206 | ret = lttng_dynamic_buffer_append(&payload->buffer, &map_content_comm, | |
1207 | sizeof(map_content_comm)); | |
1208 | if (ret) { | |
1209 | goto end; | |
1210 | } | |
1211 | for (i = 0; i < count; i++) { | |
1212 | const struct lttng_map_key_value_pair_list *kv_pair_list = | |
1213 | lttng_map_content_get_at_index(map_content, i); | |
1214 | ||
1215 | assert(kv_pair_list); | |
1216 | ||
1217 | ret = lttng_map_key_value_pair_list_serialize(kv_pair_list, payload); | |
1218 | if (ret) { | |
1219 | goto end; | |
1220 | } | |
1221 | } | |
1222 | ||
1223 | end: | |
1224 | return ret; | |
1225 | } | |
1226 | ||
1227 | void lttng_map_content_destroy(struct lttng_map_content *map_content) | |
1228 | { | |
1229 | if (!map_content) { | |
1230 | return; | |
1231 | } | |
1232 | ||
1233 | lttng_dynamic_pointer_array_reset(&map_content->array); | |
1234 | free(map_content); | |
1235 | } |