xref: /netbsd-src/sys/lib/libsa/alloc.c (revision 10497fd285fb21c25f76e74beeb53b30864bc3f3)
1*10497fd2Schristos /*	$NetBSD: alloc.c,v 1.28 2019/03/31 20:08:45 christos Exp $	*/
26668f51cScgd 
3ea27b7aaScgd /*
4aad01611Sagc  * Copyright (c) 1993
5aad01611Sagc  *	The Regents of the University of California.  All rights reserved.
6aad01611Sagc  *
7aad01611Sagc  * This code is derived from software contributed to Berkeley by
8aad01611Sagc  * The Mach Operating System project at Carnegie-Mellon University.
9aad01611Sagc  *
10aad01611Sagc  * Redistribution and use in source and binary forms, with or without
11aad01611Sagc  * modification, are permitted provided that the following conditions
12aad01611Sagc  * are met:
13aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
14aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
15aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
16aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
17aad01611Sagc  *    documentation and/or other materials provided with the distribution.
18aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
19aad01611Sagc  *    may be used to endorse or promote products derived from this software
20aad01611Sagc  *    without specific prior written permission.
21aad01611Sagc  *
22aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32aad01611Sagc  * SUCH DAMAGE.
33aad01611Sagc  *
34aad01611Sagc  *	@(#)alloc.c	8.1 (Berkeley) 6/11/93
35aad01611Sagc  *
36aad01611Sagc  *
37ea27b7aaScgd  * Copyright (c) 1997 Christopher G. Demetriou.  All rights reserved.
38ea27b7aaScgd  * Copyright (c) 1996
39ea27b7aaScgd  *	Matthias Drochner.  All rights reserved.
4036b52a82Sbrezak  *
4136b52a82Sbrezak  * This code is derived from software contributed to Berkeley by
4236b52a82Sbrezak  * The Mach Operating System project at Carnegie-Mellon University.
4336b52a82Sbrezak  *
4436b52a82Sbrezak  * Redistribution and use in source and binary forms, with or without
4536b52a82Sbrezak  * modification, are permitted provided that the following conditions
4636b52a82Sbrezak  * are met:
4736b52a82Sbrezak  * 1. Redistributions of source code must retain the above copyright
4836b52a82Sbrezak  *    notice, this list of conditions and the following disclaimer.
4936b52a82Sbrezak  * 2. Redistributions in binary form must reproduce the above copyright
5036b52a82Sbrezak  *    notice, this list of conditions and the following disclaimer in the
5136b52a82Sbrezak  *    documentation and/or other materials provided with the distribution.
5236b52a82Sbrezak  * 3. All advertising materials mentioning features or use of this software
5336b52a82Sbrezak  *    must display the following acknowledgement:
5436b52a82Sbrezak  *	This product includes software developed by the University of
5536b52a82Sbrezak  *	California, Berkeley and its contributors.
5636b52a82Sbrezak  * 4. Neither the name of the University nor the names of its contributors
5736b52a82Sbrezak  *    may be used to endorse or promote products derived from this software
5836b52a82Sbrezak  *    without specific prior written permission.
5936b52a82Sbrezak  *
6036b52a82Sbrezak  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6136b52a82Sbrezak  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6236b52a82Sbrezak  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6336b52a82Sbrezak  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6436b52a82Sbrezak  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6536b52a82Sbrezak  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6636b52a82Sbrezak  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6736b52a82Sbrezak  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6836b52a82Sbrezak  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6936b52a82Sbrezak  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7036b52a82Sbrezak  * SUCH DAMAGE.
7136b52a82Sbrezak  *
726668f51cScgd  *	@(#)alloc.c	8.1 (Berkeley) 6/11/93
7336b52a82Sbrezak  *
7436b52a82Sbrezak  *
7536b52a82Sbrezak  * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University
7636b52a82Sbrezak  * All Rights Reserved.
7736b52a82Sbrezak  *
7836b52a82Sbrezak  * Author: Alessandro Forin
7936b52a82Sbrezak  *
8036b52a82Sbrezak  * Permission to use, copy, modify and distribute this software and its
8136b52a82Sbrezak  * documentation is hereby granted, provided that both the copyright
8236b52a82Sbrezak  * notice and this permission notice appear in all copies of the
8336b52a82Sbrezak  * software, derivative works or modified versions, and any portions
8436b52a82Sbrezak  * thereof, and that both notices appear in supporting documentation.
8536b52a82Sbrezak  *
8636b52a82Sbrezak  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
8736b52a82Sbrezak  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
8836b52a82Sbrezak  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
8936b52a82Sbrezak  *
9036b52a82Sbrezak  * Carnegie Mellon requests users of this software to return to
9136b52a82Sbrezak  *
9236b52a82Sbrezak  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
9336b52a82Sbrezak  *  School of Computer Science
9436b52a82Sbrezak  *  Carnegie Mellon University
9536b52a82Sbrezak  *  Pittsburgh PA 15213-3890
9636b52a82Sbrezak  *
9736b52a82Sbrezak  * any improvements or extensions that they make and grant Carnegie the
9836b52a82Sbrezak  * rights to redistribute these changes.
9936b52a82Sbrezak  */
10036b52a82Sbrezak 
101ea27b7aaScgd /*
102ea27b7aaScgd  * Dynamic memory allocator.
103ea27b7aaScgd  *
104ea27b7aaScgd  * Compile options:
105ea27b7aaScgd  *
106ea27b7aaScgd  *	HEAP_LIMIT	heap limit address (defaults to "no limit").
107ea27b7aaScgd  *
108ea27b7aaScgd  *	HEAP_START	start address of heap (defaults to '&end').
109ea27b7aaScgd  *
110ea27b7aaScgd  *	DEBUG		enable debugging sanity checks.
111ea27b7aaScgd  */
112ea27b7aaScgd 
11320b21822Scgd #include <sys/param.h>
1148347a747Sdrochner #include "stand.h"
11520b21822Scgd 
11636b52a82Sbrezak /*
117db898c55Stsutsui  * Each block actually has ALIGN(unsigned int) + ALIGN(size) bytes allocated
118ea27b7aaScgd  * to it, as follows:
119ea27b7aaScgd  *
120db898c55Stsutsui  * 0 ... (sizeof(unsigned int) - 1)
121ea27b7aaScgd  *	allocated or unallocated: holds size of user-data part of block.
122ea27b7aaScgd  *
123db898c55Stsutsui  * sizeof(unsigned int) ... (ALIGN(sizeof(unsigned int)) - 1)
124ea27b7aaScgd  *	allocated: unused
125ea27b7aaScgd  *	unallocated: depends on packing of struct fl
126ea27b7aaScgd  *
127db898c55Stsutsui  * ALIGN(sizeof(unsigned int)) ...
128db898c55Stsutsui  *     (ALIGN(sizeof(unsigned int)) + ALIGN(data size) - 1)
129ea27b7aaScgd  *	allocated: user data
130ea27b7aaScgd  *	unallocated: depends on packing of struct fl
131ea27b7aaScgd  *
132ea27b7aaScgd  * 'next' is only used when the block is unallocated (i.e. on the free list).
133db898c55Stsutsui  * However, note that ALIGN(sizeof(unsigned int)) + ALIGN(data size) must
134ea27b7aaScgd  * be at least 'sizeof(struct fl)', so that blocks can be used as structures
135ea27b7aaScgd  * when on the free list.
1366896e29dSmaxv  *
1376896e29dSmaxv  * When HEAP_LIMIT is defined and the heap limit is reached, alloc() panics.
1386896e29dSmaxv  * Otherwise, it never fails.
13936b52a82Sbrezak  */
14036b52a82Sbrezak struct fl {
141db898c55Stsutsui 	unsigned int	size;
142ea27b7aaScgd 	struct fl	*next;
143bb7cdd7cScgd } *freelist;
14436b52a82Sbrezak 
145a1d00666Sdrochner #ifdef HEAP_VARIABLE
146a8ac47ddSdrochner static char *top, *heapstart, *heaplimit;
1471c038e68Sisaki void
setheap(void * start,void * limit)1481c038e68Sisaki setheap(void *start, void *limit)
149a1d00666Sdrochner {
150a8ac47ddSdrochner 	heapstart = top = start;
151a1d00666Sdrochner 	heaplimit = limit;
152a1d00666Sdrochner }
153a8ac47ddSdrochner #define HEAP_START heapstart
154a1d00666Sdrochner #define HEAP_LIMIT heaplimit
155a8ac47ddSdrochner #else /* !HEAP_VARIABLE */
156a8ac47ddSdrochner #ifndef HEAP_START
157a8ac47ddSdrochner extern char end[];
158a8ac47ddSdrochner #define HEAP_START end
159a1d00666Sdrochner #endif
160a8ac47ddSdrochner static char *top = (char *)HEAP_START;
161a8ac47ddSdrochner #endif /* HEAP_VARIABLE */
16236b52a82Sbrezak 
163c97378d0Sjoerg __compactcall void *
alloc(size_t size)1646645a4f3Schristos alloc(size_t size)
16536b52a82Sbrezak {
1661279e67bSaugustss 	struct fl **f = &freelist, **bestf = NULL;
167db898c55Stsutsui 	unsigned int bestsize = 0xffffffff;	/* greater than any real size */
168ea27b7aaScgd 	char *help;
169ea27b7aaScgd 	int failed;
17036b52a82Sbrezak 
171ea27b7aaScgd 	/* scan freelist */
172ea27b7aaScgd 	while (*f) {
1736645a4f3Schristos 		if ((size_t)(*f)->size >= size) {
1746645a4f3Schristos 			if ((size_t)(*f)->size == size) /* exact match */
175ea27b7aaScgd 				goto found;
176ea27b7aaScgd 
177ea27b7aaScgd 			if ((*f)->size < bestsize) {
178ea27b7aaScgd 				/* keep best fit */
179ea27b7aaScgd 				bestf = f;
180ea27b7aaScgd 				bestsize = (*f)->size;
18136b52a82Sbrezak 			}
182ea27b7aaScgd 		}
183ea27b7aaScgd 		f = &((*f)->next);
184ea27b7aaScgd 	}
185ea27b7aaScgd 
186ea27b7aaScgd 	/* no match in freelist if bestsize unchanged */
187ea27b7aaScgd 	failed = (bestsize == 0xffffffff);
188ea27b7aaScgd 
189ea27b7aaScgd 	if (failed) { /* nothing found */
190ea27b7aaScgd 		/*
191ea27b7aaScgd 		 * allocate from heap, keep chunk len in
192ea27b7aaScgd 		 * first word
193ea27b7aaScgd 		 */
194ea27b7aaScgd 		help = top;
195ea27b7aaScgd 
196ea27b7aaScgd 		/* make _sure_ the region can hold a struct fl. */
197ea27b7aaScgd 		if (size < ALIGN(sizeof (struct fl *)))
198ea27b7aaScgd 			size = ALIGN(sizeof (struct fl *));
199db898c55Stsutsui 		top += ALIGN(sizeof(unsigned int)) + ALIGN(size);
200ea27b7aaScgd #ifdef HEAP_LIMIT
201ea27b7aaScgd 		if (top > (char *)HEAP_LIMIT)
202fbe9cca8Sjakllsch 			panic("heap full (%p+%zu)", help, size);
203ea27b7aaScgd #endif
204db898c55Stsutsui 		*(unsigned int *)(void *)help = (unsigned int)ALIGN(size);
205db898c55Stsutsui 		return help + ALIGN(sizeof(unsigned int));
206ea27b7aaScgd 	}
207ea27b7aaScgd 
208ea27b7aaScgd 	/* we take the best fit */
209ea27b7aaScgd 	f = bestf;
210ea27b7aaScgd 
211ea27b7aaScgd found:
212ea27b7aaScgd 	/* remove from freelist */
213049fd5ebSchristos 	help = (char *)(void *)*f;
214ea27b7aaScgd 	*f = (*f)->next;
215db898c55Stsutsui 	return help + ALIGN(sizeof(unsigned int));
21636b52a82Sbrezak }
21736b52a82Sbrezak 
218c97378d0Sjoerg __compactcall void
219049fd5ebSchristos /*ARGSUSED*/
dealloc(void * ptr,size_t size)2206645a4f3Schristos dealloc(void *ptr, size_t size)
22136b52a82Sbrezak {
2221279e67bSaugustss 	struct fl *f =
223db898c55Stsutsui 	    (struct fl *)(void *)((char *)(void *)ptr -
224db898c55Stsutsui 	    ALIGN(sizeof(unsigned int)));
225ea27b7aaScgd #ifdef DEBUG
2261c038e68Sisaki 	if (size > (size_t)f->size) {
227*10497fd2Schristos 		printf("%s: %zu bytes @%p, should be <=%u\n", __func__,
228*10497fd2Schristos 			size, ptr, f->size);
2291c038e68Sisaki 	}
230a8ac47ddSdrochner 
23163930d7dSthorpej 	if (ptr < (void *)HEAP_START)
232*10497fd2Schristos 		printf("%s: %p before start of heap.\n", __func__, ptr);
23363930d7dSthorpej 
23463930d7dSthorpej #ifdef HEAP_LIMIT
23563930d7dSthorpej 	if (ptr > (void *)HEAP_LIMIT)
236*10497fd2Schristos 		printf("%s: %p beyond end of heap.\n", __func__, ptr);
23763930d7dSthorpej #endif
23863930d7dSthorpej #endif /* DEBUG */
239ea27b7aaScgd 	/* put into freelist */
24036b52a82Sbrezak 	f->next = freelist;
24136b52a82Sbrezak 	freelist = f;
24236b52a82Sbrezak }
243