Initial commit of vpp code.
[vpp.git] / vppinfra / 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
43 #include <vppinfra/clib.h>          /* uword, etc */
44 #include <vppinfra/mheap_bootstrap.h>
45 #include <vppinfra/os.h>
46 #include <vppinfra/string.h>        /* memcpy, memset */
47 #include <vppinfra/valgrind.h>
48
49 /* Per CPU heaps. */
50 extern void * clib_per_cpu_mheaps[32];
51
52 always_inline void * clib_mem_get_per_cpu_heap (void)
53 {
54   int cpu = os_get_cpu_number ();
55   return clib_per_cpu_mheaps[cpu];
56 }
57
58 always_inline void * clib_mem_set_per_cpu_heap (u8 * new_heap)
59 {
60   int cpu = os_get_cpu_number ();
61   void * old = clib_per_cpu_mheaps[cpu];
62   clib_per_cpu_mheaps[cpu] = new_heap;
63   return old;
64 }
65
66 /* Memory allocator which returns null when it fails. */
67 always_inline void *
68 clib_mem_alloc_aligned_at_offset (uword size,
69                                   uword align,
70                                   uword align_offset)
71 {
72   void * heap, * p;
73   uword offset, cpu;
74
75   if (align_offset > align)
76     {
77       if (align > 0)
78         align_offset %= align;
79       else
80         align_offset = align;
81     }
82
83   cpu = os_get_cpu_number ();
84   heap = clib_per_cpu_mheaps[cpu];
85   heap = mheap_get_aligned (heap,
86                             size, align, align_offset,
87                             &offset);
88   clib_per_cpu_mheaps[cpu] = heap;
89
90   if (offset != ~0)
91     {
92       p = heap + offset;
93 #if CLIB_DEBUG > 0
94       VALGRIND_MALLOCLIKE_BLOCK (p, mheap_data_bytes (heap, offset), 0, 0);
95 #endif
96       return p;
97     }
98   else
99     {
100       os_out_of_memory ();
101       return 0;
102     }
103 }
104
105 /* Memory allocator which returns null when it fails. */
106 always_inline void *
107 clib_mem_alloc (uword size)
108 { return clib_mem_alloc_aligned_at_offset (size, /* align */ 1, /* align_offset */ 0); }
109
110 always_inline void *
111 clib_mem_alloc_aligned (uword size, uword align)
112 { return clib_mem_alloc_aligned_at_offset (size, align, /* align_offset */ 0); }
113
114 /* Memory allocator which panics when it fails.
115    Use macro so that clib_panic macro can expand __FUNCTION__ and __LINE__. */
116 #define clib_mem_alloc_aligned_no_fail(size,align)                              \
117 ({                                                                              \
118   uword _clib_mem_alloc_size = (size);                                          \
119   void * _clib_mem_alloc_p;                                                     \
120   _clib_mem_alloc_p = clib_mem_alloc_aligned (_clib_mem_alloc_size, (align));   \
121   if (! _clib_mem_alloc_p)                                                      \
122     clib_panic ("failed to allocate %d bytes", _clib_mem_alloc_size);           \
123   _clib_mem_alloc_p;                                                            \
124 })
125
126 #define clib_mem_alloc_no_fail(size) clib_mem_alloc_aligned_no_fail(size,1)
127
128 /* Alias to stack allocator for naming consistency. */
129 #define clib_mem_alloc_stack(bytes) __builtin_alloca(bytes)
130
131 always_inline uword clib_mem_is_heap_object (void * p)
132 {
133   void * heap = clib_mem_get_per_cpu_heap ();
134   uword offset = (uword)p - (uword)heap;
135   mheap_elt_t * e, * n;
136
137   if (offset >= vec_len (heap))
138     return 0;
139
140   e = mheap_elt_at_uoffset (heap, offset);
141   n = mheap_next_elt (e);
142   
143   /* Check that heap forward and reverse pointers agree. */
144   return e->n_user_data == n->prev_n_user_data;
145 }
146
147 always_inline void clib_mem_free (void * p)
148 {
149   u8 * heap = clib_mem_get_per_cpu_heap ();
150
151   /* Make sure object is in the correct heap. */
152   ASSERT (clib_mem_is_heap_object (p));
153
154   mheap_put (heap, (u8 *) p - heap);
155
156 #if CLIB_DEBUG > 0
157   VALGRIND_FREELIKE_BLOCK (p, 0);
158 #endif
159 }
160
161 always_inline void * clib_mem_realloc (void * p, uword new_size, uword old_size)
162 {
163   /* By default use alloc, copy and free to emulate realloc. */
164   void * q = clib_mem_alloc (new_size);
165   if (q)
166     {
167       uword copy_size;
168       if (old_size < new_size)
169         copy_size = old_size;
170       else
171         copy_size = new_size;
172       memcpy (q, p, copy_size);
173       clib_mem_free (p);
174     }
175   return q;
176 }
177
178 always_inline uword clib_mem_size (void * p)
179 {
180   ASSERT (clib_mem_is_heap_object (p));
181   mheap_elt_t * e = mheap_user_pointer_to_elt (p);
182   return mheap_elt_data_bytes (e);
183 }
184
185 always_inline void * clib_mem_get_heap (void)
186 { return clib_mem_get_per_cpu_heap (); }
187
188 always_inline void * clib_mem_set_heap (void * heap)
189 { return clib_mem_set_per_cpu_heap (heap); }
190
191 void * clib_mem_init (void * heap, uword size);
192
193 void clib_mem_exit (void);
194
195 uword clib_mem_get_page_size (void);
196
197 void clib_mem_validate (void);
198
199 void clib_mem_trace (int enable);
200
201 typedef struct {
202   /* Total number of objects allocated. */
203   uword object_count;
204
205   /* Total allocated bytes.  Bytes used and free.
206      used + free = total */
207   uword bytes_total, bytes_used, bytes_free;
208
209   /* Number of bytes used by mheap data structure overhead
210      (e.g. free lists, mheap header). */
211   uword bytes_overhead;
212
213   /* Amount of free space returned to operating system. */
214   uword bytes_free_reclaimed;
215   
216   /* For malloc which puts small objects in sbrk region and
217      large objects in mmap'ed regions. */
218   uword bytes_used_sbrk;
219   uword bytes_used_mmap;
220
221   /* Max. number of bytes in this heap. */
222   uword bytes_max;
223 } clib_mem_usage_t;
224
225 void clib_mem_usage (clib_mem_usage_t * usage);
226
227 u8 * format_clib_mem_usage (u8 * s, va_list * args);
228
229 /* Include appropriate VM functions depending on whether
230    we are compiling for linux kernel, for Unix or standalone. */
231 #ifdef CLIB_LINUX_KERNEL
232 #include <vppinfra/vm_linux_kernel.h>
233 #endif
234
235 #ifdef CLIB_UNIX
236 #include <vppinfra/vm_unix.h>
237 #endif
238
239 #ifdef CLIB_STANDALONE
240 #include <vppinfra/vm_standalone.h>
241 #endif
242
243 #include <vppinfra/error.h>             /* clib_panic */
244
245 #endif /* _included_clib_mem_h */