blob: e31ec82e7c5cd7e0f59e45bdedb90ed3b2c556c8 [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>
Dave Barach6a5adc32018-07-04 10:56:23 -040047
48#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -070049#include <vppinfra/mheap_bootstrap.h>
Dave Barach6a5adc32018-07-04 10:56:23 -040050#else
51#include <vppinfra/dlmalloc.h>
52#endif
53
Ed Warnickecb9cada2015-12-08 15:45:58 -070054#include <vppinfra/os.h>
Dave Barachb7b92992018-10-17 10:38:51 -040055#include <vppinfra/string.h> /* memcpy, clib_memset */
Ed Warnickecb9cada2015-12-08 15:45:58 -070056#include <vppinfra/valgrind.h>
57
Damjan Marionce8debf2016-02-06 19:16:21 +010058#define CLIB_MAX_MHEAPS 256
59
Ed Warnickecb9cada2015-12-08 15:45:58 -070060/* Per CPU heaps. */
Dave Barachc3799992016-08-15 11:12:27 -040061extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
Ed Warnickecb9cada2015-12-08 15:45:58 -070062
Dave Barachc3799992016-08-15 11:12:27 -040063always_inline void *
64clib_mem_get_per_cpu_heap (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070065{
Damjan Marionf55f9b82017-05-10 21:06:28 +020066 int cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070067 return clib_per_cpu_mheaps[cpu];
68}
69
Dave Barachc3799992016-08-15 11:12:27 -040070always_inline void *
71clib_mem_set_per_cpu_heap (u8 * new_heap)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
Damjan Marionf55f9b82017-05-10 21:06:28 +020073 int cpu = os_get_thread_index ();
Dave Barachc3799992016-08-15 11:12:27 -040074 void *old = clib_per_cpu_mheaps[cpu];
Ed Warnickecb9cada2015-12-08 15:45:58 -070075 clib_per_cpu_mheaps[cpu] = new_heap;
76 return old;
77}
78
Dave Barach241e5222016-10-13 10:53:26 -040079/* Memory allocator which may call os_out_of_memory() if it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -070080always_inline void *
Dave Barach241e5222016-10-13 10:53:26 -040081clib_mem_alloc_aligned_at_offset (uword size, uword align, uword align_offset,
82 int os_out_of_memory_on_failure)
Ed Warnickecb9cada2015-12-08 15:45:58 -070083{
Dave Barachc3799992016-08-15 11:12:27 -040084 void *heap, *p;
Dave Barach6a5adc32018-07-04 10:56:23 -040085 uword cpu;
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
87 if (align_offset > align)
88 {
89 if (align > 0)
90 align_offset %= align;
91 else
92 align_offset = align;
93 }
94
Damjan Marionf55f9b82017-05-10 21:06:28 +020095 cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070096 heap = clib_per_cpu_mheaps[cpu];
Dave Barach6a5adc32018-07-04 10:56:23 -040097
98#if USE_DLMALLOC == 0
99 uword offset;
Dave Barachc3799992016-08-15 11:12:27 -0400100 heap = mheap_get_aligned (heap, size, align, align_offset, &offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101 clib_per_cpu_mheaps[cpu] = heap;
102
103 if (offset != ~0)
104 {
105 p = heap + offset;
106#if CLIB_DEBUG > 0
107 VALGRIND_MALLOCLIKE_BLOCK (p, mheap_data_bytes (heap, offset), 0, 0);
108#endif
109 return p;
110 }
111 else
112 {
Dave Barach241e5222016-10-13 10:53:26 -0400113 if (os_out_of_memory_on_failure)
114 os_out_of_memory ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115 return 0;
116 }
Dave Barach6a5adc32018-07-04 10:56:23 -0400117#else
118 p = mspace_get_aligned (heap, size, align, align_offset);
119 if (PREDICT_FALSE (p == 0))
120 {
121 if (os_out_of_memory_on_failure)
122 os_out_of_memory ();
123 return 0;
124 }
125
126 return p;
127#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128}
129
Dave Barach241e5222016-10-13 10:53:26 -0400130/* Memory allocator which calls os_out_of_memory() when it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131always_inline void *
132clib_mem_alloc (uword size)
Dave Barachc3799992016-08-15 11:12:27 -0400133{
134 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
Dave Barach241e5222016-10-13 10:53:26 -0400135 /* align_offset */ 0,
136 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400137}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
139always_inline void *
140clib_mem_alloc_aligned (uword size, uword align)
Dave Barachc3799992016-08-15 11:12:27 -0400141{
Dave Barach241e5222016-10-13 10:53:26 -0400142 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
143 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400144}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Dave Barach241e5222016-10-13 10:53:26 -0400146/* Memory allocator which calls os_out_of_memory() when it fails */
147always_inline void *
148clib_mem_alloc_or_null (uword size)
149{
150 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
151 /* align_offset */ 0,
152 /* os_out_of_memory */ 0);
153}
154
155always_inline void *
156clib_mem_alloc_aligned_or_null (uword size, uword align)
157{
158 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
159 /* os_out_of_memory */ 0);
160}
161
162
163
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164/* Memory allocator which panics when it fails.
165 Use macro so that clib_panic macro can expand __FUNCTION__ and __LINE__. */
166#define clib_mem_alloc_aligned_no_fail(size,align) \
167({ \
168 uword _clib_mem_alloc_size = (size); \
169 void * _clib_mem_alloc_p; \
170 _clib_mem_alloc_p = clib_mem_alloc_aligned (_clib_mem_alloc_size, (align)); \
171 if (! _clib_mem_alloc_p) \
172 clib_panic ("failed to allocate %d bytes", _clib_mem_alloc_size); \
173 _clib_mem_alloc_p; \
174})
175
176#define clib_mem_alloc_no_fail(size) clib_mem_alloc_aligned_no_fail(size,1)
177
178/* Alias to stack allocator for naming consistency. */
179#define clib_mem_alloc_stack(bytes) __builtin_alloca(bytes)
180
Dave Barachc3799992016-08-15 11:12:27 -0400181always_inline uword
182clib_mem_is_heap_object (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183{
Dave Barach6a5adc32018-07-04 10:56:23 -0400184#if USE_DLMALLOC == 0
Dave Barachc3799992016-08-15 11:12:27 -0400185 void *heap = clib_mem_get_per_cpu_heap ();
186 uword offset = (uword) p - (uword) heap;
187 mheap_elt_t *e, *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
189 if (offset >= vec_len (heap))
190 return 0;
191
192 e = mheap_elt_at_uoffset (heap, offset);
193 n = mheap_next_elt (e);
Dave Barachc3799992016-08-15 11:12:27 -0400194
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 /* Check that heap forward and reverse pointers agree. */
196 return e->n_user_data == n->prev_n_user_data;
Dave Barach6a5adc32018-07-04 10:56:23 -0400197#else
198 void *heap = clib_mem_get_per_cpu_heap ();
199
200 return mspace_is_heap_object (heap, p);
201#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202}
203
Dave Barachc3799992016-08-15 11:12:27 -0400204always_inline void
205clib_mem_free (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206{
Dave Barachc3799992016-08-15 11:12:27 -0400207 u8 *heap = clib_mem_get_per_cpu_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
209 /* Make sure object is in the correct heap. */
210 ASSERT (clib_mem_is_heap_object (p));
211
Dave Barach6a5adc32018-07-04 10:56:23 -0400212#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 mheap_put (heap, (u8 *) p - heap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400214#else
215 mspace_put (heap, p);
216#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
218#if CLIB_DEBUG > 0
219 VALGRIND_FREELIKE_BLOCK (p, 0);
220#endif
221}
222
Dave Barachc3799992016-08-15 11:12:27 -0400223always_inline void *
224clib_mem_realloc (void *p, uword new_size, uword old_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225{
226 /* By default use alloc, copy and free to emulate realloc. */
Dave Barachc3799992016-08-15 11:12:27 -0400227 void *q = clib_mem_alloc (new_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 if (q)
229 {
230 uword copy_size;
231 if (old_size < new_size)
232 copy_size = old_size;
233 else
234 copy_size = new_size;
Dave Barach178cf492018-11-13 16:34:13 -0500235 clib_memcpy_fast (q, p, copy_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 clib_mem_free (p);
237 }
238 return q;
239}
240
Dave Barachc3799992016-08-15 11:12:27 -0400241always_inline uword
242clib_mem_size (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Dave Barach6a5adc32018-07-04 10:56:23 -0400244#if USE_DLMALLOC == 0
Dave Barachc3799992016-08-15 11:12:27 -0400245 mheap_elt_t *e = mheap_user_pointer_to_elt (p);
Dave Barach6a5adc32018-07-04 10:56:23 -0400246 ASSERT (clib_mem_is_heap_object (p));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 return mheap_elt_data_bytes (e);
Dave Barach6a5adc32018-07-04 10:56:23 -0400248#else
249 ASSERT (clib_mem_is_heap_object (p));
250 return mspace_usable_size_with_delta (p);
251#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252}
253
Dave Barachc3799992016-08-15 11:12:27 -0400254always_inline void *
255clib_mem_get_heap (void)
256{
257 return clib_mem_get_per_cpu_heap ();
258}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259
Dave Barachc3799992016-08-15 11:12:27 -0400260always_inline void *
261clib_mem_set_heap (void *heap)
262{
263 return clib_mem_set_per_cpu_heap (heap);
264}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Dave Barachc3799992016-08-15 11:12:27 -0400266void *clib_mem_init (void *heap, uword size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400267void *clib_mem_init_thread_safe (void *memory, uword memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700268
269void clib_mem_exit (void);
270
271uword clib_mem_get_page_size (void);
272
273void clib_mem_validate (void);
274
275void clib_mem_trace (int enable);
276
Dave Barachd67a4282019-06-15 12:46:13 -0400277int clib_mem_is_traced (void);
278
Dave Barachc3799992016-08-15 11:12:27 -0400279typedef struct
280{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 /* Total number of objects allocated. */
282 uword object_count;
283
284 /* Total allocated bytes. Bytes used and free.
285 used + free = total */
286 uword bytes_total, bytes_used, bytes_free;
287
288 /* Number of bytes used by mheap data structure overhead
289 (e.g. free lists, mheap header). */
290 uword bytes_overhead;
291
292 /* Amount of free space returned to operating system. */
293 uword bytes_free_reclaimed;
Dave Barachc3799992016-08-15 11:12:27 -0400294
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 /* For malloc which puts small objects in sbrk region and
296 large objects in mmap'ed regions. */
297 uword bytes_used_sbrk;
298 uword bytes_used_mmap;
299
300 /* Max. number of bytes in this heap. */
301 uword bytes_max;
302} clib_mem_usage_t;
303
304void clib_mem_usage (clib_mem_usage_t * usage);
305
Dave Barachc3799992016-08-15 11:12:27 -0400306u8 *format_clib_mem_usage (u8 * s, va_list * args);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307
Damjan Marion01914ce2017-09-14 19:04:50 +0200308/* Allocate virtual address space. */
309always_inline void *
310clib_mem_vm_alloc (uword size)
311{
312 void *mmap_addr;
313 uword flags = MAP_PRIVATE;
314
315#ifdef MAP_ANONYMOUS
316 flags |= MAP_ANONYMOUS;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700317#endif
318
Damjan Marion01914ce2017-09-14 19:04:50 +0200319 mmap_addr = mmap (0, size, PROT_READ | PROT_WRITE, flags, -1, 0);
320 if (mmap_addr == (void *) -1)
321 mmap_addr = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322
Damjan Marion01914ce2017-09-14 19:04:50 +0200323 return mmap_addr;
324}
325
326always_inline void
327clib_mem_vm_free (void *addr, uword size)
328{
329 munmap (addr, size);
330}
331
332always_inline void *
333clib_mem_vm_unmap (void *addr, uword size)
334{
335 void *mmap_addr;
336 uword flags = MAP_PRIVATE | MAP_FIXED;
337
338 /* To unmap we "map" with no protection. If we actually called
339 munmap then other callers could steal the address space. By
340 changing to PROT_NONE the kernel can free up the pages which is
341 really what we want "unmap" to mean. */
342 mmap_addr = mmap (addr, size, PROT_NONE, flags, -1, 0);
343 if (mmap_addr == (void *) -1)
344 mmap_addr = 0;
345
346 return mmap_addr;
347}
348
349always_inline void *
350clib_mem_vm_map (void *addr, uword size)
351{
352 void *mmap_addr;
Dave Barache89be4e2018-08-29 08:50:40 -0400353 uword flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
Damjan Marion01914ce2017-09-14 19:04:50 +0200354
355 mmap_addr = mmap (addr, size, (PROT_READ | PROT_WRITE), flags, -1, 0);
356 if (mmap_addr == (void *) -1)
357 mmap_addr = 0;
358
359 return mmap_addr;
360}
361
362typedef struct
363{
364#define CLIB_MEM_VM_F_SHARED (1 << 0)
365#define CLIB_MEM_VM_F_HUGETLB (1 << 1)
366#define CLIB_MEM_VM_F_NUMA_PREFER (1 << 2)
367#define CLIB_MEM_VM_F_NUMA_FORCE (1 << 3)
368#define CLIB_MEM_VM_F_HUGETLB_PREALLOC (1 << 4)
Damjan Marion7b185362018-03-04 16:41:35 +0100369#define CLIB_MEM_VM_F_LOCKED (1 << 5)
Damjan Marion01914ce2017-09-14 19:04:50 +0200370 u32 flags; /**< vm allocation flags:
371 <br> CLIB_MEM_VM_F_SHARED: request shared memory, file
Florin Corasd3e83a92018-01-16 02:40:18 -0800372 descriptor will be provided on successful allocation.
Damjan Marion01914ce2017-09-14 19:04:50 +0200373 <br> CLIB_MEM_VM_F_HUGETLB: request hugepages.
374 <br> CLIB_MEM_VM_F_NUMA_PREFER: numa_node field contains valid
375 numa node preference.
376 <br> CLIB_MEM_VM_F_NUMA_FORCE: fail if setting numa policy fails.
377 <br> CLIB_MEM_VM_F_HUGETLB_PREALLOC: pre-allocate hugepages if
378 number of available pages is not sufficient.
Damjan Marion7b185362018-03-04 16:41:35 +0100379 <br> CLIB_MEM_VM_F_LOCKED: request locked memory.
Damjan Marion01914ce2017-09-14 19:04:50 +0200380 */
381 char *name; /**< Name for memory allocation, set by caller. */
382 uword size; /**< Allocation size, set by caller. */
383 int numa_node; /**< numa node preference. Valid if CLIB_MEM_VM_F_NUMA_PREFER set. */
384 void *addr; /**< Pointer to allocated memory, set on successful allocation. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800385 int fd; /**< File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set. */
Damjan Marion01914ce2017-09-14 19:04:50 +0200386 int log2_page_size; /* Page size in log2 format, set on successful allocation. */
387 int n_pages; /* Number of pages. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800388 uword requested_va; /**< Request fixed position mapping */
Damjan Marion01914ce2017-09-14 19:04:50 +0200389} clib_mem_vm_alloc_t;
390
Damjan Marion567e61d2018-10-24 17:08:26 +0200391clib_error_t *clib_mem_create_fd (char *name, int *fdp);
Damjan Marion1636b162018-10-19 12:54:42 +0200392clib_error_t *clib_mem_create_hugetlb_fd (char *name, int *fdp);
Damjan Marion01914ce2017-09-14 19:04:50 +0200393clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a);
Haiyang Tan642829d2018-10-09 19:09:45 -0700394void clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a);
Damjan Marion567e61d2018-10-24 17:08:26 +0200395u64 clib_mem_get_fd_page_size (int fd);
Damjan Marion9787f5f2018-10-24 12:56:32 +0200396uword clib_mem_get_default_hugepage_size (void);
Damjan Marion567e61d2018-10-24 17:08:26 +0200397int clib_mem_get_fd_log2_page_size (int fd);
Damjan Marion01914ce2017-09-14 19:04:50 +0200398u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages);
399
Florin Corasd3e83a92018-01-16 02:40:18 -0800400typedef struct
401{
402 uword size; /**< Map size */
403 int fd; /**< File descriptor to be mapped */
404 uword requested_va; /**< Request fixed position mapping */
405 void *addr; /**< Pointer to mapped memory, if successful */
406} clib_mem_vm_map_t;
Florin Corasd3e83a92018-01-16 02:40:18 -0800407
Florin Corasb384b542018-01-15 01:08:33 -0800408clib_error_t *clib_mem_vm_ext_map (clib_mem_vm_map_t * a);
409void clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400410void mheap_trace (void *v, int enable);
Dave Barach8fdde3c2019-05-17 10:46:40 -0400411uword clib_mem_trace_enable_disable (uword enable);
412void clib_mem_trace (int enable);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413
Dave Barachc3799992016-08-15 11:12:27 -0400414#include <vppinfra/error.h> /* clib_panic */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
416#endif /* _included_clib_mem_h */
Dave Barachc3799992016-08-15 11:12:27 -0400417
418/*
419 * fd.io coding-style-patch-verification: ON
420 *
421 * Local Variables:
422 * eval: (c-set-style "gnu")
423 * End:
424 */