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