xref: /dpdk/lib/eal/common/eal_common_lcore_var.c (revision 9ebdbe62c2aaae8f71851483139b3b4dcfaf991b)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2024 Ericsson AB
3  */
4 
5 #include <inttypes.h>
6 #include <stdlib.h>
7 
8 #ifdef RTE_EXEC_ENV_WINDOWS
9 #include <malloc.h>
10 #endif
11 
12 #include <rte_common.h>
13 #include <rte_debug.h>
14 #include <rte_log.h>
15 
16 #include <rte_lcore_var.h>
17 
18 #include "eal_private.h"
19 #include "eal_lcore_var.h"
20 
21 /*
22  * Refer to the programmer's guide for an overview
23  * of the lcore variables implementation.
24  */
25 
26 /* base unit */
27 struct lcore_var_buffer {
28 	char data[RTE_MAX_LCORE_VAR * RTE_MAX_LCORE];
29 	struct lcore_var_buffer *prev;
30 };
31 
32 /* last allocated unit */
33 static struct lcore_var_buffer *current_buffer;
34 
35 /* initialized to trigger buffer allocation on first allocation */
36 static size_t offset = RTE_MAX_LCORE_VAR;
37 
38 /* >8 end of documented variables */
39 
40 static void *
41 lcore_var_alloc(size_t size, size_t align)
42 {
43 	void *handle;
44 	unsigned int lcore_id;
45 	void *value;
46 
47 	offset = RTE_ALIGN_CEIL(offset, align);
48 
49 	if (offset + size > RTE_MAX_LCORE_VAR) {
50 		struct lcore_var_buffer *prev = current_buffer;
51 		size_t alloc_size =
52 			RTE_ALIGN_CEIL(sizeof(struct lcore_var_buffer),	RTE_CACHE_LINE_SIZE);
53 #ifdef RTE_EXEC_ENV_WINDOWS
54 		current_buffer = _aligned_malloc(alloc_size, RTE_CACHE_LINE_SIZE);
55 #else
56 		current_buffer = aligned_alloc(RTE_CACHE_LINE_SIZE, alloc_size);
57 #endif
58 		RTE_VERIFY(current_buffer != NULL);
59 
60 		current_buffer->prev = prev;
61 
62 		offset = 0;
63 	}
64 
65 	handle = &current_buffer->data[offset];
66 
67 	offset += size;
68 
69 	RTE_LCORE_VAR_FOREACH(lcore_id, value, handle)
70 		memset(value, 0, size);
71 
72 	EAL_LOG(DEBUG, "Allocated %"PRIuPTR" bytes of per-lcore data with a "
73 			"%"PRIuPTR"-byte alignment", size, align);
74 
75 	return handle;
76 }
77 
78 void *
79 rte_lcore_var_alloc(size_t size, size_t align)
80 {
81 	/* Having the per-lcore buffer size aligned on cache lines
82 	 * assures as well as having the base pointer aligned on cache size
83 	 * assures that aligned offsets also translate to aligned pointers
84 	 * across all values.
85 	 */
86 	RTE_BUILD_BUG_ON(RTE_MAX_LCORE_VAR % RTE_CACHE_LINE_SIZE != 0);
87 	RTE_VERIFY(align <= RTE_CACHE_LINE_SIZE);
88 	RTE_VERIFY(size <= RTE_MAX_LCORE_VAR);
89 
90 	/* '0' means asking for worst-case alignment requirements */
91 	if (align == 0)
92 #ifdef RTE_TOOLCHAIN_MSVC
93 		/* MSVC <stddef.h> is missing the max_align_t typedef */
94 		align = alignof(double);
95 #else
96 		align = alignof(max_align_t);
97 #endif
98 
99 	RTE_VERIFY(rte_is_power_of_2(align));
100 
101 	return lcore_var_alloc(size, align);
102 }
103 
104 void
105 eal_lcore_var_cleanup(void)
106 {
107 	while (current_buffer != NULL) {
108 		struct lcore_var_buffer *prev = current_buffer->prev;
109 
110 #ifdef RTE_EXEC_ENV_WINDOWS
111 		_aligned_free(current_buffer);
112 #else
113 		free(current_buffer);
114 #endif
115 
116 		current_buffer = prev;
117 	}
118 }
119