1 #ifndef lint 2 static char sccsid[] = "@(#)malloc.c 4.1 (Berkeley) 06/22/83"; 3 #endif 4 #ifdef debug 5 #define ASSERT(p) if(!(p))botch("p");else 6 botch(s) 7 char *s; 8 { 9 printf("assertion botched: %s\n",s); 10 abort(); 11 } 12 #else 13 #define ASSERT(p) 14 #endif 15 16 /* avoid break bug */ 17 #ifdef pdp11 18 #define GRANULE 64 19 #else 20 #define GRANULE 0 21 #endif 22 /* C storage allocator 23 * circular first-fit strategy 24 * works with noncontiguous, but monotonically linked, arena 25 * each block is preceded by a ptr to the (pointer of) 26 * the next following block 27 * blocks are exact number of words long 28 * aligned to the data type requirements of ALIGN 29 * pointers to blocks must have BUSY bit 0 30 * bit in ptr is 1 for busy, 0 for idle 31 * gaps in arena are merely noted as busy blocks 32 * last block of arena (pointed to by alloct) is empty and 33 * has a pointer to first 34 * idle blocks are coalesced during space search 35 * 36 * a different implementation may need to redefine 37 * ALIGN, NALIGN, BLOCK, BUSY, INT 38 * where INT is integer type to which a pointer can be cast 39 */ 40 #define INT int 41 #define ALIGN int 42 #define NALIGN 1 43 #define WORD sizeof(union store) 44 #define BLOCK 1024 /* a multiple of WORD*/ 45 #define BUSY 1 46 #define NULL 0 47 #define testbusy(p) ((INT)(p)&BUSY) 48 #define setbusy(p) (union store *)((INT)(p)|BUSY) 49 #define clearbusy(p) (union store *)((INT)(p)&~BUSY) 50 51 union store { union store *ptr; 52 ALIGN dummy[NALIGN]; 53 int calloc; /*calloc clears an array of integers*/ 54 }; 55 56 static union store allocs[2]; /*initial arena*/ 57 static union store *allocp; /*search ptr*/ 58 static union store *alloct; /*arena top*/ 59 static union store *allocx; /*for benefit of realloc*/ 60 char *sbrk(); 61 62 char * 63 malloc(nbytes) 64 unsigned nbytes; 65 { 66 register union store *p, *q; 67 register nw; 68 static temp; /*coroutines assume no auto*/ 69 70 if(allocs[0].ptr==0) { /*first time*/ 71 allocs[0].ptr = setbusy(&allocs[1]); 72 allocs[1].ptr = setbusy(&allocs[0]); 73 alloct = &allocs[1]; 74 allocp = &allocs[0]; 75 } 76 nw = (nbytes+WORD+WORD-1)/WORD; 77 ASSERT(allocp>=allocs && allocp<=alloct); 78 ASSERT(allock()); 79 for(p=allocp; ; ) { 80 for(temp=0; ; ) { 81 if(!testbusy(p->ptr)) { 82 while(!testbusy((q=p->ptr)->ptr)) { 83 ASSERT(q>p&&q<alloct); 84 p->ptr = q->ptr; 85 } 86 if(q>=p+nw && p+nw>=p) 87 goto found; 88 } 89 q = p; 90 p = clearbusy(p->ptr); 91 if(p>q) 92 ASSERT(p<=alloct); 93 else if(q!=alloct || p!=allocs) { 94 ASSERT(q==alloct&&p==allocs); 95 return(NULL); 96 } else if(++temp>1) 97 break; 98 } 99 temp = ((nw+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD); 100 q = (union store *)sbrk(0); 101 if(q+temp+GRANULE < q) { 102 return(NULL); 103 } 104 q = (union store *)sbrk(temp*WORD); 105 if((INT)q == -1) { 106 return(NULL); 107 } 108 ASSERT(q>alloct); 109 alloct->ptr = q; 110 if(q!=alloct+1) 111 alloct->ptr = setbusy(alloct->ptr); 112 alloct = q->ptr = q+temp-1; 113 alloct->ptr = setbusy(allocs); 114 } 115 found: 116 allocp = p + nw; 117 ASSERT(allocp<=alloct); 118 if(q>allocp) { 119 allocx = allocp->ptr; 120 allocp->ptr = p->ptr; 121 } 122 p->ptr = setbusy(allocp); 123 return((char *)(p+1)); 124 } 125 126 /* freeing strategy tuned for LIFO allocation 127 */ 128 free(ap) 129 register char *ap; 130 { 131 register union store *p = (union store *)ap; 132 133 ASSERT(p>clearbusy(allocs[1].ptr)&&p<=alloct); 134 ASSERT(allock()); 135 allocp = --p; 136 ASSERT(testbusy(p->ptr)); 137 p->ptr = clearbusy(p->ptr); 138 ASSERT(p->ptr > allocp && p->ptr <= alloct); 139 } 140 141 /* realloc(p, nbytes) reallocates a block obtained from malloc() 142 * and freed since last call of malloc() 143 * to have new size nbytes, and old content 144 * returns new location, or 0 on failure 145 */ 146 147 char * 148 realloc(p, nbytes) 149 register union store *p; 150 unsigned nbytes; 151 { 152 register union store *q; 153 union store *s, *t; 154 register unsigned nw; 155 unsigned onw; 156 157 if(testbusy(p[-1].ptr)) 158 free((char *)p); 159 onw = p[-1].ptr - p; 160 q = (union store *)malloc(nbytes); 161 if(q==NULL || q==p) 162 return((char *)q); 163 s = p; 164 t = q; 165 nw = (nbytes+WORD-1)/WORD; 166 if(nw<onw) 167 onw = nw; 168 while(onw--!=0) 169 *t++ = *s++; 170 if(q<p && q+nw>=p) 171 (q+(q+nw-p))->ptr = allocx; 172 return((char *)q); 173 } 174 175 #ifdef debug 176 allock() 177 { 178 #ifdef longdebug 179 register union store *p; 180 int x; 181 x = 0; 182 for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) { 183 if(p==allocp) 184 x++; 185 } 186 ASSERT(p==alloct); 187 return(x==1|p==allocp); 188 #else 189 return(1); 190 #endif 191 } 192 #endif 193