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