xref: /titanic_50/usr/src/cmd/spell/malloc.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.3	*/
27 #ifdef debug
28 #define ASSERT(p) if(!(p))botch("p");else
29 botch(s)
30 char *s;
31 {
32 	printf("assertion botched: %s\n",s);
33 	abort();
34 }
35 #else
36 #define ASSERT(p)
37 #endif
38 
39 /*	C storage allocator
40  *	circular first-fit strategy
41  *	works with noncontiguous, but monotonically linked, arena
42  *	each block is preceded by a ptr to the (pointer of)
43  *	the next following block
44  *	blocks are exact number of words long
45  *	aligned to the data type requirements of ALIGN
46  *	pointers to blocks must have BUSY bit 0
47  *	bit in ptr is 1 for busy, 0 for idle
48  *	gaps in arena are merely noted as busy blocks
49  *	last block of arena is empty and
50  *	has a pointer to first
51  *	idle blocks are coalesced during space search
52  *
53  *	a different implementation may need to redefine
54  *	ALIGN, NALIGN, BLOCK, BUSY, INT
55  *	where INT is integer type to which a pointer can be cast
56 */
57 #define INT int
58 #define ALIGN int
59 #define NALIGN 1
60 #define WORD sizeof(union store)
61 #define BLOCK 1024
62 #define BUSY 1
63 #define NULL 0
64 #define testbusy(p) ((INT)(p)&BUSY)
65 #define setbusy(p) (union store *)((INT)(p)|BUSY)
66 #define clearbusy(p) (union store *)((INT)(p)&~BUSY)
67 
68 union store {
69 	      union store *ptr;
70 	      ALIGN dummy[NALIGN];
71 	      int calloc;	/*calloc clears an array of integers*/
72 };
73 
74 static	union store alloca;	/* initial arena */
75 static	union store *allocb = &alloca;	/*arena base*/
76 static	union store *allocp = &alloca;	/*search ptr*/
77 static	union store *allocx;	/*for benefit of realloc*/
78 extern	char *sbrk();
79 
80 char *
81 malloc(nbytes)
82 unsigned nbytes;
83 {
84 	register union store *p, *q;
85 	register nw;
86 	register temp;
87 	register union store *r = 0;
88 
89 	nw = (nbytes+WORD+WORD-1)/WORD + 1;	/*need one more than asked for*/
90 	ASSERT(allock(allocp));
91 	for(; ; ) {	/* done at most twice */
92 		p = allocp;
93 		if(alloca.ptr!=0)		/*C can't initialize union*/
94 		for(temp=0; ; ) {
95 			if(!testbusy(p->ptr)) {
96 				while(!testbusy((q=p->ptr)->ptr)) {
97 					ASSERT(q>p);
98 					p->ptr = q->ptr;
99 					allocp = p;
100 				}
101 				if(q>=p+nw && p+nw>=p)
102 					goto found;
103 				r = p;
104 			}
105 			q = p;
106 			p = clearbusy(p->ptr);
107 			if(p <= q) {
108 				ASSERT(p==allocb);
109 				if(p != allocb)
110 					return(NULL);
111 				if(++temp>1)
112 					break;
113 			}
114 		}
115 		temp = nw;
116 		p = (union store *)sbrk(0);
117 		if (r && !testbusy(r->ptr) && r->ptr + 1 == p)
118 			temp -= p - r - 1;
119 		temp = ((temp+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD);
120 		if(p+temp <= p)
121 			return(NULL);
122 		for(; ; ) {
123 			q = (union store *)sbrk(temp*WORD);
124 			if((INT)q != -1)
125 				break;
126 			temp -= (temp-nw+1)/2;
127 			if(temp <= nw)
128 				return(NULL);
129 		}
130 		ialloc((char *)q, (unsigned)temp*WORD);
131 	}
132 found:
133 	allocp = p + nw;
134 	if(q>allocp) {
135 		allocx = allocp->ptr;
136 		allocp->ptr = p->ptr;
137 	}
138 	p->ptr = setbusy(allocp);
139 	return((char *)(p+1));
140 }
141 
142 /*	freeing strategy tuned for LIFO allocation
143 */
144 free(ap)
145 char *ap;
146 {
147 	register union store *p = (union store *)ap;
148 
149 	allocp = --p;
150 	ASSERT(allock(allocp));
151 	ASSERT(testbusy(p->ptr));
152 	p->ptr = clearbusy(p->ptr);
153 	ASSERT(p->ptr > allocp);
154 }
155 
156 /* ialloc(q, nbytes) inserts a block that did not come
157  * from malloc into the arena
158  *
159  * q points to new block
160  * r points to last of new block
161  * p points to last cell of arena before new block
162  * s points to first cell of arena after new block
163 */
164 ialloc(qq, nbytes)
165 char *qq;
166 unsigned nbytes;
167 {
168 	register union store *p, *q, *s;
169 	union store *r;
170 
171 	q = (union store *)qq;
172 	r = q + (nbytes/WORD) - 1;
173 	q->ptr = r;
174 	if(alloca.ptr==0)		/*C can't initialize union*/
175 		alloca.ptr = &alloca;
176 	for(p=allocb; ; p=s) {
177 		s = clearbusy(p->ptr);
178 		if(s==allocb)
179 			break;
180 		ASSERT(s>p);
181 		if(s>r) {
182 			if(p<q)
183 				break;
184 			else
185 				ASSERT(p>r);
186 		}
187 	}
188 	p->ptr = q==p+1? q: setbusy(q);
189 	r->ptr = s==r+1? s: setbusy(s);
190 	if(allocb > q)
191 		allocb = q;
192 	allocp = allocb;
193 }
194 
195 /*	realloc(p, nbytes) reallocates a block obtained from malloc()
196  *	and freed since last call of malloc()
197  *	to have new size nbytes, and old content
198  *	returns new location, or 0 on failure
199 */
200 
201 char *
202 realloc(pp, nbytes)
203 char *pp;
204 unsigned nbytes;
205 {
206 	register union store *q;
207 	register union store *p = (union store *)pp;
208 	union store *s, *t;
209 	register unsigned nw;
210 	unsigned onw;
211 
212 	ASSERT(allock(p-1));
213 	if(testbusy(p[-1].ptr))
214 		free((char *)p);
215 	onw = p[-1].ptr - p;
216 	q = (union store *)malloc(nbytes);
217 	if(q==NULL || q==p)
218 		return((char *)q);
219 	ASSERT(q<p||q>p[-1].ptr);
220 	s = p;
221 	t = q;
222 	nw = (nbytes+WORD-1)/WORD;
223 	if(nw<onw)
224 		onw = nw;
225 	while(onw--!=0)
226 		*t++ = *s++;
227 	ASSERT(clearbusy(q[-1].ptr)-q==nw);
228 	if(q<p && q+nw>=p)
229 		(q+(q+nw-p))->ptr = allocx;
230 	ASSERT(allock(q-1));
231 	return((char *)q);
232 }
233 
234 #ifdef debug
235 allock(q)
236 union store *q;
237 {
238 #ifdef longdebug
239 	register union store *p, *r;
240 	int x;
241 	x = 0;
242 	p = allocb;
243 	if(alloca.ptr==0)
244 		return(1);
245 	for( ; (r=clearbusy(p->ptr)) > p; p=r) {
246 		if(p==q)
247 			x++;
248 	}
249 	return(r==allocb&(x==1|p==q));
250 #else
251 	return(q>=allocb);
252 #endif
253 }
254 #endif
255 
256