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
botch(s)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 *
malloc(nbytes)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 */
free(ap)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 */
ialloc(qq,nbytes)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 *
realloc(pp,nbytes)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