9cc62ed759279a43ed9474f9afb178ffbe354d9f
[vpp.git] / src / vppinfra / mem.h
1 /*
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>
42 #include <unistd.h>
43 #include <sys/mman.h>
44
45 #include <vppinfra/clib.h>      /* uword, etc */
46 #include <vppinfra/clib_error.h>
47
48 #if USE_DLMALLOC == 0
49 #include <vppinfra/mheap_bootstrap.h>
50 #else
51 #include <vppinfra/dlmalloc.h>
52 #endif
53
54 #include <vppinfra/os.h>
55 #include <vppinfra/string.h>    /* memcpy, memset */
56 #include <vppinfra/valgrind.h>
57
58 #define CLIB_MAX_MHEAPS 256
59
60 /* Per CPU heaps. */
61 extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
62
63 always_inline void *
64 clib_mem_get_per_cpu_heap (void)
65 {
66   int cpu = os_get_thread_index ();
67   return clib_per_cpu_mheaps[cpu];
68 }
69
70 always_inline void *
71 clib_mem_set_per_cpu_heap (u8 * new_heap)
72 {
73   int cpu = os_get_thread_index ();
74   void *old = clib_per_cpu_mheaps[cpu];
75   clib_per_cpu_mheaps[cpu] = new_heap;
76   return old;
77 }
78
79 /* Memory allocator which may call os_out_of_memory() if it fails */
80 always_inline void *
81 clib_mem_alloc_aligned_at_offset (uword size, uword align, uword align_offset,
82                                   int os_out_of_memory_on_failure)
83 {
84   void *heap, *p;
85   uword cpu;
86
87   if (align_offset > align)
88     {
89       if (align > 0)
90         align_offset %= align;
91       else
92         align_offset = align;
93     }
94
95   cpu = os_get_thread_index ();
96   heap = clib_per_cpu_mheaps[cpu];
97
98 #if USE_DLMALLOC == 0
99   uword offset;
100   heap = mheap_get_aligned (heap, size, align, align_offset, &offset);
101   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     {
113       if (os_out_of_memory_on_failure)
114         os_out_of_memory ();
115       return 0;
116     }
117 #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 */
128 }
129
130 /* Memory allocator which calls os_out_of_memory() when it fails */
131 always_inline void *
132 clib_mem_alloc (uword size)
133 {
134   return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
135                                            /* align_offset */ 0,
136                                            /* os_out_of_memory */ 1);
137 }
138
139 always_inline void *
140 clib_mem_alloc_aligned (uword size, uword align)
141 {
142   return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
143                                            /* os_out_of_memory */ 1);
144 }
145
146 /* Memory allocator which calls os_out_of_memory() when it fails */
147 always_inline void *
148 clib_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
155 always_inline void *
156 clib_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
164 /* 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
181 always_inline uword
182 clib_mem_is_heap_object (void *p)
183 {
184 #if USE_DLMALLOC == 0
185   void *heap = clib_mem_get_per_cpu_heap ();
186   uword offset = (uword) p - (uword) heap;
187   mheap_elt_t *e, *n;
188
189   if (offset >= vec_len (heap))
190     return 0;
191
192   e = mheap_elt_at_uoffset (heap, offset);
193   n = mheap_next_elt (e);
194
195   /* Check that heap forward and reverse pointers agree. */
196   return e->n_user_data == n->prev_n_user_data;
197 #else
198   void *heap = clib_mem_get_per_cpu_heap ();
199
200   return mspace_is_heap_object (heap, p);
201 #endif /* USE_DLMALLOC */
202 }
203
204 always_inline void
205 clib_mem_free (void *p)
206 {
207   u8 *heap = clib_mem_get_per_cpu_heap ();
208
209   /* Make sure object is in the correct heap. */
210   ASSERT (clib_mem_is_heap_object (p));
211
212 #if USE_DLMALLOC == 0
213   mheap_put (heap, (u8 *) p - heap);
214 #else
215   mspace_put (heap, p);
216 #endif
217
218 #if CLIB_DEBUG > 0
219   VALGRIND_FREELIKE_BLOCK (p, 0);
220 #endif
221 }
222
223 always_inline void *
224 clib_mem_realloc (void *p, uword new_size, uword old_size)
225 {
226   /* By default use alloc, copy and free to emulate realloc. */
227   void *q = clib_mem_alloc (new_size);
228   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;
235       clib_memcpy (q, p, copy_size);
236       clib_mem_free (p);
237     }
238   return q;
239 }
240
241 always_inline uword
242 clib_mem_size (void *p)
243 {
244 #if USE_DLMALLOC == 0
245   mheap_elt_t *e = mheap_user_pointer_to_elt (p);
246   ASSERT (clib_mem_is_heap_object (p));
247   return mheap_elt_data_bytes (e);
248 #else
249   ASSERT (clib_mem_is_heap_object (p));
250   return mspace_usable_size_with_delta (p);
251 #endif
252 }
253
254 always_inline void *
255 clib_mem_get_heap (void)
256 {
257   return clib_mem_get_per_cpu_heap ();
258 }
259
260 always_inline void *
261 clib_mem_set_heap (void *heap)
262 {
263   return clib_mem_set_per_cpu_heap (heap);
264 }
265
266 void *clib_mem_init (void *heap, uword size);
267 void *clib_mem_init_thread_safe (void *memory, uword memory_size);
268
269 void clib_mem_exit (void);
270
271 uword clib_mem_get_page_size (void);
272
273 void clib_mem_validate (void);
274
275 void clib_mem_trace (int enable);
276
277 typedef struct
278 {
279   /* Total number of objects allocated. */
280   uword object_count;
281
282   /* Total allocated bytes.  Bytes used and free.
283      used + free = total */
284   uword bytes_total, bytes_used, bytes_free;
285
286   /* Number of bytes used by mheap data structure overhead
287      (e.g. free lists, mheap header). */
288   uword bytes_overhead;
289
290   /* Amount of free space returned to operating system. */
291   uword bytes_free_reclaimed;
292
293   /* For malloc which puts small objects in sbrk region and
294      large objects in mmap'ed regions. */
295   uword bytes_used_sbrk;
296   uword bytes_used_mmap;
297
298   /* Max. number of bytes in this heap. */
299   uword bytes_max;
300 } clib_mem_usage_t;
301
302 void clib_mem_usage (clib_mem_usage_t * usage);
303
304 u8 *format_clib_mem_usage (u8 * s, va_list * args);
305
306 /* Allocate virtual address space. */
307 always_inline void *
308 clib_mem_vm_alloc (uword size)
309 {
310   void *mmap_addr;
311   uword flags = MAP_PRIVATE;
312
313 #ifdef MAP_ANONYMOUS
314   flags |= MAP_ANONYMOUS;
315 #endif
316
317   mmap_addr = mmap (0, 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
324 always_inline void
325 clib_mem_vm_free (void *addr, uword size)
326 {
327   munmap (addr, size);
328 }
329
330 always_inline void *
331 clib_mem_vm_unmap (void *addr, uword size)
332 {
333   void *mmap_addr;
334   uword flags = MAP_PRIVATE | MAP_FIXED;
335
336   /* To unmap we "map" with no protection.  If we actually called
337      munmap then other callers could steal the address space.  By
338      changing to PROT_NONE the kernel can free up the pages which is
339      really what we want "unmap" to mean. */
340   mmap_addr = mmap (addr, size, PROT_NONE, flags, -1, 0);
341   if (mmap_addr == (void *) -1)
342     mmap_addr = 0;
343
344   return mmap_addr;
345 }
346
347 always_inline void *
348 clib_mem_vm_map (void *addr, uword size)
349 {
350   void *mmap_addr;
351   uword flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
352
353   mmap_addr = mmap (addr, size, (PROT_READ | PROT_WRITE), flags, -1, 0);
354   if (mmap_addr == (void *) -1)
355     mmap_addr = 0;
356
357   return mmap_addr;
358 }
359
360 typedef struct
361 {
362 #define CLIB_MEM_VM_F_SHARED (1 << 0)
363 #define CLIB_MEM_VM_F_HUGETLB (1 << 1)
364 #define CLIB_MEM_VM_F_NUMA_PREFER (1 << 2)
365 #define CLIB_MEM_VM_F_NUMA_FORCE (1 << 3)
366 #define CLIB_MEM_VM_F_HUGETLB_PREALLOC (1 << 4)
367 #define CLIB_MEM_VM_F_LOCKED (1 << 5)
368   u32 flags; /**< vm allocation flags:
369                 <br> CLIB_MEM_VM_F_SHARED: request shared memory, file
370                 descriptor will be provided on successful allocation.
371                 <br> CLIB_MEM_VM_F_HUGETLB: request hugepages.
372                 <br> CLIB_MEM_VM_F_NUMA_PREFER: numa_node field contains valid
373                 numa node preference.
374                 <br> CLIB_MEM_VM_F_NUMA_FORCE: fail if setting numa policy fails.
375                 <br> CLIB_MEM_VM_F_HUGETLB_PREALLOC: pre-allocate hugepages if
376                 number of available pages is not sufficient.
377                 <br> CLIB_MEM_VM_F_LOCKED: request locked memory.
378              */
379   char *name; /**< Name for memory allocation, set by caller. */
380   uword size; /**< Allocation size, set by caller. */
381   int numa_node; /**< numa node preference. Valid if CLIB_MEM_VM_F_NUMA_PREFER set. */
382   void *addr; /**< Pointer to allocated memory, set on successful allocation. */
383   int fd; /**< File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set. */
384   int log2_page_size;           /* Page size in log2 format, set on successful allocation. */
385   int n_pages;                  /* Number of pages. */
386   uword requested_va;           /**< Request fixed position mapping */
387 } clib_mem_vm_alloc_t;
388
389 clib_error_t *clib_mem_create_hugetlb_fd (char *name, int *fdp);
390 clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a);
391 void clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a);
392 u64 clib_mem_vm_get_page_size (int fd);
393 int clib_mem_vm_get_log2_page_size (int fd);
394 u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages);
395
396 typedef struct
397 {
398   uword size;           /**< Map size */
399   int fd;               /**< File descriptor to be mapped */
400   uword requested_va;   /**< Request fixed position mapping */
401   void *addr;           /**< Pointer to mapped memory, if successful */
402 } clib_mem_vm_map_t;
403
404 clib_error_t *clib_mem_vm_ext_map (clib_mem_vm_map_t * a);
405 void clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size);
406 void mheap_trace (void *v, int enable);
407
408 #include <vppinfra/error.h>     /* clib_panic */
409
410 #endif /* _included_clib_mem_h */
411
412 /*
413  * fd.io coding-style-patch-verification: ON
414  *
415  * Local Variables:
416  * eval: (c-set-style "gnu")
417  * End:
418  */