]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/libsa/zalloc.c
amd64: use register macros for gdb_cpu_getreg()
[FreeBSD/FreeBSD.git] / stand / libsa / zalloc.c
1 /*
2  * This module derived from code donated to the FreeBSD Project by
3  * Matthew Dillon <dillon@backplane.com>
4  *
5  * Copyright (c) 1998 The FreeBSD Project
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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.
16  *
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
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34
35 /*
36  * LIB/MEMORY/ZALLOC.C  - self contained low-overhead memory pool/allocation
37  *                        subsystem
38  *
39  *      This subsystem implements memory pools and memory allocation
40  *      routines.
41  *
42  *      Pools are managed via a linked list of 'free' areas.  Allocating
43  *      memory creates holes in the freelist, freeing memory fills them.
44  *      Since the freelist consists only of free memory areas, it is possible
45  *      to allocate the entire pool without incuring any structural overhead.
46  *
47  *      The system works best when allocating similarly-sized chunks of
48  *      memory.  Care must be taken to avoid fragmentation when
49  *      allocating/deallocating dissimilar chunks.
50  *
51  *      When a memory pool is first allocated, the entire pool is marked as
52  *      allocated.  This is done mainly because we do not want to modify any
53  *      portion of a pool's data area until we are given permission.  The
54  *      caller must explicitly deallocate portions of the pool to make them
55  *      available.
56  *
57  *      z[n]xalloc() works like z[n]alloc() but the allocation is made from
58  *      within the specified address range.  If the segment could not be
59  *      allocated, NULL is returned.  WARNING!  The address range will be
60  *      aligned to an 8 or 16 byte boundry depending on the cpu so if you
61  *      give an unaligned address range, unexpected results may occur.
62  *
63  *      If a standard allocation fails, the reclaim function will be called
64  *      to recover some space.  This usually causes other portions of the
65  *      same pool to be released.  Memory allocations at this low level
66  *      should not block but you can do that too in your reclaim function
67  *      if you want.  Reclaim does not function when z[n]xalloc() is used,
68  *      only for z[n]alloc().
69  *
70  *      Allocation and frees of 0 bytes are valid operations.
71  */
72
73 #include "zalloc_defs.h"
74
75 /*
76  * Objects in the pool must be aligned to at least the size of struct MemNode.
77  * They must also be aligned to MALLOCALIGN, which should normally be larger
78  * than the struct, so assert that to be so at compile time.
79  */
80 typedef char assert_align[(sizeof(struct MemNode) <= MALLOCALIGN) ? 1 : -1];
81
82 #define MEMNODE_SIZE_MASK       MALLOCALIGN_MASK
83
84 /*
85  * znalloc() -  allocate memory (without zeroing) from pool.  Call reclaim
86  *              and retry if appropriate, return NULL if unable to allocate
87  *              memory.
88  */
89
90 void *
91 znalloc(MemPool *mp, uintptr_t bytes, size_t align)
92 {
93         MemNode **pmn;
94         MemNode *mn;
95
96         /*
97          * align according to pool object size (can be 0).  This is
98          * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
99          *
100         */
101         bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK;
102
103         if (bytes == 0)
104                 return ((void *)-1);
105
106         /*
107          * locate freelist entry big enough to hold the object.  If all objects
108          * are the same size, this is a constant-time function.
109          */
110
111         if (bytes > mp->mp_Size - mp->mp_Used)
112                 return (NULL);
113
114         for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) {
115                 char *ptr = (char *)mn;
116                 uintptr_t dptr;
117                 char *aligned;
118                 size_t extra;
119
120                 dptr = (uintptr_t)(ptr + MALLOCALIGN);  /* pointer to data */
121                 aligned = (char *)(roundup2(dptr, align) - MALLOCALIGN);
122                 extra = aligned - ptr;
123
124                 if (bytes + extra > mn->mr_Bytes)
125                         continue;
126
127                 /*
128                  * Cut extra from head and create new memory node from
129                  * remainder.
130                  */
131
132                 if (extra != 0) {
133                         MemNode *new;
134
135                         new = (MemNode *)aligned;
136                         new->mr_Next = mn->mr_Next;
137                         new->mr_Bytes = mn->mr_Bytes - extra;
138
139                         /* And update current memory node */
140                         mn->mr_Bytes = extra;
141                         mn->mr_Next = new;
142                         /* In next iteration, we will get our aligned address */
143                         continue;
144                 }
145
146                 /*
147                  *  Cut a chunk of memory out of the beginning of this
148                  *  block and fixup the link appropriately.
149                  */
150
151                 if (mn->mr_Bytes == bytes) {
152                         *pmn = mn->mr_Next;
153                 } else {
154                         mn = (MemNode *)((char *)mn + bytes);
155                         mn->mr_Next  = ((MemNode *)ptr)->mr_Next;
156                         mn->mr_Bytes = ((MemNode *)ptr)->mr_Bytes - bytes;
157                         *pmn = mn;
158                 }
159                 mp->mp_Used += bytes;
160                 return(ptr);
161         }
162
163         /*
164          * Memory pool is full, return NULL.
165          */
166
167         return (NULL);
168 }
169
170 /*
171  * zfree() - free previously allocated memory
172  */
173
174 void
175 zfree(MemPool *mp, void *ptr, uintptr_t bytes)
176 {
177         MemNode **pmn;
178         MemNode *mn;
179
180         /*
181          * align according to pool object size (can be 0).  This is
182          * inclusive of the MEMNODE_SIZE_MASK minimum alignment.
183          */
184         bytes = (bytes + MEMNODE_SIZE_MASK) & ~MEMNODE_SIZE_MASK;
185
186         if (bytes == 0)
187                 return;
188
189         /*
190          * panic if illegal pointer
191          */
192
193         if ((char *)ptr < (char *)mp->mp_Base ||
194             (char *)ptr + bytes > (char *)mp->mp_End ||
195             ((uintptr_t)ptr & MEMNODE_SIZE_MASK) != 0)
196                 panic("zfree(%p,%ju): wild pointer", ptr, (uintmax_t)bytes);
197
198         /*
199          * free the segment
200          */
201         mp->mp_Used -= bytes;
202
203         for (pmn = &mp->mp_First; (mn = *pmn) != NULL; pmn = &mn->mr_Next) {
204                 /*
205                  * If area between last node and current node
206                  *  - check range
207                  *  - check merge with next area
208                  *  - check merge with previous area
209                  */
210                 if ((char *)ptr <= (char *)mn) {
211                         /*
212                          * range check
213                          */
214                         if ((char *)ptr + bytes > (char *)mn) {
215                                 panic("zfree(%p,%ju): corrupt memlist1", ptr,
216                                     (uintmax_t)bytes);
217                         }
218
219                         /*
220                          * merge against next area or create independant area
221                          */
222
223                         if ((char *)ptr + bytes == (char *)mn) {
224                                 ((MemNode *)ptr)->mr_Next = mn->mr_Next;
225                                 ((MemNode *)ptr)->mr_Bytes =
226                                     bytes + mn->mr_Bytes;
227                         } else {
228                                 ((MemNode *)ptr)->mr_Next = mn;
229                                 ((MemNode *)ptr)->mr_Bytes = bytes;
230                         }
231                         *pmn = mn = (MemNode *)ptr;
232
233                         /*
234                          * merge against previous area (if there is a previous
235                          * area).
236                          */
237
238                         if (pmn != &mp->mp_First) {
239                                 if ((char *)pmn + ((MemNode*)pmn)->mr_Bytes ==
240                                     (char *)ptr) {
241                                         ((MemNode *)pmn)->mr_Next = mn->mr_Next;
242                                         ((MemNode *)pmn)->mr_Bytes +=
243                                             mn->mr_Bytes;
244                                         mn = (MemNode *)pmn;
245                                 }
246                         }
247                         return;
248                 }
249                 if ((char *)ptr < (char *)mn + mn->mr_Bytes) {
250                         panic("zfree(%p,%ju): corrupt memlist2", ptr,
251                             (uintmax_t)bytes);
252                 }
253         }
254         /*
255          * We are beyond the last MemNode, append new MemNode.  Merge against
256          * previous area if possible.
257          */
258         if (pmn == &mp->mp_First ||
259             (char *)pmn + ((MemNode *)pmn)->mr_Bytes != (char *)ptr) {
260                 ((MemNode *)ptr)->mr_Next = NULL;
261                 ((MemNode *)ptr)->mr_Bytes = bytes;
262                 *pmn = (MemNode *)ptr;
263                 mn = (MemNode *)ptr;
264         } else {
265                 ((MemNode *)pmn)->mr_Bytes += bytes;
266                 mn = (MemNode *)pmn;
267         }
268 }
269
270 /*
271  * zextendPool() - extend memory pool to cover additional space.
272  *
273  *                 Note: the added memory starts out as allocated, you
274  *                 must free it to make it available to the memory subsystem.
275  *
276  *                 Note: mp_Size may not reflect (mp_End - mp_Base) range
277  *                 due to other parts of the system doing their own sbrk()
278  *                 calls.
279  */
280
281 void
282 zextendPool(MemPool *mp, void *base, uintptr_t bytes)
283 {
284         if (mp->mp_Size == 0) {
285                 mp->mp_Base = base;
286                 mp->mp_Used = bytes;
287                 mp->mp_End = (char *)base + bytes;
288                 mp->mp_Size = bytes;
289         } else {
290                 void *pend = (char *)mp->mp_Base + mp->mp_Size;
291
292                 if (base < mp->mp_Base) {
293                         mp->mp_Size += (char *)mp->mp_Base - (char *)base;
294                         mp->mp_Used += (char *)mp->mp_Base - (char *)base;
295                         mp->mp_Base = base;
296                 }
297                 base = (char *)base + bytes;
298                 if (base > pend) {
299                         mp->mp_Size += (char *)base - (char *)pend;
300                         mp->mp_Used += (char *)base - (char *)pend;
301                         mp->mp_End = (char *)base;
302                 }
303         }
304 }
305
306 #ifdef ZALLOCDEBUG
307
308 void
309 zallocstats(MemPool *mp)
310 {
311         int abytes = 0;
312         int hbytes = 0;
313         int fcount = 0;
314         MemNode *mn;
315
316         printf("%d bytes reserved", (int)mp->mp_Size);
317
318         mn = mp->mp_First;
319
320         if ((void *)mn != (void *)mp->mp_Base) {
321                 abytes += (char *)mn - (char *)mp->mp_Base;
322         }
323
324         while (mn != NULL) {
325                 if ((char *)mn + mn->mr_Bytes != mp->mp_End) {
326                         hbytes += mn->mr_Bytes;
327                         ++fcount;
328                 }
329                 if (mn->mr_Next != NULL) {
330                         abytes += (char *)mn->mr_Next -
331                             ((char *)mn + mn->mr_Bytes);
332                 }
333                 mn = mn->mr_Next;
334         }
335         printf(" %d bytes allocated\n%d fragments (%d bytes fragmented)\n",
336             abytes, fcount, hbytes);
337 }
338
339 #endif