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 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 * 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 */ 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 */ 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 * 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