xref: /openbsd/sys/lib/libsa/alloc.c (revision 78b63d65)
1 /*	$OpenBSD: alloc.c,v 1.5 1997/08/01 21:57:09 pefo Exp $	*/
2 /*	$NetBSD: alloc.c,v 1.6 1997/02/04 18:36:33 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
6  * Copyright (c) 1996
7  *	Matthias Drochner.  All rights reserved.
8  * Copyright (c) 1993
9  *	The Regents of the University of California.  All rights reserved.
10  *
11  * This code is derived from software contributed to Berkeley by
12  * The Mach Operating System project at Carnegie-Mellon University.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *	This product includes software developed by the University of
25  *	California, Berkeley and its contributors.
26  * 4. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	@(#)alloc.c	8.1 (Berkeley) 6/11/93
43  *
44  *
45  * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
46  * All Rights Reserved.
47  *
48  * Author: Alessandro Forin
49  *
50  * Permission to use, copy, modify and distribute this software and its
51  * documentation is hereby granted, provided that both the copyright
52  * notice and this permission notice appear in all copies of the
53  * software, derivative works or modified versions, and any portions
54  * thereof, and that both notices appear in supporting documentation.
55  *
56  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
57  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
58  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
59  *
60  * Carnegie Mellon requests users of this software to return to
61  *
62  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
63  *  School of Computer Science
64  *  Carnegie Mellon University
65  *  Pittsburgh PA 15213-3890
66  *
67  * any improvements or extensions that they make and grant Carnegie the
68  * rights to redistribute these changes.
69  */
70 
71 /*
72  * Dynamic memory allocator.
73  *
74  * Compile options:
75  *
76  *	ALLOC_TRACE	enable tracing of allocations/deallocations
77  *
78  *	ALLOC_FIRST_FIT	use a first-fit allocation algorithm, rather than
79  *			the default best-fit algorithm.
80  *
81  *	HEAP_LIMIT	heap limit address (defaults to "no limit").
82  *
83  *	HEAP_START	start address of heap (defaults to '&end').
84  *
85  *	DEBUG		enable debugging sanity checks.
86  */
87 
88 #include <sys/param.h>
89 
90 /*
91  * Each block actually has ALIGN(unsigned) + ALIGN(size) bytes allocated
92  * to it, as follows:
93  *
94  * 0 ... (sizeof(unsigned) - 1)
95  *	allocated or unallocated: holds size of user-data part of block.
96  *
97  * sizeof(unsigned) ... (ALIGN(sizeof(unsigned)) - 1)
98  *	allocated: unused
99  *	unallocated: depends on packing of struct fl
100  *
101  * ALIGN(sizeof(unsigned)) ... (ALIGN(sizeof(unsigned)) + ALIGN(data size) - 1)
102  *	allocated: user data
103  *	unallocated: depends on packing of struct fl
104  *
105  * 'next' is only used when the block is unallocated (i.e. on the free list).
106  * However, note that ALIGN(sizeof(unsigned)) + ALIGN(data size) must
107  * be at least 'sizeof(struct fl)', so that blocks can be used as structures
108  * when on the free list.
109  */
110 
111 #include "stand.h"
112 
113 struct fl {
114 	unsigned	size;
115 	struct fl	*next;
116 } *freelist = (struct fl *)0;
117 
118 #ifdef HEAP_START
119 static char *top = (char*)HEAP_START;
120 #else
121 extern char end[];
122 static char *top = end;
123 #endif
124 
125 void *
126 alloc(size)
127 	unsigned size;
128 {
129 	register struct fl **f = &freelist, **bestf = NULL;
130 #ifndef ALLOC_FIRST_FIT
131 	unsigned bestsize = 0xffffffff;	/* greater than any real size */
132 #endif
133 	char *help;
134 	int failed;
135 
136 #ifdef ALLOC_TRACE
137 	printf("alloc(%u)", size);
138 #endif
139 
140 #ifdef ALLOC_FIRST_FIT
141 	while (*f != (struct fl *)0 && (*f)->size < size)
142 		f = &((*f)->next);
143 	bestf = f;
144 	failed = (*bestf == (struct fl *)0);
145 #else
146 	/* scan freelist */
147 	while (*f) {
148 		if ((*f)->size >= size) {
149 			if ((*f)->size == size) /* exact match */
150 				goto found;
151 
152 			if ((*f)->size < bestsize) {
153 				/* keep best fit */
154 	                        bestf = f;
155 	                        bestsize = (*f)->size;
156 	                }
157 	        }
158 	        f = &((*f)->next);
159 	}
160 
161 	/* no match in freelist if bestsize unchanged */
162 	failed = (bestsize == 0xffffffff);
163 #endif
164 
165 	if (failed) { /* nothing found */
166 	        /*
167 		 * allocate from heap, keep chunk len in
168 		 * first word
169 		 */
170 	        help = top;
171 
172 		/* make _sure_ the region can hold a struct fl. */
173 		if (size < ALIGN(sizeof (struct fl *)))
174 			size = ALIGN(sizeof (struct fl *));
175 		top += ALIGN(sizeof(unsigned)) + ALIGN(size);
176 #ifdef HEAP_LIMIT
177 		if (top > (char*)HEAP_LIMIT)
178 		        panic("heap full (0x%lx+%u)", help, size);
179 #endif
180 		*(unsigned *)help = ALIGN(size);
181 #ifdef ALLOC_TRACE
182 		printf("=%p\n", help + ALIGN(sizeof(unsigned)));
183 #endif
184 		return(help + ALIGN(sizeof(unsigned)));
185 	}
186 
187 	/* we take the best fit */
188 	f = bestf;
189 
190 #ifndef ALLOC_FIRST_FIT
191 found:
192 #endif
193         /* remove from freelist */
194         help = (char*)*f;
195 	*f = (*f)->next;
196 #ifdef ALLOC_TRACE
197 	printf("=%p (origsize %u)\n", help + ALIGN(sizeof(unsigned)),
198 	    *(unsigned *)help);
199 #endif
200 	return(help + ALIGN(sizeof(unsigned)));
201 }
202 
203 void
204 free(ptr, size)
205 	void *ptr;
206 	unsigned size; /* only for consistence check */
207 {
208 	register struct fl *f =
209 	    (struct fl *)((char*)ptr - ALIGN(sizeof(unsigned)));
210 #ifdef ALLOC_TRACE
211 	printf("free(%p, %u) (origsize %u)\n", ptr, size, f->size);
212 #endif
213 #ifdef DEBUG
214         if (size > f->size)
215 	        printf("free %u bytes @%p, should be <=%u\n",
216 		    size, ptr, f->size);
217 #ifdef HEAP_START
218 	if (ptr < (void *)HEAP_START)
219 #else
220 	if (ptr < (void *)end)
221 #endif
222 		printf("free: %lx before start of heap.\n", (u_long)ptr);
223 
224 #ifdef HEAP_LIMIT
225 	if (ptr > (void *)HEAP_LIMIT)
226 		printf("free: %lx beyond end of heap.\n", (u_long)ptr);
227 #endif
228 #endif /* DEBUG */
229 	/* put into freelist */
230 	f->next = freelist;
231 	freelist = f;
232 }
233