|
|
1.1 root 1: #ifdef debug
2: #define ASSERT(p,t) if(!(p))return(t(TRASHED));else
3: #else
4: #define ASSERT(p,t)
5: #endif
6:
7: /* avoid break bug */
8: #ifdef pdp11
9: #define GRANULE 64
10: #else
11: #define GRANULE 0
12: #endif
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 (pointed to by alloct) 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 /* a multiple of WORD*/
36: #define BUSY 1
37: #define NULL 0
38: #define TRASHED -1
39: #define testbusy(p) ((INT)(p)&BUSY)
40: #define setbusy(p) (union store *)((INT)(p)|BUSY)
41: #define clearbusy(p) (union store *)((INT)(p)&~BUSY)
42:
43: union store { union store *ptr;
44: ALIGN dummy[NALIGN];
45: int calloc; /*calloc clears an array of integers*/
46: };
47:
48: static union store allocs[2]; /*initial arena*/
49: static union store *allocp; /*search ptr*/
50: static union store *alloct; /*arena top*/
51: static union store *allocx; /*for benefit of realloc*/
52: char *sbrk();
53:
54: char *
55: malloc(nbytes)
56: unsigned nbytes;
57: {
58: register union store *p, *q;
59: register nw;
60: static temp; /*coroutines assume no auto*/
61:
62: if(allocs[0].ptr==0) { /*first time*/
63: allocs[0].ptr = setbusy(&allocs[1]);
64: allocs[1].ptr = setbusy(&allocs[0]);
65: alloct = &allocs[1];
66: allocp = &allocs[0];
67: }
68: nw = (nbytes+WORD+WORD-1)/WORD;
69: ASSERT(allocp>=allocs && allocp<=alloct,(char *));
70: ASSERT(allock(),(char *));
71: for(p=allocp; ; ) {
72: for(temp=0; ; ) {
73: if(!testbusy(p->ptr)) {
74: while(!testbusy((q=p->ptr)->ptr)) {
75: ASSERT(q>p&&q<alloct,(char *));
76: p->ptr = q->ptr;
77: }
78: if(q>=p+nw && p+nw>=p)
79: goto found;
80: }
81: q = p;
82: p = clearbusy(p->ptr);
83: if(p>q)
84: ASSERT(p<=alloct,(char *));
85: else if(q!=alloct || p!=allocs) {
86: ASSERT(q==alloct&&p==allocs,(char *));
87: return(NULL);
88: } else if(++temp>1)
89: break;
90: }
91: temp = ((nw+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD);
92: q = (union store *)sbrk(0);
93: if(q+temp+GRANULE < q) {
94: return(NULL);
95: }
96: q = (union store *)sbrk(temp*WORD);
97: if((INT)q == -1) {
98: return(NULL);
99: }
100: ASSERT(q>alloct,(char *));
101: alloct->ptr = q;
102: if(q!=alloct+1)
103: alloct->ptr = setbusy(alloct->ptr);
104: alloct = q->ptr = q+temp-1;
105: alloct->ptr = setbusy(allocs);
106: }
107: found:
108: allocp = p + nw;
109: ASSERT(allocp<=alloct,(char *));
110: if(q>allocp) {
111: allocx = allocp->ptr;
112: allocp->ptr = p->ptr;
113: }
114: p->ptr = setbusy(allocp);
115: return((char *)(p+1));
116: }
117:
118: /* freeing strategy tuned for LIFO allocation
119: */
120: free(ap)
121: register char *ap;
122: {
123: register union store *p = (union store *)ap;
124:
125: ASSERT(p != 0,(long));
126: ASSERT(p>clearbusy(allocs[1].ptr)&&p<=alloct,(long));
127: ASSERT(allock(),(long));
128: allocp = --p;
129: ASSERT(testbusy(p->ptr),(long));
130: p->ptr = clearbusy(p->ptr);
131: ASSERT(p->ptr > allocp && p->ptr <= alloct,(long));
132: return(NULL);
133: }
134:
135: /* realloc(p, nbytes) reallocates a block obtained from malloc()
136: * and freed since last call of malloc()
137: * to have new size nbytes, and old content
138: * returns new location, or 0 on failure
139: */
140:
141: char *
142: realloc(p, nbytes)
143: register union store *p;
144: unsigned nbytes;
145: {
146: register union store *q;
147: union store *s, *t;
148: register unsigned nw;
149: unsigned onw;
150:
151: if(testbusy(p[-1].ptr))
152: free((char *)p);
153: onw = p[-1].ptr - p;
154: q = (union store *)malloc(nbytes);
155: if(q==NULL || q==p)
156: return((char *)q);
157: s = p;
158: t = q;
159: nw = (nbytes+WORD-1)/WORD;
160: if(nw<onw)
161: onw = nw;
162: while(onw--!=0)
163: *t++ = *s++;
164: if(q<p && q+nw>=p)
165: (q+(q+nw-p))->ptr = allocx;
166: return((char *)q);
167: }
168:
169: #ifdef debug
170: allock()
171: {
172: #ifdef longdebug
173: register union store *p;
174: int x;
175: x = 0;
176: for(p= &allocs[0]; clearbusy(p->ptr) > p; p=clearbusy(p->ptr)) {
177: if(p==allocp)
178: x++;
179: }
180: ASSERT(p==alloct,(long));
181: return(x==1|p==allocp);
182: #else
183: return(1);
184: #endif
185: }
186: #endif
187:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.