blob: 55a276f466c83f60cabdfa2ae4c8a0711c6ad1c8 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#ifndef _included_clib_mem_h
39#define _included_clib_mem_h
40
41#include <stdarg.h>
Damjan Marion01914ce2017-09-14 19:04:50 +020042#include <unistd.h>
43#include <sys/mman.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070044
Dave Barachc3799992016-08-15 11:12:27 -040045#include <vppinfra/clib.h> /* uword, etc */
Damjan Marion01914ce2017-09-14 19:04:50 +020046#include <vppinfra/clib_error.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070047#include <vppinfra/mheap_bootstrap.h>
48#include <vppinfra/os.h>
Dave Barachc3799992016-08-15 11:12:27 -040049#include <vppinfra/string.h> /* memcpy, memset */
Ed Warnickecb9cada2015-12-08 15:45:58 -070050#include <vppinfra/valgrind.h>
51
Damjan Marionce8debf2016-02-06 19:16:21 +010052#define CLIB_MAX_MHEAPS 256
53
Ed Warnickecb9cada2015-12-08 15:45:58 -070054/* Per CPU heaps. */
Dave Barachc3799992016-08-15 11:12:27 -040055extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
Ed Warnickecb9cada2015-12-08 15:45:58 -070056
Dave Barachc3799992016-08-15 11:12:27 -040057always_inline void *
58clib_mem_get_per_cpu_heap (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070059{
Damjan Marionf55f9b82017-05-10 21:06:28 +020060 int cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070061 return clib_per_cpu_mheaps[cpu];
62}
63
Dave Barachc3799992016-08-15 11:12:27 -040064always_inline void *
65clib_mem_set_per_cpu_heap (u8 * new_heap)
Ed Warnickecb9cada2015-12-08 15:45:58 -070066{
Damjan Marionf55f9b82017-05-10 21:06:28 +020067 int cpu = os_get_thread_index ();
Dave Barachc3799992016-08-15 11:12:27 -040068 void *old = clib_per_cpu_mheaps[cpu];
Ed Warnickecb9cada2015-12-08 15:45:58 -070069 clib_per_cpu_mheaps[cpu] = new_heap;
70 return old;
71}
72
Dave Barach241e5222016-10-13 10:53:26 -040073/* Memory allocator which may call os_out_of_memory() if it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -070074always_inline void *
Dave Barach241e5222016-10-13 10:53:26 -040075clib_mem_alloc_aligned_at_offset (uword size, uword align, uword align_offset,
76 int os_out_of_memory_on_failure)
Ed Warnickecb9cada2015-12-08 15:45:58 -070077{
Dave Barachc3799992016-08-15 11:12:27 -040078 void *heap, *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 uword offset, cpu;
80
81 if (align_offset > align)
82 {
83 if (align > 0)
84 align_offset %= align;
85 else
86 align_offset = align;
87 }
88
Damjan Marionf55f9b82017-05-10 21:06:28 +020089 cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 heap = clib_per_cpu_mheaps[cpu];
Dave Barachc3799992016-08-15 11:12:27 -040091 heap = mheap_get_aligned (heap, size, align, align_offset, &offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 clib_per_cpu_mheaps[cpu] = heap;
93
94 if (offset != ~0)
95 {
96 p = heap + offset;
97#if CLIB_DEBUG > 0
98 VALGRIND_MALLOCLIKE_BLOCK (p, mheap_data_bytes (heap, offset), 0, 0);
99#endif
100 return p;
101 }
102 else
103 {
Dave Barach241e5222016-10-13 10:53:26 -0400104 if (os_out_of_memory_on_failure)
105 os_out_of_memory ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 return 0;
107 }
108}
109
Dave Barach241e5222016-10-13 10:53:26 -0400110/* Memory allocator which calls os_out_of_memory() when it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111always_inline void *
112clib_mem_alloc (uword size)
Dave Barachc3799992016-08-15 11:12:27 -0400113{
114 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
Dave Barach241e5222016-10-13 10:53:26 -0400115 /* align_offset */ 0,
116 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400117}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118
119always_inline void *
120clib_mem_alloc_aligned (uword size, uword align)
Dave Barachc3799992016-08-15 11:12:27 -0400121{
Dave Barach241e5222016-10-13 10:53:26 -0400122 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
123 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400124}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125
Dave Barach241e5222016-10-13 10:53:26 -0400126/* Memory allocator which calls os_out_of_memory() when it fails */
127always_inline void *
128clib_mem_alloc_or_null (uword size)
129{
130 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
131 /* align_offset */ 0,
132 /* os_out_of_memory */ 0);
133}
134
135always_inline void *
136clib_mem_alloc_aligned_or_null (uword size, uword align)
137{
138 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
139 /* os_out_of_memory */ 0);
140}
141
142
143
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144/* Memory allocator which panics when it fails.
145 Use macro so that clib_panic macro can expand __FUNCTION__ and __LINE__. */
146#define clib_mem_alloc_aligned_no_fail(size,align) \
147({ \
148 uword _clib_mem_alloc_size = (size); \
149 void * _clib_mem_alloc_p; \
150 _clib_mem_alloc_p = clib_mem_alloc_aligned (_clib_mem_alloc_size, (align)); \
151 if (! _clib_mem_alloc_p) \
152 clib_panic ("failed to allocate %d bytes", _clib_mem_alloc_size); \
153 _clib_mem_alloc_p; \
154})
155
156#define clib_mem_alloc_no_fail(size) clib_mem_alloc_aligned_no_fail(size,1)
157
158/* Alias to stack allocator for naming consistency. */
159#define clib_mem_alloc_stack(bytes) __builtin_alloca(bytes)
160
Dave Barachc3799992016-08-15 11:12:27 -0400161always_inline uword
162clib_mem_is_heap_object (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163{
Dave Barachc3799992016-08-15 11:12:27 -0400164 void *heap = clib_mem_get_per_cpu_heap ();
165 uword offset = (uword) p - (uword) heap;
166 mheap_elt_t *e, *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
168 if (offset >= vec_len (heap))
169 return 0;
170
171 e = mheap_elt_at_uoffset (heap, offset);
172 n = mheap_next_elt (e);
Dave Barachc3799992016-08-15 11:12:27 -0400173
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 /* Check that heap forward and reverse pointers agree. */
175 return e->n_user_data == n->prev_n_user_data;
176}
177
Dave Barachc3799992016-08-15 11:12:27 -0400178always_inline void
179clib_mem_free (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180{
Dave Barachc3799992016-08-15 11:12:27 -0400181 u8 *heap = clib_mem_get_per_cpu_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182
183 /* Make sure object is in the correct heap. */
184 ASSERT (clib_mem_is_heap_object (p));
185
186 mheap_put (heap, (u8 *) p - heap);
187
188#if CLIB_DEBUG > 0
189 VALGRIND_FREELIKE_BLOCK (p, 0);
190#endif
191}
192
Dave Barachc3799992016-08-15 11:12:27 -0400193always_inline void *
194clib_mem_realloc (void *p, uword new_size, uword old_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195{
196 /* By default use alloc, copy and free to emulate realloc. */
Dave Barachc3799992016-08-15 11:12:27 -0400197 void *q = clib_mem_alloc (new_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 if (q)
199 {
200 uword copy_size;
201 if (old_size < new_size)
202 copy_size = old_size;
203 else
204 copy_size = new_size;
Damjan Marionf1213b82016-03-13 02:22:06 +0100205 clib_memcpy (q, p, copy_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 clib_mem_free (p);
207 }
208 return q;
209}
210
Dave Barachc3799992016-08-15 11:12:27 -0400211always_inline uword
212clib_mem_size (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213{
214 ASSERT (clib_mem_is_heap_object (p));
Dave Barachc3799992016-08-15 11:12:27 -0400215 mheap_elt_t *e = mheap_user_pointer_to_elt (p);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 return mheap_elt_data_bytes (e);
217}
218
Dave Barachc3799992016-08-15 11:12:27 -0400219always_inline void *
220clib_mem_get_heap (void)
221{
222 return clib_mem_get_per_cpu_heap ();
223}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
Dave Barachc3799992016-08-15 11:12:27 -0400225always_inline void *
226clib_mem_set_heap (void *heap)
227{
228 return clib_mem_set_per_cpu_heap (heap);
229}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230
Dave Barachc3799992016-08-15 11:12:27 -0400231void *clib_mem_init (void *heap, uword size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232
233void clib_mem_exit (void);
234
235uword clib_mem_get_page_size (void);
236
237void clib_mem_validate (void);
238
239void clib_mem_trace (int enable);
240
Dave Barachc3799992016-08-15 11:12:27 -0400241typedef struct
242{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 /* Total number of objects allocated. */
244 uword object_count;
245
246 /* Total allocated bytes. Bytes used and free.
247 used + free = total */
248 uword bytes_total, bytes_used, bytes_free;
249
250 /* Number of bytes used by mheap data structure overhead
251 (e.g. free lists, mheap header). */
252 uword bytes_overhead;
253
254 /* Amount of free space returned to operating system. */
255 uword bytes_free_reclaimed;
Dave Barachc3799992016-08-15 11:12:27 -0400256
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 /* For malloc which puts small objects in sbrk region and
258 large objects in mmap'ed regions. */
259 uword bytes_used_sbrk;
260 uword bytes_used_mmap;
261
262 /* Max. number of bytes in this heap. */
263 uword bytes_max;
264} clib_mem_usage_t;
265
266void clib_mem_usage (clib_mem_usage_t * usage);
267
Dave Barachc3799992016-08-15 11:12:27 -0400268u8 *format_clib_mem_usage (u8 * s, va_list * args);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269
Damjan Marion01914ce2017-09-14 19:04:50 +0200270/* Allocate virtual address space. */
271always_inline void *
272clib_mem_vm_alloc (uword size)
273{
274 void *mmap_addr;
275 uword flags = MAP_PRIVATE;
276
277#ifdef MAP_ANONYMOUS
278 flags |= MAP_ANONYMOUS;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279#endif
280
Damjan Marion01914ce2017-09-14 19:04:50 +0200281 mmap_addr = mmap (0, size, PROT_READ | PROT_WRITE, flags, -1, 0);
282 if (mmap_addr == (void *) -1)
283 mmap_addr = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284
Damjan Marion01914ce2017-09-14 19:04:50 +0200285 return mmap_addr;
286}
287
288always_inline void
289clib_mem_vm_free (void *addr, uword size)
290{
291 munmap (addr, size);
292}
293
294always_inline void *
295clib_mem_vm_unmap (void *addr, uword size)
296{
297 void *mmap_addr;
298 uword flags = MAP_PRIVATE | MAP_FIXED;
299
300 /* To unmap we "map" with no protection. If we actually called
301 munmap then other callers could steal the address space. By
302 changing to PROT_NONE the kernel can free up the pages which is
303 really what we want "unmap" to mean. */
304 mmap_addr = mmap (addr, size, PROT_NONE, flags, -1, 0);
305 if (mmap_addr == (void *) -1)
306 mmap_addr = 0;
307
308 return mmap_addr;
309}
310
311always_inline void *
312clib_mem_vm_map (void *addr, uword size)
313{
314 void *mmap_addr;
315 uword flags = MAP_PRIVATE | MAP_FIXED;
316
317 mmap_addr = mmap (addr, size, (PROT_READ | PROT_WRITE), flags, -1, 0);
318 if (mmap_addr == (void *) -1)
319 mmap_addr = 0;
320
321 return mmap_addr;
322}
323
324typedef struct
325{
326#define CLIB_MEM_VM_F_SHARED (1 << 0)
327#define CLIB_MEM_VM_F_HUGETLB (1 << 1)
328#define CLIB_MEM_VM_F_NUMA_PREFER (1 << 2)
329#define CLIB_MEM_VM_F_NUMA_FORCE (1 << 3)
330#define CLIB_MEM_VM_F_HUGETLB_PREALLOC (1 << 4)
Damjan Marion7b185362018-03-04 16:41:35 +0100331#define CLIB_MEM_VM_F_LOCKED (1 << 5)
Damjan Marion01914ce2017-09-14 19:04:50 +0200332 u32 flags; /**< vm allocation flags:
333 <br> CLIB_MEM_VM_F_SHARED: request shared memory, file
Florin Corasd3e83a92018-01-16 02:40:18 -0800334 descriptor will be provided on successful allocation.
Damjan Marion01914ce2017-09-14 19:04:50 +0200335 <br> CLIB_MEM_VM_F_HUGETLB: request hugepages.
336 <br> CLIB_MEM_VM_F_NUMA_PREFER: numa_node field contains valid
337 numa node preference.
338 <br> CLIB_MEM_VM_F_NUMA_FORCE: fail if setting numa policy fails.
339 <br> CLIB_MEM_VM_F_HUGETLB_PREALLOC: pre-allocate hugepages if
340 number of available pages is not sufficient.
Damjan Marion7b185362018-03-04 16:41:35 +0100341 <br> CLIB_MEM_VM_F_LOCKED: request locked memory.
Damjan Marion01914ce2017-09-14 19:04:50 +0200342 */
343 char *name; /**< Name for memory allocation, set by caller. */
344 uword size; /**< Allocation size, set by caller. */
345 int numa_node; /**< numa node preference. Valid if CLIB_MEM_VM_F_NUMA_PREFER set. */
346 void *addr; /**< Pointer to allocated memory, set on successful allocation. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800347 int fd; /**< File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set. */
Damjan Marion01914ce2017-09-14 19:04:50 +0200348 int log2_page_size; /* Page size in log2 format, set on successful allocation. */
349 int n_pages; /* Number of pages. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800350 uword requested_va; /**< Request fixed position mapping */
Damjan Marion01914ce2017-09-14 19:04:50 +0200351} clib_mem_vm_alloc_t;
352
353clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a);
Florin Corasd3e83a92018-01-16 02:40:18 -0800354u64 clib_mem_vm_get_page_size (int fd);
Damjan Marion01914ce2017-09-14 19:04:50 +0200355int clib_mem_vm_get_log2_page_size (int fd);
356u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages);
357
Florin Corasd3e83a92018-01-16 02:40:18 -0800358typedef struct
359{
360 uword size; /**< Map size */
361 int fd; /**< File descriptor to be mapped */
362 uword requested_va; /**< Request fixed position mapping */
363 void *addr; /**< Pointer to mapped memory, if successful */
364} clib_mem_vm_map_t;
Florin Corasd3e83a92018-01-16 02:40:18 -0800365
Florin Corasb384b542018-01-15 01:08:33 -0800366clib_error_t *clib_mem_vm_ext_map (clib_mem_vm_map_t * a);
367void clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368
Dave Barachc3799992016-08-15 11:12:27 -0400369#include <vppinfra/error.h> /* clib_panic */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370
371#endif /* _included_clib_mem_h */
Dave Barachc3799992016-08-15 11:12:27 -0400372
373/*
374 * fd.io coding-style-patch-verification: ON
375 *
376 * Local Variables:
377 * eval: (c-set-style "gnu")
378 * End:
379 */