build: remove valgrind leftovers
[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, clib_memset */
56
57 #define CLIB_MAX_MHEAPS 256
58
59 /* Per CPU heaps. */
60 extern void *clib_per_cpu_mheaps[CLIB_MAX_MHEAPS];
61
62 always_inline void
63 clib_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
83 always_inline void *
84 clib_mem_get_per_cpu_heap (void)
85 {
86   int cpu = os_get_thread_index ();
87   return clib_per_cpu_mheaps[cpu];
88 }
89
90 always_inline void *
91 clib_mem_set_per_cpu_heap (u8 * new_heap)
92 {
93   int cpu = os_get_thread_index ();
94   void *old = clib_per_cpu_mheaps[cpu];
95   clib_per_cpu_mheaps[cpu] = new_heap;
96   return old;
97 }
98
99 /* Memory allocator which may call os_out_of_memory() if it fails */
100 always_inline void *
101 clib_mem_alloc_aligned_at_offset (uword size, uword align, uword align_offset,
102                                   int os_out_of_memory_on_failure)
103 {
104   void *heap, *p;
105   uword cpu;
106
107   if (align_offset > align)
108     {
109       if (align > 0)
110         align_offset %= align;
111       else
112         align_offset = align;
113     }
114
115   cpu = os_get_thread_index ();
116   heap = clib_per_cpu_mheaps[cpu];
117
118 #if USE_DLMALLOC == 0
119   uword offset;
120   heap = mheap_get_aligned (heap, size, align, align_offset, &offset);
121   clib_per_cpu_mheaps[cpu] = heap;
122
123   if (offset != ~0)
124     {
125       p = heap + offset;
126       return p;
127     }
128   else
129     {
130       if (os_out_of_memory_on_failure)
131         os_out_of_memory ();
132       return 0;
133     }
134 #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 */
145 }
146
147 /* Memory allocator which calls os_out_of_memory() when it fails */
148 always_inline void *
149 clib_mem_alloc (uword size)
150 {
151   return clib_mem_alloc_aligned_at_offset (size, /* align */ 1,
152                                            /* align_offset */ 0,
153                                            /* os_out_of_memory */ 1);
154 }
155
156 always_inline void *
157 clib_mem_alloc_aligned (uword size, uword align)
158 {
159   return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0,
160                                            /* os_out_of_memory */ 1);
161 }
162
163 /* Memory allocator which calls os_out_of_memory() when it fails */
164 always_inline void *
165 clib_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
172 always_inline void *
173 clib_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
181 /* 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
198 always_inline uword
199 clib_mem_is_heap_object (void *p)
200 {
201 #if USE_DLMALLOC == 0
202   void *heap = clib_mem_get_per_cpu_heap ();
203   uword offset = (uword) p - (uword) heap;
204   mheap_elt_t *e, *n;
205
206   if (offset >= vec_len (heap))
207     return 0;
208
209   e = mheap_elt_at_uoffset (heap, offset);
210   n = mheap_next_elt (e);
211
212   /* Check that heap forward and reverse pointers agree. */
213   return e->n_user_data == n->prev_n_user_data;
214 #else
215   void *heap = clib_mem_get_per_cpu_heap ();
216
217   return mspace_is_heap_object (heap, p);
218 #endif /* USE_DLMALLOC */
219 }
220
221 always_inline void
222 clib_mem_free (void *p)
223 {
224   u8 *heap = clib_mem_get_per_cpu_heap ();
225
226   /* Make sure object is in the correct heap. */
227   ASSERT (clib_mem_is_heap_object (p));
228
229 #if USE_DLMALLOC == 0
230   mheap_put (heap, (u8 *) p - heap);
231 #else
232   mspace_put (heap, p);
233 #endif
234 }
235
236 always_inline void *
237 clib_mem_realloc (void *p, uword new_size, uword old_size)
238 {
239   /* By default use alloc, copy and free to emulate realloc. */
240   void *q = clib_mem_alloc (new_size);
241   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;
248       clib_memcpy_fast (q, p, copy_size);
249       clib_mem_free (p);
250     }
251   return q;
252 }
253
254 always_inline uword
255 clib_mem_size (void *p)
256 {
257 #if USE_DLMALLOC == 0
258   mheap_elt_t *e = mheap_user_pointer_to_elt (p);
259   ASSERT (clib_mem_is_heap_object (p));
260   return mheap_elt_data_bytes (e);
261 #else
262   ASSERT (clib_mem_is_heap_object (p));
263   return mspace_usable_size_with_delta (p);
264 #endif
265 }
266
267 always_inline void
268 clib_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
275 always_inline void *
276 clib_mem_get_heap (void)
277 {
278   return clib_mem_get_per_cpu_heap ();
279 }
280
281 always_inline void *
282 clib_mem_set_heap (void *heap)
283 {
284   return clib_mem_set_per_cpu_heap (heap);
285 }
286
287 void *clib_mem_init (void *heap, uword size);
288 void *clib_mem_init_thread_safe (void *memory, uword memory_size);
289
290 void clib_mem_exit (void);
291
292 uword clib_mem_get_page_size (void);
293
294 void clib_mem_validate (void);
295
296 void clib_mem_trace (int enable);
297
298 int clib_mem_is_traced (void);
299
300 typedef struct
301 {
302   /* 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;
315
316   /* 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
325 void clib_mem_usage (clib_mem_usage_t * usage);
326
327 u8 *format_clib_mem_usage (u8 * s, va_list * args);
328
329 /* Allocate virtual address space. */
330 always_inline void *
331 clib_mem_vm_alloc (uword size)
332 {
333   void *mmap_addr;
334   uword flags = MAP_PRIVATE;
335
336 #ifdef MAP_ANONYMOUS
337   flags |= MAP_ANONYMOUS;
338 #endif
339
340   mmap_addr = mmap (0, size, PROT_READ | PROT_WRITE, 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_free (void *addr, uword size)
349 {
350   munmap (addr, size);
351 }
352
353 always_inline void *
354 clib_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
370 always_inline void *
371 clib_mem_vm_map (void *addr, uword size)
372 {
373   void *mmap_addr;
374   uword flags = MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS;
375
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
383 typedef 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)
390 #define CLIB_MEM_VM_F_LOCKED (1 << 5)
391   u32 flags; /**< vm allocation flags:
392                 <br> CLIB_MEM_VM_F_SHARED: request shared memory, file
393                 descriptor will be provided on successful allocation.
394                 <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.
400                 <br> CLIB_MEM_VM_F_LOCKED: request locked memory.
401              */
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. */
406   int fd; /**< File descriptor, set on successful allocation if CLIB_MEM_VM_F_SHARED is set. */
407   int log2_page_size;           /* Page size in log2 format, set on successful allocation. */
408   int n_pages;                  /* Number of pages. */
409   uword requested_va;           /**< Request fixed position mapping */
410 } clib_mem_vm_alloc_t;
411
412 clib_error_t *clib_mem_create_fd (char *name, int *fdp);
413 clib_error_t *clib_mem_create_hugetlb_fd (char *name, int *fdp);
414 clib_error_t *clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a);
415 void clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a);
416 u64 clib_mem_get_fd_page_size (int fd);
417 uword clib_mem_get_default_hugepage_size (void);
418 int clib_mem_get_fd_log2_page_size (int fd);
419 u64 *clib_mem_vm_get_paddr (void *mem, int log2_page_size, int n_pages);
420
421 typedef 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;
428
429 clib_error_t *clib_mem_vm_ext_map (clib_mem_vm_map_t * a);
430 void clib_mem_vm_randomize_va (uword * requested_va, u32 log2_page_size);
431 void mheap_trace (void *v, int enable);
432 uword clib_mem_trace_enable_disable (uword enable);
433 void clib_mem_trace (int enable);
434
435 #include <vppinfra/error.h>     /* clib_panic */
436
437 #endif /* _included_clib_mem_h */
438
439 /*
440  * fd.io coding-style-patch-verification: ON
441  *
442  * Local Variables:
443  * eval: (c-set-style "gnu")
444  * End:
445  */