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