blob: 14b2761c881ca7fe0eaf78830e1c70f608d44f78 [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
Damjan Marionce8debf2016-02-06 19:16:21 +010057#define CLIB_MAX_MHEAPS 256
58
Ed Warnickecb9cada2015-12-08 15:45:58 -070059/* Per CPU heaps. */
Dave Barachc3799992016-08-15 11:12:27 -040060extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
Ed Warnickecb9cada2015-12-08 15:45:58 -070061
Nathan Skrzypczakd516ca42019-08-01 18:14:06 +020062always_inline void
63clib_mem_set_thread_index (void)
64{
65 /*
66 * Find an unused slot in the per-cpu-mheaps array,
67 * and grab it for this thread. We need to be able to
68 * push/pop the thread heap without affecting other thread(s).
69 */
70 int i;
71 if (__os_thread_index != 0)
72 return;
73 for (i = 0; i < ARRAY_LEN (clib_per_cpu_mheaps); i++)
74 if (clib_atomic_bool_cmp_and_swap (&clib_per_cpu_mheaps[i],
75 0, clib_per_cpu_mheaps[0]))
76 {
77 os_set_thread_index (i);
78 break;
79 }
80 ASSERT (__os_thread_index > 0);
81}
82
Dave Barachc3799992016-08-15 11:12:27 -040083always_inline void *
84clib_mem_get_per_cpu_heap (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070085{
Damjan Marionf55f9b82017-05-10 21:06:28 +020086 int cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 return clib_per_cpu_mheaps[cpu];
88}
89
Dave Barachc3799992016-08-15 11:12:27 -040090always_inline void *
91clib_mem_set_per_cpu_heap (u8 * new_heap)
Ed Warnickecb9cada2015-12-08 15:45:58 -070092{
Damjan Marionf55f9b82017-05-10 21:06:28 +020093 int cpu = os_get_thread_index ();
Dave Barachc3799992016-08-15 11:12:27 -040094 void *old = clib_per_cpu_mheaps[cpu];
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 clib_per_cpu_mheaps[cpu] = new_heap;
96 return old;
97}
98
Dave Barach241e5222016-10-13 10:53:26 -040099/* Memory allocator which may call os_out_of_memory() if it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100always_inline void *
Dave Barach241e5222016-10-13 10:53:26 -0400101clib_mem_alloc_aligned_at_offset (uword size, uword align, uword align_offset,
102 int os_out_of_memory_on_failure)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103{
Dave Barachc3799992016-08-15 11:12:27 -0400104 void *heap, *p;
Dave Barach6a5adc32018-07-04 10:56:23 -0400105 uword cpu;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
107 if (align_offset > align)
108 {
109 if (align > 0)
110 align_offset %= align;
111 else
112 align_offset = align;
113 }
114
Damjan Marionf55f9b82017-05-10 21:06:28 +0200115 cpu = os_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 heap = clib_per_cpu_mheaps[cpu];
Dave Barach6a5adc32018-07-04 10:56:23 -0400117
118#if USE_DLMALLOC == 0
119 uword offset;
Dave Barachc3799992016-08-15 11:12:27 -0400120 heap = mheap_get_aligned (heap, size, align, align_offset, &offset);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121 clib_per_cpu_mheaps[cpu] = heap;
122
123 if (offset != ~0)
124 {
125 p = heap + offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 return p;
127 }
128 else
129 {
Dave Barach241e5222016-10-13 10:53:26 -0400130 if (os_out_of_memory_on_failure)
131 os_out_of_memory ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 return 0;
133 }
Dave Barach6a5adc32018-07-04 10:56:23 -0400134#else
135 p = mspace_get_aligned (heap, size, align, align_offset);
136 if (PREDICT_FALSE (p == 0))
137 {
138 if (os_out_of_memory_on_failure)
139 os_out_of_memory ();
140 return 0;
141 }
142
143 return p;
144#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145}
146
Dave Barach241e5222016-10-13 10:53:26 -0400147/* Memory allocator which calls os_out_of_memory() when it fails */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148always_inline void *
149clib_mem_alloc (uword size)
Dave Barachc3799992016-08-15 11:12:27 -0400150{
151 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
Dave Barach241e5222016-10-13 10:53:26 -0400152 /* align_offset */ 0,
153 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400154}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155
156always_inline void *
157clib_mem_alloc_aligned (uword size, uword align)
Dave Barachc3799992016-08-15 11:12:27 -0400158{
Dave Barach241e5222016-10-13 10:53:26 -0400159 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
160 /* os_out_of_memory */ 1);
Dave Barachc3799992016-08-15 11:12:27 -0400161}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Dave Barach241e5222016-10-13 10:53:26 -0400163/* Memory allocator which calls os_out_of_memory() when it fails */
164always_inline void *
165clib_mem_alloc_or_null (uword size)
166{
167 return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
168 /* align_offset */ 0,
169 /* os_out_of_memory */ 0);
170}
171
172always_inline void *
173clib_mem_alloc_aligned_or_null (uword size, uword align)
174{
175 return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
176 /* os_out_of_memory */ 0);
177}
178
179
180
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181/* Memory allocator which panics when it fails.
182 Use macro so that clib_panic macro can expand __FUNCTION__ and __LINE__. */
183#define clib_mem_alloc_aligned_no_fail(size,align) \
184({ \
185 uword _clib_mem_alloc_size = (size); \
186 void * _clib_mem_alloc_p; \
187 _clib_mem_alloc_p = clib_mem_alloc_aligned (_clib_mem_alloc_size, (align)); \
188 if (! _clib_mem_alloc_p) \
189 clib_panic ("failed to allocate %d bytes", _clib_mem_alloc_size); \
190 _clib_mem_alloc_p; \
191})
192
193#define clib_mem_alloc_no_fail(size) clib_mem_alloc_aligned_no_fail(size,1)
194
195/* Alias to stack allocator for naming consistency. */
196#define clib_mem_alloc_stack(bytes) __builtin_alloca(bytes)
197
Dave Barachc3799992016-08-15 11:12:27 -0400198always_inline uword
199clib_mem_is_heap_object (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200{
Dave Barach6a5adc32018-07-04 10:56:23 -0400201#if USE_DLMALLOC == 0
Dave Barachc3799992016-08-15 11:12:27 -0400202 void *heap = clib_mem_get_per_cpu_heap ();
203 uword offset = (uword) p - (uword) heap;
204 mheap_elt_t *e, *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
206 if (offset >= vec_len (heap))
207 return 0;
208
209 e = mheap_elt_at_uoffset (heap, offset);
210 n = mheap_next_elt (e);
Dave Barachc3799992016-08-15 11:12:27 -0400211
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 /* Check that heap forward and reverse pointers agree. */
213 return e->n_user_data == n->prev_n_user_data;
Dave Barach6a5adc32018-07-04 10:56:23 -0400214#else
215 void *heap = clib_mem_get_per_cpu_heap ();
216
217 return mspace_is_heap_object (heap, p);
218#endif /* USE_DLMALLOC */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219}
220
Dave Barachc3799992016-08-15 11:12:27 -0400221always_inline void
222clib_mem_free (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
Dave Barachc3799992016-08-15 11:12:27 -0400224 u8 *heap = clib_mem_get_per_cpu_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
226 /* Make sure object is in the correct heap. */
227 ASSERT (clib_mem_is_heap_object (p));
228
Dave Barach6a5adc32018-07-04 10:56:23 -0400229#if USE_DLMALLOC == 0
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230 mheap_put (heap, (u8 *) p - heap);
Dave Barach6a5adc32018-07-04 10:56:23 -0400231#else
232 mspace_put (heap, p);
233#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234}
235
Dave Barachc3799992016-08-15 11:12:27 -0400236always_inline void *
237clib_mem_realloc (void *p, uword new_size, uword old_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238{
239 /* By default use alloc, copy and free to emulate realloc. */
Dave Barachc3799992016-08-15 11:12:27 -0400240 void *q = clib_mem_alloc (new_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 if (q)
242 {
243 uword copy_size;
244 if (old_size < new_size)
245 copy_size = old_size;
246 else
247 copy_size = new_size;
Dave Barach178cf492018-11-13 16:34:13 -0500248 clib_memcpy_fast (q, p, copy_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 clib_mem_free (p);
250 }
251 return q;
252}
253
Dave Barachc3799992016-08-15 11:12:27 -0400254always_inline uword
255clib_mem_size (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256{
Dave Barach6a5adc32018-07-04 10:56:23 -0400257#if USE_DLMALLOC == 0
Dave Barachc3799992016-08-15 11:12:27 -0400258 mheap_elt_t *e = mheap_user_pointer_to_elt (p);
Dave Barach6a5adc32018-07-04 10:56:23 -0400259 ASSERT (clib_mem_is_heap_object (p));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 return mheap_elt_data_bytes (e);
Dave Barach6a5adc32018-07-04 10:56:23 -0400261#else
262 ASSERT (clib_mem_is_heap_object (p));
263 return mspace_usable_size_with_delta (p);
264#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265}
266
Benoît Ganne78af0a82019-04-29 17:27:24 +0200267always_inline void
268clib_mem_free_s (void *p)
269{
270 uword size = clib_mem_size (p);
271 memset_s_inline (p, size, 0, size);
272 clib_mem_free (p);
273}
274
Dave Barachc3799992016-08-15 11:12:27 -0400275always_inline void *
276clib_mem_get_heap (void)
277{
278 return clib_mem_get_per_cpu_heap ();
279}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
Dave Barachc3799992016-08-15 11:12:27 -0400281always_inline void *
282clib_mem_set_heap (void *heap)
283{
284 return clib_mem_set_per_cpu_heap (heap);
285}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
Dave Barachc3799992016-08-15 11:12:27 -0400287void *clib_mem_init (void *heap, uword size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400288void *clib_mem_init_thread_safe (void *memory, uword memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
290void clib_mem_exit (void);
291
292uword clib_mem_get_page_size (void);
293
294void clib_mem_validate (void);
295
296void clib_mem_trace (int enable);
297
Dave Barachd67a4282019-06-15 12:46:13 -0400298int clib_mem_is_traced (void);
299
Dave Barachc3799992016-08-15 11:12:27 -0400300typedef struct
301{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302 /* Total number of objects allocated. */
303 uword object_count;
304
305 /* Total allocated bytes. Bytes used and free.
306 used + free = total */
307 uword bytes_total, bytes_used, bytes_free;
308
309 /* Number of bytes used by mheap data structure overhead
310 (e.g. free lists, mheap header). */
311 uword bytes_overhead;
312
313 /* Amount of free space returned to operating system. */
314 uword bytes_free_reclaimed;
Dave Barachc3799992016-08-15 11:12:27 -0400315
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316 /* For malloc which puts small objects in sbrk region and
317 large objects in mmap'ed regions. */
318 uword bytes_used_sbrk;
319 uword bytes_used_mmap;
320
321 /* Max. number of bytes in this heap. */
322 uword bytes_max;
323} clib_mem_usage_t;
324
325void clib_mem_usage (clib_mem_usage_t * usage);
326
Dave Barachc3799992016-08-15 11:12:27 -0400327u8 *format_clib_mem_usage (u8 * s, va_list * args);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328
Damjan Marion01914ce2017-09-14 19:04:50 +0200329/* Allocate virtual address space. */
330always_inline void *
331clib_mem_vm_alloc (uword size)
332{
333 void *mmap_addr;
334 uword flags = MAP_PRIVATE;
335
336#ifdef MAP_ANONYMOUS
337 flags |= MAP_ANONYMOUS;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338#endif
339
Damjan Marion01914ce2017-09-14 19:04:50 +0200340 mmap_addr = mmap (0, size, PROT_READ | PROT_WRITE, flags, -1, 0);
341 if (mmap_addr == (void *) -1)
342 mmap_addr = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343
Damjan Marion01914ce2017-09-14 19:04:50 +0200344 return mmap_addr;
345}
346
347always_inline void
348clib_mem_vm_free (void *addr, uword size)
349{
350 munmap (addr, size);
351}
352
353always_inline void *
354clib_mem_vm_unmap (void *addr, uword size)
355{
356 void *mmap_addr;
357 uword flags = MAP_PRIVATE | MAP_FIXED;
358
359 /* To unmap we "map" with no protection. If we actually called
360 munmap then other callers could steal the address space. By
361 changing to PROT_NONE the kernel can free up the pages which is
362 really what we want "unmap" to mean. */
363 mmap_addr = mmap (addr, size, PROT_NONE, flags, -1, 0);
364 if (mmap_addr == (void *) -1)
365 mmap_addr = 0;
366
367 return mmap_addr;
368}
369
370always_inline void *
371clib_mem_vm_map (void *addr, uword size)
372{
373 void *mmap_addr;
Dave Barache89be4e2018-08-29 08:50:40 -0400374 uword flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
Damjan Marion01914ce2017-09-14 19:04:50 +0200375
376 mmap_addr = mmap (addr, size, (PROT_READ | PROT_WRITE), flags, -1, 0);
377 if (mmap_addr == (void *) -1)
378 mmap_addr = 0;
379
380 return mmap_addr;
381}
382
383typedef struct
384{
385#define CLIB_MEM_VM_F_SHARED (1 << 0)
386#define CLIB_MEM_VM_F_HUGETLB (1 << 1)
387#define CLIB_MEM_VM_F_NUMA_PREFER (1 << 2)
388#define CLIB_MEM_VM_F_NUMA_FORCE (1 << 3)
389#define CLIB_MEM_VM_F_HUGETLB_PREALLOC (1 << 4)
Damjan Marion7b185362018-03-04 16:41:35 +0100390#define CLIB_MEM_VM_F_LOCKED (1 << 5)
Damjan Marion01914ce2017-09-14 19:04:50 +0200391 u32 flags; /**< vm allocation flags:
392 <br> CLIB_MEM_VM_F_SHARED: request shared memory, file
Florin Corasd3e83a92018-01-16 02:40:18 -0800393 descriptor will be provided on successful allocation.
Damjan Marion01914ce2017-09-14 19:04:50 +0200394 <br> CLIB_MEM_VM_F_HUGETLB: request hugepages.
395 <br> CLIB_MEM_VM_F_NUMA_PREFER: numa_node field contains valid
396 numa node preference.
397 <br> CLIB_MEM_VM_F_NUMA_FORCE: fail if setting numa policy fails.
398 <br> CLIB_MEM_VM_F_HUGETLB_PREALLOC: pre-allocate hugepages if
399 number of available pages is not sufficient.
Damjan Marion7b185362018-03-04 16:41:35 +0100400 <br> CLIB_MEM_VM_F_LOCKED: request locked memory.
Damjan Marion01914ce2017-09-14 19:04:50 +0200401 */
402 char *name; /**< Name for memory allocation, set by caller. */
403 uword size; /**< Allocation size, set by caller. */
404 int numa_node; /**< numa node preference. Valid if CLIB_MEM_VM_F_NUMA_PREFER set. */
405 void *addr; /**< Pointer to allocated memory, set on successful allocation. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800406 int fd; /**< File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set. */
Damjan Marion01914ce2017-09-14 19:04:50 +0200407 int log2_page_size; /* Page size in log2 format, set on successful allocation. */
408 int n_pages; /* Number of pages. */
Florin Corasd3e83a92018-01-16 02:40:18 -0800409 uword requested_va; /**< Request fixed position mapping */
Damjan Marion01914ce2017-09-14 19:04:50 +0200410} clib_mem_vm_alloc_t;
411
Damjan Marion567e61d2018-10-24 17:08:26 +0200412clib_error_t *clib_mem_create_fd (char *name, int *fdp);
Damjan Marion1636b162018-10-19 12:54:42 +0200413clib_error_t *clib_mem_create_hugetlb_fd (char *name, int *fdp);
Damjan Marion01914ce2017-09-14 19:04:50 +0200414clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a);
Haiyang Tan642829d2018-10-09 19:09:45 -0700415void clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a);
Damjan Marion567e61d2018-10-24 17:08:26 +0200416u64 clib_mem_get_fd_page_size (int fd);
Damjan Marion9787f5f2018-10-24 12:56:32 +0200417uword clib_mem_get_default_hugepage_size (void);
Damjan Marion567e61d2018-10-24 17:08:26 +0200418int clib_mem_get_fd_log2_page_size (int fd);
Damjan Marion01914ce2017-09-14 19:04:50 +0200419u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages);
420
Florin Corasd3e83a92018-01-16 02:40:18 -0800421typedef struct
422{
423 uword size; /**< Map size */
424 int fd; /**< File descriptor to be mapped */
425 uword requested_va; /**< Request fixed position mapping */
426 void *addr; /**< Pointer to mapped memory, if successful */
427} clib_mem_vm_map_t;
Florin Corasd3e83a92018-01-16 02:40:18 -0800428
Florin Corasb384b542018-01-15 01:08:33 -0800429clib_error_t *clib_mem_vm_ext_map (clib_mem_vm_map_t * a);
430void clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size);
Dave Barach6a5adc32018-07-04 10:56:23 -0400431void mheap_trace (void *v, int enable);
Dave Barach8fdde3c2019-05-17 10:46:40 -0400432uword clib_mem_trace_enable_disable (uword enable);
433void clib_mem_trace (int enable);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
Dave Barachc3799992016-08-15 11:12:27 -0400435#include <vppinfra/error.h> /* clib_panic */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700436
437#endif /* _included_clib_mem_h */
Dave Barachc3799992016-08-15 11:12:27 -0400438
439/*
440 * fd.io coding-style-patch-verification: ON
441 *
442 * Local Variables:
443 * eval: (c-set-style "gnu")
444 * End:
445 */