blob: 70e34cb4eb3f89e400798df14c7820754ff1a41e [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;
Dave Barachc3799992016-08-15 11:12:27 -040043
Ed Warnickecb9cada2015-12-08 15:45:58 -070044 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. */
Dave Barachc3799992016-08-15 11:12:27 -040071typedef struct
72{
Ed Warnickecb9cada2015-12-08 15:45:58 -070073 /* Offset of this element (plus free bit).
74 If element is free, data at offset contains pointer to free list. */
75 u32 offset;
76
77 /* Index of next and previous elements relative to current element. */
78 i32 next, prev;
79} heap_elt_t;
80
81/* Use high bit of offset as free bit. */
82#define HEAP_ELT_FREE_BIT (1 << 31)
83
Dave Barachc3799992016-08-15 11:12:27 -040084always_inline uword
85heap_is_free (heap_elt_t * e)
Ed Warnickecb9cada2015-12-08 15:45:58 -070086{
Dave Barachc3799992016-08-15 11:12:27 -040087 return (e->offset & HEAP_ELT_FREE_BIT) != 0;
88}
89
90always_inline uword
91heap_offset (heap_elt_t * e)
92{
93 return e->offset & ~HEAP_ELT_FREE_BIT;
94}
95
96always_inline heap_elt_t *
97heap_next (heap_elt_t * e)
98{
99 return e + e->next;
100}
101
102always_inline heap_elt_t *
103heap_prev (heap_elt_t * e)
104{
105 return e + e->prev;
106}
107
108always_inline uword
109heap_elt_size (void *v, heap_elt_t * e)
110{
111 heap_elt_t *n = heap_next (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700112 uword next_offset = n != e ? heap_offset (n) : vec_len (v);
113 return next_offset - heap_offset (e);
114}
115
116/* Sizes are binned. Sizes 1 to 2^log2_small_bins have their
117 own free lists. Larger sizes are grouped in powers of two. */
118#define HEAP_LOG2_SMALL_BINS (5)
119#define HEAP_SMALL_BINS (1 << HEAP_LOG2_SMALL_BINS)
120#define HEAP_N_BINS (2 * HEAP_SMALL_BINS)
121
122/* Header for heaps. */
Dave Barachc3799992016-08-15 11:12:27 -0400123typedef struct
124{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125 /* Vector of used and free elements. */
Dave Barachc3799992016-08-15 11:12:27 -0400126 heap_elt_t *elts;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127
128 /* For elt_bytes < sizeof (u32) we need some extra space
129 per elt to store free list index. */
Dave Barachc3799992016-08-15 11:12:27 -0400130 u32 *small_free_elt_free_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
132 /* Vector of free indices of elts array. */
Dave Barachc3799992016-08-15 11:12:27 -0400133 u32 *free_elts;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134
135 /* Indices of free elts indexed by size bin. */
Dave Barachc3799992016-08-15 11:12:27 -0400136 u32 **free_lists;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137
Dave Barachc3799992016-08-15 11:12:27 -0400138 format_function_t *format_elt;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139
140 /* Used for validattion/debugging. */
Dave Barachc3799992016-08-15 11:12:27 -0400141 uword *used_elt_bitmap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
143 /* First and last element of doubly linked chain of elements. */
144 u32 head, tail;
145
146 u32 used_count, max_len;
147
148 /* Number of bytes in a help element. */
149 u32 elt_bytes;
150
151 u32 flags;
152 /* Static heaps are made from external memory given to
153 us by user and are not re-sizeable vectors. */
154#define HEAP_IS_STATIC (1)
155} heap_header_t;
156
157/* Start of heap elements is always cache aligned. */
158#define HEAP_DATA_ALIGN (CLIB_CACHE_LINE_BYTES)
159
Dave Barachc3799992016-08-15 11:12:27 -0400160always_inline heap_header_t *
161heap_header (void *v)
162{
163 return vec_header (v, sizeof (heap_header_t));
164}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165
Dave Barachc3799992016-08-15 11:12:27 -0400166always_inline uword
167heap_header_bytes ()
168{
169 return vec_header_bytes (sizeof (heap_header_t));
170}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
Dave Barachc3799992016-08-15 11:12:27 -0400172always_inline void
173heap_dup_header (heap_header_t * old, heap_header_t * new)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174{
175 uword i;
176
177 new[0] = old[0];
178 new->elts = vec_dup (new->elts);
179 new->free_elts = vec_dup (new->free_elts);
180 new->free_lists = vec_dup (new->free_lists);
181 for (i = 0; i < vec_len (new->free_lists); i++)
182 new->free_lists[i] = vec_dup (new->free_lists[i]);
183 new->used_elt_bitmap = clib_bitmap_dup (new->used_elt_bitmap);
184 new->small_free_elt_free_index = vec_dup (new->small_free_elt_free_index);
185}
186
187/* Make a duplicate copy of a heap. */
188#define heap_dup(v) _heap_dup(v, vec_len (v) * sizeof (v[0]))
189
Dave Barachc3799992016-08-15 11:12:27 -0400190always_inline void *
191_heap_dup (void *v_old, uword v_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192{
Dave Barachc3799992016-08-15 11:12:27 -0400193 heap_header_t *h_old, *h_new;
194 void *v_new;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
196 h_old = heap_header (v_old);
197
Dave Barachc3799992016-08-15 11:12:27 -0400198 if (!v_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 return v_old;
200
201 v_new = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400202 v_new =
203 _vec_resize (v_new, _vec_len (v_old), v_bytes, sizeof (heap_header_t),
204 HEAP_DATA_ALIGN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 h_new = heap_header (v_new);
206 heap_dup_header (h_old, h_new);
Damjan Marionf1213b82016-03-13 02:22:06 +0100207 clib_memcpy (v_new, v_old, v_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 return v_new;
209}
210
Dave Barachc3799992016-08-15 11:12:27 -0400211always_inline uword
212heap_elts (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213{
Dave Barachc3799992016-08-15 11:12:27 -0400214 heap_header_t *h = heap_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 return h->used_count;
216}
217
Dave Barachc3799992016-08-15 11:12:27 -0400218uword heap_bytes (void *v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219
Dave Barachc3799992016-08-15 11:12:27 -0400220always_inline void *
221_heap_new (u32 len, u32 n_elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222{
Damjan Marion2f25ef32018-05-04 20:45:41 +0200223 void *v = _vec_resize ((void *) 0, len, (uword) len * n_elt_bytes,
Dave Barachc3799992016-08-15 11:12:27 -0400224 sizeof (heap_header_t),
225 HEAP_DATA_ALIGN);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226 heap_header (v)->elt_bytes = n_elt_bytes;
227 return v;
228}
229
230#define heap_new(v) (v) = _heap_new (0, sizeof ((v)[0]))
231
232always_inline void
Dave Barachc3799992016-08-15 11:12:27 -0400233heap_set_format (void *v, format_function_t * format_elt)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234{
235 ASSERT (v);
236 heap_header (v)->format_elt = format_elt;
237}
238
239always_inline void
Dave Barachc3799992016-08-15 11:12:27 -0400240heap_set_max_len (void *v, uword max_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241{
242 ASSERT (v);
243 heap_header (v)->max_len = max_len;
244}
245
Dave Barachc3799992016-08-15 11:12:27 -0400246always_inline uword
247heap_get_max_len (void *v)
248{
249 return v ? heap_header (v)->max_len : 0;
250}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251
252/* Create fixed size heap with given block of memory. */
253always_inline void *
Dave Barachc3799992016-08-15 11:12:27 -0400254heap_create_from_memory (void *memory, uword max_len, uword elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255{
Dave Barachc3799992016-08-15 11:12:27 -0400256 heap_header_t *h;
257 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
259 if (max_len * elt_bytes < sizeof (h[0]))
260 return 0;
261
262 h = memory;
263 memset (h, 0, sizeof (h[0]));
264 h->max_len = max_len;
265 h->elt_bytes = elt_bytes;
266 h->flags = HEAP_IS_STATIC;
267
Dave Barachc3799992016-08-15 11:12:27 -0400268 v = (void *) (memory + heap_header_bytes ());
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 _vec_len (v) = 0;
270 return v;
271}
272
273/* Execute BODY for each allocated heap element. */
274#define heap_foreach(var,len,heap,body) \
275do { \
276 if (vec_len (heap) > 0) \
277 { \
278 heap_header_t * _h = heap_header (heap); \
279 heap_elt_t * _e = _h->elts + _h->head; \
280 heap_elt_t * _end = _h->elts + _h->tail; \
281 while (1) \
282 { \
283 if (! heap_is_free (_e)) \
284 { \
285 (var) = (heap) + heap_offset (_e); \
286 (len) = heap_elt_size ((heap), _e); \
287 do { body; } while (0); \
288 } \
289 if (_e == _end) \
290 break; \
291 _e = heap_next (_e); \
292 } \
293 } \
294} while (0)
295
296#define heap_elt_at_index(v,index) vec_elt_at_index(v,index)
297
298always_inline heap_elt_t *
Dave Barachc3799992016-08-15 11:12:27 -0400299heap_get_elt (void *v, uword handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300{
Dave Barachc3799992016-08-15 11:12:27 -0400301 heap_header_t *h = heap_header (v);
302 heap_elt_t *e = vec_elt_at_index (h->elts, handle);
303 ASSERT (!heap_is_free (e));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700304 return e;
305}
306
307#define heap_elt_with_handle(v,handle) \
308({ \
309 heap_elt_t * _e = heap_get_elt ((v), (handle)); \
310 (v) + heap_offset (_e); \
311})
312
313always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400314heap_is_free_handle (void *v, uword heap_handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315{
Dave Barachc3799992016-08-15 11:12:27 -0400316 heap_header_t *h = heap_header (v);
317 heap_elt_t *e = vec_elt_at_index (h->elts, heap_handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 return heap_is_free (e);
319}
320
Dave Barachc3799992016-08-15 11:12:27 -0400321extern uword heap_len (void *v, word handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322
323/* Low level allocation call. */
Dave Barachc3799992016-08-15 11:12:27 -0400324extern void *_heap_alloc (void *v, uword size, uword alignment,
325 uword elt_bytes, uword * offset, uword * handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326
327#define heap_alloc_aligned(v,size,align,handle) \
328({ \
329 uword _o, _h; \
330 uword _a = (align); \
331 uword _s = (size); \
332 (v) = _heap_alloc ((v), _s, _a, sizeof ((v)[0]), &_o, &_h); \
333 (handle) = _h; \
334 _o; \
335})
336
337#define heap_alloc(v,size,handle) heap_alloc_aligned((v),(size),0,(handle))
338
Dave Barachc3799992016-08-15 11:12:27 -0400339extern void heap_dealloc (void *v, uword handle);
340extern void heap_validate (void *v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341
342/* Format heap internal data structures as string. */
Dave Barachc3799992016-08-15 11:12:27 -0400343extern u8 *format_heap (u8 * s, va_list * va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344
Dave Barachc3799992016-08-15 11:12:27 -0400345void *_heap_free (void *v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346
347#define heap_free(v) (v)=_heap_free(v)
348
349#endif /* included_heap_h */
Dave Barachc3799992016-08-15 11:12:27 -0400350
351/*
352 * fd.io coding-style-patch-verification: ON
353 *
354 * Local Variables:
355 * eval: (c-set-style "gnu")
356 * End:
357 */