blob: 912e865e75bdb7dce14ac913ec9fd787567ecc4c [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/* Heaps of objects of type T (e.g. int, struct foo, ...).
39
40 Usage. To declare a null heap:
41
42 T * heap = 0;
43
44 To allocate:
45
46 offset = heap_alloc (heap, size, handle);
47
48 New object is heap[offset] ... heap[offset + size]
49 Handle is used to free/query object.
50
51 To free object:
52
53 heap_dealloc (heap, handle);
54
55 To query the size of an object:
56
57 heap_size (heap, handle)
58
59*/
60
61#ifndef included_heap_h
62#define included_heap_h
63
64#include <vppinfra/clib.h>
65#include <vppinfra/cache.h>
66#include <vppinfra/hash.h>
67#include <vppinfra/format.h>
68#include <vppinfra/bitmap.h>
69
70/* Doubly linked list of elements. */
71typedef struct {
72 /* Offset of this element (plus free bit).
73 If element is free, data at offset contains pointer to free list. */
74 u32 offset;
75
76 /* Index of next and previous elements relative to current element. */
77 i32 next, prev;
78} heap_elt_t;
79
80/* Use high bit of offset as free bit. */
81#define HEAP_ELT_FREE_BIT (1 << 31)
82
83always_inline uword heap_is_free (heap_elt_t * e)
84{ return (e->offset & HEAP_ELT_FREE_BIT) != 0; }
85
86always_inline uword heap_offset (heap_elt_t * e)
87{ return e->offset &~ HEAP_ELT_FREE_BIT; }
88
89always_inline heap_elt_t * heap_next (heap_elt_t * e)
90{ return e + e->next; }
91
92always_inline heap_elt_t * heap_prev (heap_elt_t * e)
93{ return e + e->prev; }
94
95always_inline uword heap_elt_size (void * v, heap_elt_t * e)
96{
97 heap_elt_t * n = heap_next (e);
98 uword next_offset = n != e ? heap_offset (n) : vec_len (v);
99 return next_offset - heap_offset (e);
100}
101
102/* Sizes are binned. Sizes 1 to 2^log2_small_bins have their
103 own free lists. Larger sizes are grouped in powers of two. */
104#define HEAP_LOG2_SMALL_BINS (5)
105#define HEAP_SMALL_BINS (1 << HEAP_LOG2_SMALL_BINS)
106#define HEAP_N_BINS (2 * HEAP_SMALL_BINS)
107
108/* Header for heaps. */
109typedef struct {
110 /* Vector of used and free elements. */
111 heap_elt_t * elts;
112
113 /* For elt_bytes < sizeof (u32) we need some extra space
114 per elt to store free list index. */
115 u32 * small_free_elt_free_index;
116
117 /* Vector of free indices of elts array. */
118 u32 * free_elts;
119
120 /* Indices of free elts indexed by size bin. */
121 u32 ** free_lists;
122
123 format_function_t * format_elt;
124
125 /* Used for validattion/debugging. */
126 uword * used_elt_bitmap;
127
128 /* First and last element of doubly linked chain of elements. */
129 u32 head, tail;
130
131 u32 used_count, max_len;
132
133 /* Number of bytes in a help element. */
134 u32 elt_bytes;
135
136 u32 flags;
137 /* Static heaps are made from external memory given to
138 us by user and are not re-sizeable vectors. */
139#define HEAP_IS_STATIC (1)
140} heap_header_t;
141
142/* Start of heap elements is always cache aligned. */
143#define HEAP_DATA_ALIGN (CLIB_CACHE_LINE_BYTES)
144
145always_inline heap_header_t * heap_header (void * v)
146{ return vec_header (v, sizeof (heap_header_t)); }
147
148always_inline uword heap_header_bytes ()
149{ return vec_header_bytes (sizeof (heap_header_t)); }
150
151always_inline void heap_dup_header (heap_header_t * old, heap_header_t * new)
152{
153 uword i;
154
155 new[0] = old[0];
156 new->elts = vec_dup (new->elts);
157 new->free_elts = vec_dup (new->free_elts);
158 new->free_lists = vec_dup (new->free_lists);
159 for (i = 0; i < vec_len (new->free_lists); i++)
160 new->free_lists[i] = vec_dup (new->free_lists[i]);
161 new->used_elt_bitmap = clib_bitmap_dup (new->used_elt_bitmap);
162 new->small_free_elt_free_index = vec_dup (new->small_free_elt_free_index);
163}
164
165/* Make a duplicate copy of a heap. */
166#define heap_dup(v) _heap_dup(v, vec_len (v) * sizeof (v[0]))
167
168always_inline void * _heap_dup (void * v_old, uword v_bytes)
169{
170 heap_header_t * h_old, * h_new;
171 void * v_new;
172
173 h_old = heap_header (v_old);
174
175 if (! v_old)
176 return v_old;
177
178 v_new = 0;
179 v_new = _vec_resize (v_new, _vec_len (v_old), v_bytes, sizeof (heap_header_t),
180 HEAP_DATA_ALIGN);
181 h_new = heap_header (v_new);
182 heap_dup_header (h_old, h_new);
183 memcpy (v_new, v_old, v_bytes);
184 return v_new;
185}
186
187always_inline uword heap_elts (void * v)
188{
189 heap_header_t * h = heap_header (v);
190 return h->used_count;
191}
192
193uword heap_bytes (void * v);
194
195always_inline void * _heap_new (u32 len, u32 n_elt_bytes)
196{
197 void * v = _vec_resize (0, len, len*n_elt_bytes,
198 sizeof (heap_header_t),
199 HEAP_DATA_ALIGN);
200 heap_header (v)->elt_bytes = n_elt_bytes;
201 return v;
202}
203
204#define heap_new(v) (v) = _heap_new (0, sizeof ((v)[0]))
205
206always_inline void
207heap_set_format (void * v, format_function_t * format_elt)
208{
209 ASSERT (v);
210 heap_header (v)->format_elt = format_elt;
211}
212
213always_inline void
214heap_set_max_len (void * v, uword max_len)
215{
216 ASSERT (v);
217 heap_header (v)->max_len = max_len;
218}
219
220always_inline uword heap_get_max_len (void * v)
221{ return v ? heap_header (v)->max_len : 0; }
222
223/* Create fixed size heap with given block of memory. */
224always_inline void *
225heap_create_from_memory (void * memory, uword max_len, uword elt_bytes)
226{
227 heap_header_t * h;
228 void * v;
229
230 if (max_len * elt_bytes < sizeof (h[0]))
231 return 0;
232
233 h = memory;
234 memset (h, 0, sizeof (h[0]));
235 h->max_len = max_len;
236 h->elt_bytes = elt_bytes;
237 h->flags = HEAP_IS_STATIC;
238
239 v = (void *) (memory + heap_header_bytes ());
240 _vec_len (v) = 0;
241 return v;
242}
243
244/* Execute BODY for each allocated heap element. */
245#define heap_foreach(var,len,heap,body) \
246do { \
247 if (vec_len (heap) > 0) \
248 { \
249 heap_header_t * _h = heap_header (heap); \
250 heap_elt_t * _e = _h->elts + _h->head; \
251 heap_elt_t * _end = _h->elts + _h->tail; \
252 while (1) \
253 { \
254 if (! heap_is_free (_e)) \
255 { \
256 (var) = (heap) + heap_offset (_e); \
257 (len) = heap_elt_size ((heap), _e); \
258 do { body; } while (0); \
259 } \
260 if (_e == _end) \
261 break; \
262 _e = heap_next (_e); \
263 } \
264 } \
265} while (0)
266
267#define heap_elt_at_index(v,index) vec_elt_at_index(v,index)
268
269always_inline heap_elt_t *
270heap_get_elt (void * v, uword handle)
271{
272 heap_header_t * h = heap_header (v);
273 heap_elt_t * e = vec_elt_at_index (h->elts, handle);
274 ASSERT (! heap_is_free (e));
275 return e;
276}
277
278#define heap_elt_with_handle(v,handle) \
279({ \
280 heap_elt_t * _e = heap_get_elt ((v), (handle)); \
281 (v) + heap_offset (_e); \
282})
283
284always_inline uword
285heap_is_free_handle (void * v, uword heap_handle)
286{
287 heap_header_t * h = heap_header (v);
288 heap_elt_t * e = vec_elt_at_index (h->elts, heap_handle);
289 return heap_is_free (e);
290}
291
292extern uword heap_len (void * v, word handle);
293
294/* Low level allocation call. */
295extern void * _heap_alloc (void * v, uword size, uword alignment,
296 uword elt_bytes,
297 uword * offset, uword * handle);
298
299#define heap_alloc_aligned(v,size,align,handle) \
300({ \
301 uword _o, _h; \
302 uword _a = (align); \
303 uword _s = (size); \
304 (v) = _heap_alloc ((v), _s, _a, sizeof ((v)[0]), &_o, &_h); \
305 (handle) = _h; \
306 _o; \
307})
308
309#define heap_alloc(v,size,handle) heap_alloc_aligned((v),(size),0,(handle))
310
311extern void heap_dealloc (void * v, uword handle);
312extern void heap_validate (void * v);
313
314/* Format heap internal data structures as string. */
315extern u8 * format_heap (u8 * s, va_list * va);
316
317void * _heap_free (void * v);
318
319#define heap_free(v) (v)=_heap_free(v)
320
321#endif /* included_heap_h */