source: trunk/minix/lib/ansi/malloc.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 4.6 KB
Line 
1/* $Header: /cvsup/minix/src/lib/ansi/malloc.c,v 1.1.1.1 2005/04/21 14:56:05 beng Exp $ */
2
3/* replace undef by define */
4#undef DEBUG /* check assertions */
5#undef SLOWDEBUG /* some extra test loops (requires DEBUG) */
6
7#ifndef DEBUG
8#define NDEBUG
9#endif
10
11#include <stdlib.h>
12#include <string.h>
13#include <errno.h>
14#include <assert.h>
15
16#if _EM_WSIZE == _EM_PSIZE
17#define ptrint int
18#else
19#define ptrint long
20#endif
21
22#if _EM_PSIZE == 2
23#define BRKSIZE 1024
24#else
25#define BRKSIZE 4096
26#endif
27#define PTRSIZE ((int) sizeof(void *))
28#define Align(x,a) (((x) + (a - 1)) & ~(a - 1))
29#define NextSlot(p) (* (void **) ((p) - PTRSIZE))
30#define NextFree(p) (* (void **) (p))
31
32/*
33 * A short explanation of the data structure and algorithms.
34 * An area returned by malloc() is called a slot. Each slot
35 * contains the number of bytes requested, but preceeded by
36 * an extra pointer to the next the slot in memory.
37 * '_bottom' and '_top' point to the first/last slot.
38 * More memory is asked for using brk() and appended to top.
39 * The list of free slots is maintained to keep malloc() fast.
40 * '_empty' points the the first free slot. Free slots are
41 * linked together by a pointer at the start of the
42 * user visable part, so just after the next-slot pointer.
43 * Free slots are merged together by free().
44 */
45
46extern void *_sbrk(int);
47extern int _brk(void *);
48static void *_bottom, *_top, *_empty;
49
50static int grow(size_t len)
51{
52 register char *p;
53
54 assert(NextSlot((char *)_top) == 0);
55 if ((char *) _top + len < (char *) _top
56 || (p = (char *)Align((ptrint)_top + len, BRKSIZE)) < (char *) _top ) {
57 errno = ENOMEM;
58 return(0);
59 }
60 if (_brk(p) != 0)
61 return(0);
62 NextSlot((char *)_top) = p;
63 NextSlot(p) = 0;
64 free(_top);
65 _top = p;
66 return 1;
67}
68
69void *
70malloc(size_t size)
71{
72 register char *prev, *p, *next, *new;
73 register unsigned len, ntries;
74
75 if (size == 0)
76 return NULL;
77
78 for (ntries = 0; ntries < 2; ntries++) {
79 if ((len = Align(size, PTRSIZE) + PTRSIZE) < 2 * PTRSIZE) {
80 errno = ENOMEM;
81 return NULL;
82 }
83 if (_bottom == 0) {
84 if ((p = _sbrk(2 * PTRSIZE)) == (char *) -1)
85 return NULL;
86 p = (char *) Align((ptrint)p, PTRSIZE);
87 p += PTRSIZE;
88 _top = _bottom = p;
89 NextSlot(p) = 0;
90 }
91#ifdef SLOWDEBUG
92 for (p = _bottom; (next = NextSlot(p)) != 0; p = next)
93 assert(next > p);
94 assert(p == _top);
95#endif
96 for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
97 next = NextSlot(p);
98 new = p + len; /* easily overflows!! */
99 if (new > next || new <= p)
100 continue; /* too small */
101 if (new + PTRSIZE < next) { /* too big, so split */
102 /* + PTRSIZE avoids tiny slots on free list */
103 NextSlot(new) = next;
104 NextSlot(p) = new;
105 NextFree(new) = NextFree(p);
106 NextFree(p) = new;
107 }
108 if (prev)
109 NextFree(prev) = NextFree(p);
110 else
111 _empty = NextFree(p);
112 return p;
113 }
114 if (grow(len) == 0)
115 break;
116 }
117 assert(ntries != 2);
118 return NULL;
119}
120
121void *
122realloc(void *oldp, size_t size)
123{
124 register char *prev, *p, *next, *new;
125 char *old = oldp;
126 register size_t len, n;
127
128 if (old == 0)
129 return malloc(size);
130 if (size == 0) {
131 free(old);
132 return NULL;
133 }
134 len = Align(size, PTRSIZE) + PTRSIZE;
135 next = NextSlot(old);
136 n = (int)(next - old); /* old length */
137 /*
138 * extend old if there is any free space just behind it
139 */
140 for (prev = 0, p = _empty; p != 0; prev = p, p = NextFree(p)) {
141 if (p > next)
142 break;
143 if (p == next) { /* 'next' is a free slot: merge */
144 NextSlot(old) = NextSlot(p);
145 if (prev)
146 NextFree(prev) = NextFree(p);
147 else
148 _empty = NextFree(p);
149 next = NextSlot(old);
150 break;
151 }
152 }
153 new = old + len;
154 /*
155 * Can we use the old, possibly extended slot?
156 */
157 if (new <= next && new >= old) { /* it does fit */
158 if (new + PTRSIZE < next) { /* too big, so split */
159 /* + PTRSIZE avoids tiny slots on free list */
160 NextSlot(new) = next;
161 NextSlot(old) = new;
162 free(new);
163 }
164 return old;
165 }
166 if ((new = malloc(size)) == NULL) /* it didn't fit */
167 return NULL;
168 memcpy(new, old, n); /* n < size */
169 free(old);
170 return new;
171}
172
173void
174free(void *ptr)
175{
176 register char *prev, *next;
177 char *p = ptr;
178
179 if (p == 0)
180 return;
181
182 assert(NextSlot(p) > p);
183 for (prev = 0, next = _empty; next != 0; prev = next, next = NextFree(next))
184 if (p < next)
185 break;
186 NextFree(p) = next;
187 if (prev)
188 NextFree(prev) = p;
189 else
190 _empty = p;
191 if (next) {
192 assert(NextSlot(p) <= next);
193 if (NextSlot(p) == next) { /* merge p and next */
194 NextSlot(p) = NextSlot(next);
195 NextFree(p) = NextFree(next);
196 }
197 }
198 if (prev) {
199 assert(NextSlot(prev) <= p);
200 if (NextSlot(prev) == p) { /* merge prev and p */
201 NextSlot(prev) = NextSlot(p);
202 NextFree(prev) = NextFree(p);
203 }
204 }
205}
Note: See TracBrowser for help on using the repository browser.