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