1: static char *sccsid = "@(#)alloc.c 4.1 10/9/80";
2:
3: #include "sh.local.h"
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: #ifdef V6
170: copy(t++, s++, sizeof (*t));
171: #else
172: *t++ = *s++;
173: #endif
174: if(q<p && q+nw>=p)
175: (q+(q+nw-p))->ptr = allocx;
176: return((char *)q);
177: }
178:
179: #ifdef debug
180: allock()
181: {
182: #ifdef longdebug
183: register union store *p;
184: int x;
185: x = 0;
186: for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) {
187: if(p==allocp)
188: x++;
189: }
190: ASSERT(p==alloct);
191: return(x==1|p==allocp);
192: #else
193: return(1);
194: #endif
195: }
196: #endif
197:
198: #ifdef debug
199: showall(v)
200: char **v;
201: {
202: register union store *p, *q;
203: int used = 0, free = 0, i;
204:
205: for (p = clearbusy(allocs[1].ptr); p != alloct; p = q) {
206: q = clearbusy(p->ptr);
207: if (v[1])
208: printf("%6o %5d %s\n", p,
209: ((unsigned) q - (unsigned) p),
210: testbusy(p->ptr) ? "BUSY" : "FREE");
211: i = ((unsigned) q - (unsigned) p);
212: if (testbusy(p->ptr)) used += i; else free += i;
213: }
214: printf("%d used, %d free, %l end\n", used, free, clearbusy(alloct));
215: }
216: #endif
Defined functions
botch
defined in line
6; used 1 times
free
defined in line
128; used 5 times
Defined variables
allocp
defined in line
57; used 14 times
allocs
defined in line
56; used 14 times
alloct
defined in line
58; used 19 times
sccsid
defined in line
1;
never used
Defined union's
store
defined in line
51; used 32 times
Defined macros
ALIGN
defined in line
41; used 1 times
ASSERT
defined in line
13; used 11 times
BLOCK
defined in line
44; used 3 times
BUSY
defined in line
45; used 3 times
INT
defined in line
40; used 4 times
NULL
defined in line
46; used 4 times
WORD
defined in line
43; used 9 times