2 * This module derived from code donated to the FreeBSD Project by
3 * Matthew Dillon <dillon@backplane.com>
5 * Copyright (c) 1998 The FreeBSD Project
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
34 * LIB/MEMORY/ZALLOC.C - self contained low-overhead memory pool/allocation
37 * This subsystem implements memory pools and memory allocation
40 * Pools are managed via a linked list of 'free' areas. Allocating
41 * memory creates holes in the freelist, freeing memory fills them.
42 * Since the freelist consists only of free memory areas, it is possible
43 * to allocate the entire pool without incuring any structural overhead.
45 * The system works best when allocating similarly-sized chunks of
46 * memory. Care must be taken to avoid fragmentation when
47 * allocating/deallocating dissimilar chunks.
49 * When a memory pool is first allocated, the entire pool is marked as
50 * allocated. This is done mainly because we do not want to modify any
51 * portion of a pool's data area until we are given permission. The
52 * caller must explicitly deallocate portions of the pool to make them
55 * z[n]xalloc() works like z[n]alloc() but the allocation is made from
56 * within the specified address range. If the segment could not be
57 * allocated, NULL is returned. WARNING! The address range will be
58 * aligned to an 8 or 16 byte boundry depending on the cpu so if you
59 * give an unaligned address range, unexpected results may occur.
61 * If a standard allocation fails, the reclaim function will be called
62 * to recover some space. This usually causes other portions of the
63 * same pool to be released. Memory allocations at this low level
64 * should not block but you can do that too in your reclaim function
65 * if you want. Reclaim does not function when z[n]xalloc() is used,
66 * only for z[n]alloc().
68 * Allocation and frees of 0 bytes are valid operations.
71 #include "zalloc_defs.h"
74 * Objects in the pool must be aligned to at least the size of struct MemNode.
75 * They must also be aligned to MALLOCALIGN, which should normally be larger
76 * than the struct, so assert that to be so at compile time.
78 typedef char assert_align
[(sizeof(struct MemNode
) <= MALLOCALIGN
) ? 1 : -1];
80 #define MEMNODE_SIZE_MASK MALLOCALIGN_MASK
83 * znalloc() - allocate memory (without zeroing) from pool. Call reclaim
84 * and retry if appropriate, return NULL if unable to allocate
89 znalloc(MemPool
*mp
, uintptr_t bytes
)
92 * align according to pool object size (can be 0). This is
93 * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
96 bytes
= (bytes
+ MEMNODE_SIZE_MASK
) & ~MEMNODE_SIZE_MASK
;
102 * locate freelist entry big enough to hold the object. If all objects
103 * are the same size, this is a constant-time function.
106 if (bytes
<= mp
->mp_Size
- mp
->mp_Used
) {
110 for (pmn
= &mp
->mp_First
; (mn
=*pmn
) != NULL
; pmn
= &mn
->mr_Next
) {
111 if (bytes
> mn
->mr_Bytes
)
115 * Cut a chunk of memory out of the beginning of this
116 * block and fixup the link appropriately.
120 char *ptr
= (char *)mn
;
122 if (mn
->mr_Bytes
== bytes
) {
125 mn
= (MemNode
*)((char *)mn
+ bytes
);
126 mn
->mr_Next
= ((MemNode
*)ptr
)->mr_Next
;
127 mn
->mr_Bytes
= ((MemNode
*)ptr
)->mr_Bytes
- bytes
;
130 mp
->mp_Used
+= bytes
;
137 * Memory pool is full, return NULL.
144 * zfree() - free previously allocated memory
148 zfree(MemPool
*mp
, void *ptr
, uintptr_t bytes
)
151 * align according to pool object size (can be 0). This is
152 * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
154 bytes
= (bytes
+ MEMNODE_SIZE_MASK
) & ~MEMNODE_SIZE_MASK
;
160 * panic if illegal pointer
163 if ((char *)ptr
< (char *)mp
->mp_Base
||
164 (char *)ptr
+ bytes
> (char *)mp
->mp_End
||
165 ((uintptr_t)ptr
& MEMNODE_SIZE_MASK
) != 0)
166 panic("zfree(%p,%ju): wild pointer", ptr
, (uintmax_t)bytes
);
176 mp
->mp_Used
-= bytes
;
178 for (pmn
= &mp
->mp_First
; (mn
= *pmn
) != NULL
; pmn
= &mn
->mr_Next
) {
180 * If area between last node and current node
182 * - check merge with next area
183 * - check merge with previous area
185 if ((char *)ptr
<= (char *)mn
) {
189 if ((char *)ptr
+ bytes
> (char *)mn
) {
190 panic("zfree(%p,%ju): corrupt memlist1", ptr
,
195 * merge against next area or create independant area
198 if ((char *)ptr
+ bytes
== (char *)mn
) {
199 ((MemNode
*)ptr
)->mr_Next
= mn
->mr_Next
;
200 ((MemNode
*)ptr
)->mr_Bytes
= bytes
+ mn
->mr_Bytes
;
202 ((MemNode
*)ptr
)->mr_Next
= mn
;
203 ((MemNode
*)ptr
)->mr_Bytes
= bytes
;
205 *pmn
= mn
= (MemNode
*)ptr
;
208 * merge against previous area (if there is a previous
212 if (pmn
!= &mp
->mp_First
) {
213 if ((char*)pmn
+ ((MemNode
*)pmn
)->mr_Bytes
== (char*)ptr
) {
214 ((MemNode
*)pmn
)->mr_Next
= mn
->mr_Next
;
215 ((MemNode
*)pmn
)->mr_Bytes
+= mn
->mr_Bytes
;
222 if ((char *)ptr
< (char *)mn
+ mn
->mr_Bytes
) {
223 panic("zfree(%p,%ju): corrupt memlist2", ptr
,
228 * We are beyond the last MemNode, append new MemNode. Merge against
229 * previous area if possible.
231 if (pmn
== &mp
->mp_First
||
232 (char *)pmn
+ ((MemNode
*)pmn
)->mr_Bytes
!= (char *)ptr
234 ((MemNode
*)ptr
)->mr_Next
= NULL
;
235 ((MemNode
*)ptr
)->mr_Bytes
= bytes
;
236 *pmn
= (MemNode
*)ptr
;
239 ((MemNode
*)pmn
)->mr_Bytes
+= bytes
;
246 * zextendPool() - extend memory pool to cover additional space.
248 * Note: the added memory starts out as allocated, you
249 * must free it to make it available to the memory subsystem.
251 * Note: mp_Size may not reflect (mp_End - mp_Base) range
252 * due to other parts of the system doing their own sbrk()
257 zextendPool(MemPool
*mp
, void *base
, uintptr_t bytes
)
259 if (mp
->mp_Size
== 0) {
262 mp
->mp_End
= (char *)base
+ bytes
;
265 void *pend
= (char *)mp
->mp_Base
+ mp
->mp_Size
;
267 if (base
< mp
->mp_Base
) {
268 mp
->mp_Size
+= (char *)mp
->mp_Base
- (char *)base
;
269 mp
->mp_Used
+= (char *)mp
->mp_Base
- (char *)base
;
272 base
= (char *)base
+ bytes
;
274 mp
->mp_Size
+= (char *)base
- (char *)pend
;
275 mp
->mp_Used
+= (char *)base
- (char *)pend
;
276 mp
->mp_End
= (char *)base
;
284 zallocstats(MemPool
*mp
)
291 printf("%d bytes reserved", (int) mp
->mp_Size
);
295 if ((void *)mn
!= (void *)mp
->mp_Base
) {
296 abytes
+= (char *)mn
- (char *)mp
->mp_Base
;
300 if ((char *)mn
+ mn
->mr_Bytes
!= mp
->mp_End
) {
301 hbytes
+= mn
->mr_Bytes
;
305 abytes
+= (char *)mn
->mr_Next
- ((char *)mn
+ mn
->mr_Bytes
);
308 printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n",