udp: fix csum computation when offload disabled
[vpp.git] / src / vppinfra / mem_dlmalloc.c
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 #include <vppinfra/format.h>
17 #include <vppinfra/dlmalloc.h>
18 #include <vppinfra/os.h>
19 #include <vppinfra/lock.h>
20 #include <vppinfra/hash.h>
21 #include <vppinfra/elf_clib.h>
22
23 typedef struct
24 {
25   /* Address of callers: outer first, inner last. */
26   uword callers[12];
27
28   /* Count of allocations with this traceback. */
29   u32 n_allocations;
30
31   /* Count of bytes allocated with this traceback. */
32   u32 n_bytes;
33
34   /* Offset of this item */
35   uword offset;
36 } mheap_trace_t;
37
38 typedef struct
39 {
40   clib_spinlock_t lock;
41
42   mheap_trace_t *traces;
43
44   /* Indices of free traces. */
45   u32 *trace_free_list;
46
47   /* Hash table mapping callers to trace index. */
48   uword *trace_by_callers;
49
50   /* Hash table mapping mheap offset to trace index. */
51   uword *trace_index_by_offset;
52
53   /* So we can easily shut off current segment trace, if any */
54   const clib_mem_heap_t *current_traced_mheap;
55
56 } mheap_trace_main_t;
57
58 mheap_trace_main_t mheap_trace_main;
59
60 static __thread int mheap_trace_thread_disable;
61
62 static void
63 mheap_get_trace_internal (const clib_mem_heap_t *heap, uword offset,
64                           uword size)
65 {
66   mheap_trace_main_t *tm = &mheap_trace_main;
67   mheap_trace_t *t;
68   uword i, n_callers, trace_index, *p;
69   mheap_trace_t trace;
70
71   if (heap != tm->current_traced_mheap || mheap_trace_thread_disable)
72     return;
73
74   /* Spurious Coverity warnings be gone. */
75   clib_memset (&trace, 0, sizeof (trace));
76
77   clib_spinlock_lock (&tm->lock);
78
79   /* heap could have changed while we were waiting on the lock */
80   if (heap != tm->current_traced_mheap)
81     goto out;
82
83   /* Turn off tracing for this thread to avoid embarrassment... */
84   mheap_trace_thread_disable = 1;
85
86   /* Skip our frame and mspace_get_aligned's frame */
87   n_callers = clib_backtrace (trace.callers, ARRAY_LEN (trace.callers), 2);
88   if (n_callers == 0)
89     goto out;
90
91   if (!tm->trace_by_callers)
92     tm->trace_by_callers =
93       hash_create_shmem (0, sizeof (trace.callers), sizeof (uword));
94
95   p = hash_get_mem (tm->trace_by_callers, &trace.callers);
96   if (p)
97     {
98       trace_index = p[0];
99       t = tm->traces + trace_index;
100     }
101   else
102     {
103       i = vec_len (tm->trace_free_list);
104       if (i > 0)
105         {
106           trace_index = tm->trace_free_list[i - 1];
107           vec_set_len (tm->trace_free_list, i - 1);
108         }
109       else
110         {
111           mheap_trace_t *old_start = tm->traces;
112           mheap_trace_t *old_end = vec_end (tm->traces);
113
114           vec_add2 (tm->traces, t, 1);
115
116           if (tm->traces != old_start)
117             {
118               hash_pair_t *p;
119               mheap_trace_t *q;
120             hash_foreach_pair (p, tm->trace_by_callers,
121             ({
122               q = uword_to_pointer (p->key, mheap_trace_t *);
123               ASSERT (q >= old_start && q < old_end);
124               p->key = pointer_to_uword (tm->traces + (q - old_start));
125             }));
126             }
127           trace_index = t - tm->traces;
128         }
129
130       t = tm->traces + trace_index;
131       t[0] = trace;
132       t->n_allocations = 0;
133       t->n_bytes = 0;
134       hash_set_mem (tm->trace_by_callers, t->callers, trace_index);
135     }
136
137   t->n_allocations += 1;
138   t->n_bytes += size;
139   t->offset = offset;           /* keep a sample to autopsy */
140   hash_set (tm->trace_index_by_offset, offset, t - tm->traces);
141
142 out:
143   mheap_trace_thread_disable = 0;
144   clib_spinlock_unlock (&tm->lock);
145 }
146
147 static void
148 mheap_put_trace_internal (const clib_mem_heap_t *heap, uword offset,
149                           uword size)
150 {
151   mheap_trace_t *t;
152   uword trace_index, *p;
153   mheap_trace_main_t *tm = &mheap_trace_main;
154
155   if (heap != tm->current_traced_mheap || mheap_trace_thread_disable)
156     return;
157
158   clib_spinlock_lock (&tm->lock);
159
160   /* heap could have changed while we were waiting on the lock */
161   if (heap != tm->current_traced_mheap)
162     goto out;
163
164   /* Turn off tracing for this thread for a moment */
165   mheap_trace_thread_disable = 1;
166
167   p = hash_get (tm->trace_index_by_offset, offset);
168   if (!p)
169     goto out;
170
171   trace_index = p[0];
172   hash_unset (tm->trace_index_by_offset, offset);
173   ASSERT (trace_index < vec_len (tm->traces));
174
175   t = tm->traces + trace_index;
176   ASSERT (t->n_allocations > 0);
177   ASSERT (t->n_bytes >= size);
178   t->n_allocations -= 1;
179   t->n_bytes -= size;
180   if (t->n_allocations == 0)
181     {
182       hash_unset_mem (tm->trace_by_callers, t->callers);
183       vec_add1 (tm->trace_free_list, trace_index);
184       clib_memset (t, 0, sizeof (t[0]));
185     }
186
187 out:
188   mheap_trace_thread_disable = 0;
189   clib_spinlock_unlock (&tm->lock);
190 }
191
192 void
193 mheap_get_trace (uword offset, uword size)
194 {
195   mheap_get_trace_internal (clib_mem_get_heap (), offset, size);
196 }
197
198 void
199 mheap_put_trace (uword offset, uword size)
200 {
201   mheap_put_trace_internal (clib_mem_get_heap (), offset, size);
202 }
203
204 always_inline void
205 mheap_trace_main_free (mheap_trace_main_t * tm)
206 {
207   CLIB_SPINLOCK_ASSERT_LOCKED (&tm->lock);
208   tm->current_traced_mheap = 0;
209   vec_free (tm->traces);
210   vec_free (tm->trace_free_list);
211   hash_free (tm->trace_by_callers);
212   hash_free (tm->trace_index_by_offset);
213   mheap_trace_thread_disable = 0;
214 }
215
216 static clib_mem_heap_t *
217 clib_mem_create_heap_internal (void *base, uword size,
218                                clib_mem_page_sz_t log2_page_sz, int is_locked,
219                                char *name)
220 {
221   clib_mem_heap_t *h;
222   u8 flags = 0;
223   int sz = sizeof (clib_mem_heap_t);
224
225   if (base == 0)
226     {
227       log2_page_sz = clib_mem_log2_page_size_validate (log2_page_sz);
228       size = round_pow2 (size, clib_mem_page_bytes (log2_page_sz));
229       base = clib_mem_vm_map_internal (0, log2_page_sz, size, -1, 0,
230                                        "main heap");
231
232       if (base == CLIB_MEM_VM_MAP_FAILED)
233         return 0;
234
235       flags = CLIB_MEM_HEAP_F_UNMAP_ON_DESTROY;
236     }
237   else
238     log2_page_sz = CLIB_MEM_PAGE_SZ_UNKNOWN;
239
240   if (is_locked)
241     flags |= CLIB_MEM_HEAP_F_LOCKED;
242
243   h = base;
244   h->base = base;
245   h->size = size;
246   h->log2_page_sz = log2_page_sz;
247   h->flags = flags;
248   sz = strlen (name);
249   strcpy (h->name, name);
250   sz = round_pow2 (sz + sizeof (clib_mem_heap_t), 16);
251   h->mspace = create_mspace_with_base (base + sz, size - sz, is_locked);
252
253   mspace_disable_expand (h->mspace);
254
255   clib_mem_poison (mspace_least_addr (h->mspace),
256                    mspace_footprint (h->mspace));
257
258   return h;
259 }
260
261 /* Initialize CLIB heap based on memory/size given by user.
262    Set memory to 0 and CLIB will try to allocate its own heap. */
263 static void *
264 clib_mem_init_internal (void *base, uword size,
265                         clib_mem_page_sz_t log2_page_sz)
266 {
267   clib_mem_heap_t *h;
268
269   clib_mem_main_init ();
270
271   h = clib_mem_create_heap_internal (base, size, log2_page_sz,
272                                      1 /*is_locked */ , "main heap");
273
274   clib_mem_set_heap (h);
275
276   if (mheap_trace_main.lock == 0)
277     {
278       /* clib_spinlock_init() dynamically allocates the spinlock in the current
279        * per-cpu heap, but it is used for all traces accross all heaps and
280        * hence we can't really allocate it in the current per-cpu heap as it
281        * could be destroyed later */
282       static struct clib_spinlock_s mheap_trace_main_lock = {};
283       mheap_trace_main.lock = &mheap_trace_main_lock;
284     }
285
286   return h;
287 }
288
289 __clib_export void *
290 clib_mem_init (void *memory, uword memory_size)
291 {
292   return clib_mem_init_internal (memory, memory_size,
293                                  CLIB_MEM_PAGE_SZ_DEFAULT);
294 }
295
296 __clib_export void *
297 clib_mem_init_with_page_size (uword memory_size,
298                               clib_mem_page_sz_t log2_page_sz)
299 {
300   return clib_mem_init_internal (0, memory_size, log2_page_sz);
301 }
302
303 __clib_export void *
304 clib_mem_init_thread_safe (void *memory, uword memory_size)
305 {
306   return clib_mem_init_internal (memory, memory_size,
307                                  CLIB_MEM_PAGE_SZ_DEFAULT);
308 }
309
310 __clib_export void
311 clib_mem_destroy (void)
312 {
313   mheap_trace_main_t *tm = &mheap_trace_main;
314   clib_mem_heap_t *heap = clib_mem_get_heap ();
315
316   if (heap->mspace == tm->current_traced_mheap)
317     mheap_trace (heap, 0);
318
319   destroy_mspace (heap->mspace);
320   clib_mem_vm_unmap (heap);
321 }
322
323 __clib_export u8 *
324 format_clib_mem_usage (u8 *s, va_list *va)
325 {
326   int verbose = va_arg (*va, int);
327   return format (s, "$$$$ heap at %llx verbose %d", clib_mem_get_heap (),
328                  verbose);
329 }
330
331 /*
332  * Magic decoder ring for mallinfo stats (ala dlmalloc):
333  *
334  * size_t arena;     / * Non-mmapped space allocated (bytes) * /
335  * size_t ordblks;   / * Number of free chunks * /
336  * size_t smblks;    / * Number of free fastbin blocks * /
337  * size_t hblks;     / * Number of mmapped regions * /
338  * size_t hblkhd;    / * Space allocated in mmapped regions (bytes) * /
339  * size_t usmblks;   / * Maximum total allocated space (bytes) * /
340  * size_t fsmblks;   / * Space in freed fastbin blocks (bytes) * /
341  * size_t uordblks;  / * Total allocated space (bytes) * /
342  * size_t fordblks;  / * Total free space (bytes) * /
343  * size_t keepcost;  / * Top-most, releasable space (bytes) * /
344  *
345  */
346
347 u8 *
348 format_msize (u8 * s, va_list * va)
349 {
350   uword a = va_arg (*va, uword);
351
352   if (a >= 1ULL << 30)
353     s = format (s, "%.2fG", (((f64) a) / ((f64) (1ULL << 30))));
354   else if (a >= 1ULL << 20)
355     s = format (s, "%.2fM", (((f64) a) / ((f64) (1ULL << 20))));
356   else if (a >= 1ULL << 10)
357     s = format (s, "%.2fK", (((f64) a) / ((f64) (1ULL << 10))));
358   else
359     s = format (s, "%lld", a);
360   return s;
361 }
362
363 static int
364 mheap_trace_sort (const void *_t1, const void *_t2)
365 {
366   const mheap_trace_t *t1 = _t1;
367   const mheap_trace_t *t2 = _t2;
368   word cmp;
369
370   cmp = (word) t2->n_bytes - (word) t1->n_bytes;
371   if (!cmp)
372     cmp = (word) t2->n_allocations - (word) t1->n_allocations;
373   return cmp;
374 }
375
376 u8 *
377 format_mheap_trace (u8 * s, va_list * va)
378 {
379   mheap_trace_main_t *tm = va_arg (*va, mheap_trace_main_t *);
380   int verbose = va_arg (*va, int);
381   int have_traces = 0;
382   int i;
383   int n = 0;
384
385   clib_spinlock_lock (&tm->lock);
386   if (vec_len (tm->traces) > 0 &&
387       clib_mem_get_heap () == tm->current_traced_mheap)
388     {
389       have_traces = 1;
390
391       /* Make a copy of traces since we'll be sorting them. */
392       mheap_trace_t *t, *traces_copy;
393       u32 indent, total_objects_traced;
394
395       traces_copy = vec_dup (tm->traces);
396
397       qsort (traces_copy, vec_len (traces_copy), sizeof (traces_copy[0]),
398              mheap_trace_sort);
399
400       total_objects_traced = 0;
401       s = format (s, "\n");
402       vec_foreach (t, traces_copy)
403       {
404         /* Skip over free elements. */
405         if (t->n_allocations == 0)
406           continue;
407
408         total_objects_traced += t->n_allocations;
409
410         /* When not verbose only report the 50 biggest allocations */
411         if (!verbose && n >= 50)
412           continue;
413         n++;
414
415         if (t == traces_copy)
416           s = format (s, "%=9s%=9s %=10s Traceback\n", "Bytes", "Count",
417                       "Sample");
418         s = format (s, "%9d%9d %p", t->n_bytes, t->n_allocations, t->offset);
419         indent = format_get_indent (s);
420         for (i = 0; i < ARRAY_LEN (t->callers) && t->callers[i]; i++)
421           {
422             if (i > 0)
423               s = format (s, "%U", format_white_space, indent);
424 #if defined(CLIB_UNIX) && !defined(__APPLE__)
425             /* $$$$ does this actually work? */
426             s =
427               format (s, " %U\n", format_clib_elf_symbol_with_address,
428                       t->callers[i]);
429 #else
430             s = format (s, " %p\n", t->callers[i]);
431 #endif
432           }
433       }
434
435       s = format (s, "%d total traced objects\n", total_objects_traced);
436
437       vec_free (traces_copy);
438     }
439   clib_spinlock_unlock (&tm->lock);
440   if (have_traces == 0)
441     s = format (s, "no traced allocations\n");
442
443   return s;
444 }
445
446 __clib_export u8 *
447 format_clib_mem_heap (u8 * s, va_list * va)
448 {
449   clib_mem_heap_t *heap = va_arg (*va, clib_mem_heap_t *);
450   int verbose = va_arg (*va, int);
451   struct dlmallinfo mi;
452   mheap_trace_main_t *tm = &mheap_trace_main;
453   u32 indent = format_get_indent (s) + 2;
454
455   if (heap == 0)
456     heap = clib_mem_get_heap ();
457
458   mi = mspace_mallinfo (heap->mspace);
459
460   s = format (s, "base %p, size %U",
461               heap->base, format_memory_size, heap->size);
462
463 #define _(i,v,str) \
464   if (heap->flags & CLIB_MEM_HEAP_F_##v) s = format (s, ", %s", str);
465   foreach_clib_mem_heap_flag;
466 #undef _
467
468   s = format (s, ", name '%s'", heap->name);
469
470   if (heap->log2_page_sz != CLIB_MEM_PAGE_SZ_UNKNOWN)
471     {
472       clib_mem_page_stats_t stats;
473       clib_mem_get_page_stats (heap->base, heap->log2_page_sz,
474                                heap->size >> heap->log2_page_sz, &stats);
475       s = format (s, "\n%U%U", format_white_space, indent,
476                   format_clib_mem_page_stats, &stats);
477     }
478
479   s = format (s, "\n%Utotal: %U, used: %U, free: %U, trimmable: %U",
480               format_white_space, indent,
481               format_msize, mi.arena,
482               format_msize, mi.uordblks,
483               format_msize, mi.fordblks, format_msize, mi.keepcost);
484   if (verbose > 0)
485     {
486       s = format (s, "\n%Ufree chunks %llu free fastbin blks %llu",
487                   format_white_space, indent + 2, mi.ordblks, mi.smblks);
488       s = format (s, "\n%Umax total allocated %U",
489                   format_white_space, indent + 2, format_msize, mi.usmblks);
490     }
491
492   if (heap->flags & CLIB_MEM_HEAP_F_TRACED)
493     s = format (s, "\n%U", format_mheap_trace, tm, verbose);
494   return s;
495 }
496
497 __clib_export __clib_flatten void
498 clib_mem_get_heap_usage (clib_mem_heap_t *heap, clib_mem_usage_t *usage)
499 {
500   struct dlmallinfo mi = mspace_mallinfo (heap->mspace);
501
502   usage->bytes_total = mi.arena; /* non-mmapped space allocated from system */
503   usage->bytes_used = mi.uordblks;          /* total allocated space */
504   usage->bytes_free = mi.fordblks;          /* total free space */
505   usage->bytes_used_mmap = mi.hblkhd;       /* space in mmapped regions */
506   usage->bytes_max = mi.usmblks;            /* maximum total allocated space */
507   usage->bytes_free_reclaimed = mi.ordblks; /* number of free chunks */
508   usage->bytes_overhead = mi.keepcost; /* releasable (via malloc_trim) space */
509
510   /* Not supported */
511   usage->bytes_used_sbrk = 0;
512   usage->object_count = 0;
513 }
514
515 /* Call serial number for debugger breakpoints. */
516 uword clib_mem_validate_serial = 0;
517
518 __clib_export void
519 mheap_trace (clib_mem_heap_t * h, int enable)
520 {
521   mheap_trace_main_t *tm = &mheap_trace_main;
522
523   clib_spinlock_lock (&tm->lock);
524
525   if (tm->current_traced_mheap != 0 && tm->current_traced_mheap != h)
526     {
527       clib_warning ("tracing already enabled for another heap, ignoring");
528       goto out;
529     }
530
531   if (enable)
532     {
533       h->flags |= CLIB_MEM_HEAP_F_TRACED;
534       tm->current_traced_mheap = h;
535     }
536   else
537     {
538       h->flags &= ~CLIB_MEM_HEAP_F_TRACED;
539       mheap_trace_main_free (&mheap_trace_main);
540     }
541
542 out:
543   clib_spinlock_unlock (&tm->lock);
544 }
545
546 __clib_export void
547 clib_mem_trace (int enable)
548 {
549   void *current_heap = clib_mem_get_heap ();
550   mheap_trace (current_heap, enable);
551 }
552
553 int
554 clib_mem_is_traced (void)
555 {
556   clib_mem_heap_t *h = clib_mem_get_heap ();
557   return (h->flags &= CLIB_MEM_HEAP_F_TRACED) != 0;
558 }
559
560 __clib_export uword
561 clib_mem_trace_enable_disable (uword enable)
562 {
563   uword rv = !mheap_trace_thread_disable;
564   mheap_trace_thread_disable = !enable;
565   return rv;
566 }
567
568 __clib_export clib_mem_heap_t *
569 clib_mem_create_heap (void *base, uword size, int is_locked, char *fmt, ...)
570 {
571   clib_mem_page_sz_t log2_page_sz = clib_mem_get_log2_page_size ();
572   clib_mem_heap_t *h;
573   char *name;
574   u8 *s = 0;
575
576   if (fmt == 0)
577     {
578       name = "";
579     }
580   else if (strchr (fmt, '%'))
581     {
582       va_list va;
583       va_start (va, fmt);
584       s = va_format (0, fmt, &va);
585       vec_add1 (s, 0);
586       va_end (va);
587       name = (char *) s;
588     }
589   else
590     name = fmt;
591
592   h = clib_mem_create_heap_internal (base, size, log2_page_sz, is_locked,
593                                      name);
594   vec_free (s);
595   return h;
596 }
597
598 __clib_export void
599 clib_mem_destroy_heap (clib_mem_heap_t * h)
600 {
601   mheap_trace_main_t *tm = &mheap_trace_main;
602
603   if (h->mspace == tm->current_traced_mheap)
604     mheap_trace (h, 0);
605
606   destroy_mspace (h->mspace);
607   if (h->flags & CLIB_MEM_HEAP_F_UNMAP_ON_DESTROY)
608     clib_mem_vm_unmap (h->base);
609 }
610
611 __clib_export __clib_flatten uword
612 clib_mem_get_heap_free_space (clib_mem_heap_t *h)
613 {
614   struct dlmallinfo dlminfo = mspace_mallinfo (h->mspace);
615   return dlminfo.fordblks;
616 }
617
618 __clib_export __clib_flatten void *
619 clib_mem_get_heap_base (clib_mem_heap_t *h)
620 {
621   return h->base;
622 }
623
624 __clib_export __clib_flatten uword
625 clib_mem_get_heap_size (clib_mem_heap_t *heap)
626 {
627   return heap->size;
628 }
629
630 /* Memory allocator which may call os_out_of_memory() if it fails */
631 static inline void *
632 clib_mem_heap_alloc_inline (void *heap, uword size, uword align,
633                             int os_out_of_memory_on_failure)
634 {
635   clib_mem_heap_t *h = heap ? heap : clib_mem_get_per_cpu_heap ();
636   void *p;
637
638   align = clib_max (CLIB_MEM_MIN_ALIGN, align);
639
640   p = mspace_memalign (h->mspace, align, size);
641
642   if (PREDICT_FALSE (0 == p))
643     {
644       if (os_out_of_memory_on_failure)
645         os_out_of_memory ();
646       return 0;
647     }
648
649   if (PREDICT_FALSE (h->flags & CLIB_MEM_HEAP_F_TRACED))
650     mheap_get_trace_internal (h, pointer_to_uword (p), clib_mem_size (p));
651
652   clib_mem_unpoison (p, size);
653   return p;
654 }
655
656 /* Memory allocator which calls os_out_of_memory() when it fails */
657 __clib_export __clib_flatten void *
658 clib_mem_alloc (uword size)
659 {
660   return clib_mem_heap_alloc_inline (0, size, CLIB_MEM_MIN_ALIGN,
661                                      /* os_out_of_memory */ 1);
662 }
663
664 __clib_export __clib_flatten void *
665 clib_mem_alloc_aligned (uword size, uword align)
666 {
667   return clib_mem_heap_alloc_inline (0, size, align,
668                                      /* os_out_of_memory */ 1);
669 }
670
671 /* Memory allocator which calls os_out_of_memory() when it fails */
672 __clib_export __clib_flatten void *
673 clib_mem_alloc_or_null (uword size)
674 {
675   return clib_mem_heap_alloc_inline (0, size, CLIB_MEM_MIN_ALIGN,
676                                      /* os_out_of_memory */ 0);
677 }
678
679 __clib_export __clib_flatten void *
680 clib_mem_alloc_aligned_or_null (uword size, uword align)
681 {
682   return clib_mem_heap_alloc_inline (0, size, align,
683                                      /* os_out_of_memory */ 0);
684 }
685
686 __clib_export __clib_flatten void *
687 clib_mem_heap_alloc (void *heap, uword size)
688 {
689   return clib_mem_heap_alloc_inline (heap, size, CLIB_MEM_MIN_ALIGN,
690                                      /* os_out_of_memory */ 1);
691 }
692
693 __clib_export __clib_flatten void *
694 clib_mem_heap_alloc_aligned (void *heap, uword size, uword align)
695 {
696   return clib_mem_heap_alloc_inline (heap, size, align,
697                                      /* os_out_of_memory */ 1);
698 }
699
700 __clib_export __clib_flatten void *
701 clib_mem_heap_alloc_or_null (void *heap, uword size)
702 {
703   return clib_mem_heap_alloc_inline (heap, size, CLIB_MEM_MIN_ALIGN,
704                                      /* os_out_of_memory */ 0);
705 }
706
707 __clib_export __clib_flatten void *
708 clib_mem_heap_alloc_aligned_or_null (void *heap, uword size, uword align)
709 {
710   return clib_mem_heap_alloc_inline (heap, size, align,
711                                      /* os_out_of_memory */ 0);
712 }
713
714 __clib_export __clib_flatten void *
715 clib_mem_heap_realloc_aligned (void *heap, void *p, uword new_size,
716                                uword align)
717 {
718   uword old_alloc_size;
719   clib_mem_heap_t *h = heap ? heap : clib_mem_get_per_cpu_heap ();
720   void *new;
721
722   ASSERT (count_set_bits (align) == 1);
723
724   old_alloc_size = p ? mspace_usable_size (p) : 0;
725
726   if (new_size == old_alloc_size)
727     return p;
728
729   if (p && pointer_is_aligned (p, align) &&
730       mspace_realloc_in_place (h->mspace, p, new_size))
731     {
732       clib_mem_unpoison (p, new_size);
733       if (PREDICT_FALSE (h->flags & CLIB_MEM_HEAP_F_TRACED))
734         {
735           mheap_put_trace_internal (h, pointer_to_uword (p), old_alloc_size);
736           mheap_get_trace_internal (h, pointer_to_uword (p),
737                                     clib_mem_size (p));
738         }
739     }
740   else
741     {
742       new = clib_mem_heap_alloc_inline (h, new_size, align, 1);
743
744       clib_mem_unpoison (new, new_size);
745       if (old_alloc_size)
746         {
747           clib_mem_unpoison (p, old_alloc_size);
748           clib_memcpy_fast (new, p, clib_min (new_size, old_alloc_size));
749           clib_mem_heap_free (h, p);
750         }
751       p = new;
752     }
753
754   return p;
755 }
756
757 __clib_export __clib_flatten void *
758 clib_mem_heap_realloc (void *heap, void *p, uword new_size)
759 {
760   return clib_mem_heap_realloc_aligned (heap, p, new_size, CLIB_MEM_MIN_ALIGN);
761 }
762
763 __clib_export __clib_flatten void *
764 clib_mem_realloc_aligned (void *p, uword new_size, uword align)
765 {
766   return clib_mem_heap_realloc_aligned (0, p, new_size, align);
767 }
768
769 __clib_export __clib_flatten void *
770 clib_mem_realloc (void *p, uword new_size)
771 {
772   return clib_mem_heap_realloc_aligned (0, p, new_size, CLIB_MEM_MIN_ALIGN);
773 }
774
775 __clib_export __clib_flatten uword
776 clib_mem_heap_is_heap_object (void *heap, void *p)
777 {
778   clib_mem_heap_t *h = heap ? heap : clib_mem_get_per_cpu_heap ();
779   return mspace_is_heap_object (h->mspace, p);
780 }
781
782 __clib_export __clib_flatten uword
783 clib_mem_is_heap_object (void *p)
784 {
785   return clib_mem_heap_is_heap_object (0, p);
786 }
787
788 __clib_export __clib_flatten void
789 clib_mem_heap_free (void *heap, void *p)
790 {
791   clib_mem_heap_t *h = heap ? heap : clib_mem_get_per_cpu_heap ();
792   uword size = clib_mem_size (p);
793
794   /* Make sure object is in the correct heap. */
795   ASSERT (clib_mem_heap_is_heap_object (h, p));
796
797   if (PREDICT_FALSE (h->flags & CLIB_MEM_HEAP_F_TRACED))
798     mheap_put_trace_internal (h, pointer_to_uword (p), size);
799   clib_mem_poison (p, clib_mem_size (p));
800
801   mspace_free (h->mspace, p);
802 }
803
804 __clib_export __clib_flatten void
805 clib_mem_free (void *p)
806 {
807   clib_mem_heap_free (0, p);
808 }
809
810 __clib_export __clib_flatten uword
811 clib_mem_size (void *p)
812 {
813   return mspace_usable_size (p);
814 }
815
816 __clib_export void
817 clib_mem_free_s (void *p)
818 {
819   uword size = clib_mem_size (p);
820   clib_mem_unpoison (p, size);
821   memset_s_inline (p, size, 0, size);
822   clib_mem_free (p);
823 }