|
|
1.1 root 1: #include "sam.h"
2: /*
3: * Garbage-compacting allocator
4: *
5: * called as: gcalloc(nbytes, where)
6: * gcrealloc(p, nbytes)
7: * gcfree(p)
8: * nbytes is unsigned long
9: * where is a pointer to the location which will point to the area
10: * (e.g. base in a Bitmap), to be updated when necessary.
11: * The return values for the allocators are the new address,
12: * but since they update *where, the value isn't too useful.
13: * They panic if they fail.
14: */
15:
16: /*
17: * The arena is allocated in longs, to speed up compaction
18: * Garbage is compacted towards the bottom (low address end) of the arena.
19: * A block has a struct header as its bottom HEADERSIZE longs for use by gcfree.
20: * header.pval points to the USER location where the pointer to the block
21: * is stored; this cell must be updated after a compaction.
22: * Deallocated blocks have header.pval odd.
23: */
24:
25: #define BRKINCR (16*1024) /* bytes to add to arena each time */
26: #define LBRKINCR (BRKINCR/sizeof(long))
27: #define FREE 1
28: #define HEADERSIZE sizeof(struct header)/sizeof(long)
29:
30: static long *nextlong;
31: static long *startarena;
32: static long *endarena;
33: static compact();
34: int dontcompact;
35:
36: extern char *brk();
37: extern char *sbrk();
38:
39: struct header{
40: union uuu{
41: long Uival; /* integer value of where */
42: long **Upval; /* where */
43: }u;
44: ulong nlongs; /* # of longs in the user's data */
45: };
46: #define ival u.Uival
47: #define pval u.Upval
48: #define hp ((struct header *)p)
49:
50: uchar *
51: gcalloc(nbytes, where)
52: register ulong nbytes;
53: long **where;
54: {
55: register long *p;
56: register ulong nl;
57: if(nextlong>endarena)
58: panic("nextlong>endarena");
59: if((long)where&FREE) /* head off a possible disaster */
60: panic("where&FREE");
61: if(startarena==0){
62: if((int)(startarena=(long *)sbrk(BRKINCR))==-1)
63: error(Ealloc);
64: endarena=startarena+(BRKINCR/sizeof(long));
65: nextlong=startarena;
66: }
67: nbytes+=sizeof(long)-1;
68: nbytes/=sizeof(long); /* convert bytes to longs */
69: #define Nlongs nbytes
70: Nlongs+=HEADERSIZE;
71: if(endarena-nextlong < Nlongs){
72: if(!dontcompact)
73: compact();
74: if(endarena-nextlong < Nlongs){
75: nl=(nextlong+Nlongs)-startarena;
76: /* if !compacting, avoid greed */
77: if(!dontcompact)
78: nl=((nl+LBRKINCR-1)/LBRKINCR)*LBRKINCR;
79: if(brk((char *)(startarena+nl))!=0)
80: error(Ealloc);
81: endarena=startarena+nl;
82: }
83: }
84: p=nextlong;
85: hp->pval=where;
86: hp->nlongs=Nlongs;
87: nextlong+=Nlongs;
88: return (uchar *)(*(hp->pval)=p+HEADERSIZE);
89: }
90: uchar *
91: gcrealloc(cp, nbytes)
92: uchar *cp;
93: register ulong nbytes;
94: {
95: register long *p=(long *)cp, *q;
96: register long *newp;
97: register long **ptrold;
98: register n;
99: long *x;
100: p-=HEADERSIZE; /* the header */
101: n=hp->nlongs;
102: nbytes+=sizeof(long)-1;
103: nbytes/=sizeof(long); /* convert bytes to longs; nbytes is now Nlongs */
104: ptrold=hp->pval; /* location that will be updated if compaction occurs */
105: /* we give where==x to gcalloc to avoid collision with old header */
106: newp=(long *)gcalloc((ulong)(Nlongs*sizeof(long)), &x);
107: /* now it's safe to have both headers point to the same place */
108: ((struct header *)(newp-HEADERSIZE))->pval=ptrold;
109: p= *ptrold;
110: q=newp;
111: if(n>Nlongs)
112: n=Nlongs;
113: if(n>0) do
114: *q++= *p++;
115: while(--n);
116: (void)gcfree((uchar *)*ptrold);
117: return (uchar *)(*ptrold=newp);
118: }
119: shiftgcarena(nl)
120: ulong nl;
121: {
122: register long *p;
123: if(startarena==0 || dontcompact)
124: return;
125: if(nl<0)
126: panic("shiftgcarena");
127: bcopy((uchar *)startarena, (uchar *)nextlong, (uchar *)(startarena+nl), -1);
128: nextlong+=nl;
129: startarena+=nl;
130: endarena+=nl;
131: for(p=startarena; p<nextlong; p+=hp->nlongs){
132: if((hp->ival&FREE)==0)
133: *(hp->pval)+=nl;
134: }
135: }
136: gcfree(cp)
137: uchar *cp;
138: {
139: register long *p=(long *)cp;
140: if(p==0)
141: return;
142: p-=HEADERSIZE;
143: if(p<startarena || nextlong<=p)
144: panic("gcfree");
145: hp->ival|=FREE;
146: }
147: static
148: compact()
149: {
150: register long *w, *p;
151: register ulong n;
152:
153: w=p=startarena;
154: while(p<nextlong){
155: if(hp->ival&FREE){
156: p+=hp->nlongs;
157: continue;
158: }
159: if(w==p){
160: w+=hp->nlongs;
161: p+=hp->nlongs;
162: continue;
163: }
164: *(hp->pval)=w+HEADERSIZE; /* update *where */
165: *w++=hp->ival;
166: *w++=n=hp->nlongs;
167: p+=HEADERSIZE;
168: if((n-=HEADERSIZE)>0) do
169: *w++ = *p++;
170: while(--n);
171: }
172: nextlong=w;
173: }
174: gcchk()
175: {
176: register long *p;
177: if(startarena==0)
178: return;
179: for(p=startarena; p<nextlong; p+=hp->nlongs)
180: if((hp->ival&FREE)==0){
181: if(hp->pval==0 || ((long *)hp->pval>=startarena && ((int)(hp->pval)&0x70000000L)==0))
182: panic("gcchk 1");
183: if(p+hp->nlongs>nextlong)
184: panic("gcchk 2");
185: }
186: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.