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