ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
Revision: 1.12
Committed: Tue Apr 2 09:36:21 1991 UTC (33 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.11: +17 -7 lines
Log Message:
Added magic number for sanity checking

File Contents

# User Rev Content
1 greg 1.12 /* Copyright (c) 1991 Regents of the University of California */
2 greg 1.1
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * Fast malloc for memory hogs and VM environments.
9     * Performs a minimum of searching through free lists.
10 greg 1.4 * malloc(), realloc() and free() use buckets
11     * containing blocks in powers of two, similar to CIT routines.
12     * bfree() puts memory from any source into malloc free lists.
13     * bmalloc() doesn't keep track of free lists -- it's usually
14 greg 1.3 * just a buffered call to sbrk(2). However, bmalloc will
15     * call mscrounge() if sbrk fails.
16 greg 1.8 * mscrounge() returns whatever free memory it can find to satisfy the
17 greg 1.3 * request along with the number of bytes (modified).
18 greg 1.1 *
19     * Greg Ward Lawrence Berkeley Laboratory
20     */
21    
22 greg 1.6 #include <errno.h>
23    
24 greg 1.9 #ifdef MSTATS
25     #include <stdio.h>
26     static unsigned b_nalloced = 0;
27     static unsigned b_nfreed = 0;
28     static unsigned b_nscrounged = 0;
29     static unsigned m_nalloced = 0;
30     static unsigned m_nfreed = 0;
31     static unsigned m_nwasted = 0;
32     #else
33 greg 1.1 #define NULL 0
34 greg 1.9 #endif
35 greg 1.1
36     #ifndef ALIGN
37     #define ALIGN int /* align type */
38     #endif
39     #define BYTES_WORD sizeof(ALIGN)
40    
41 greg 1.9 #define MAXINCR (1<<16) /* largest sbrk(2) increment */
42 greg 1.3
43 greg 1.1 #ifdef NOVMEM
44 greg 1.11 #define getpagesize() 1024
45 greg 1.1 #endif
46     /* malloc free lists */
47     typedef union m_head {
48     union m_head *next;
49 greg 1.12 struct {
50     short magic;
51     short bucket;
52     } a;
53 greg 1.1 ALIGN dummy;
54     } M_HEAD;
55    
56 greg 1.12 #define MAGIC 0x1a2 /* magic number for allocated memory */
57    
58 greg 1.1 #define FIRSTBUCKET 3
59     #define NBUCKETS 30
60    
61     static M_HEAD *free_list[NBUCKETS];
62    
63 greg 1.12 static ALIGN dummy_mem;
64 greg 1.1
65 greg 1.12 #define DUMMYLOC ((char *)&dummy_mem)
66 greg 1.10
67 greg 1.12
68 greg 1.1 char *
69 greg 1.4 mscrounge(np) /* search free lists to satisfy request */
70 greg 1.3 register unsigned *np;
71     {
72     char *p;
73     register int bucket;
74     register unsigned bsiz;
75    
76     for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
77     bucket < NBUCKETS; bucket++, bsiz <<= 1)
78     if (free_list[bucket] != NULL && bsiz+sizeof(M_HEAD) >= *np) {
79     *np = bsiz+sizeof(M_HEAD);
80     p = (char *)free_list[bucket];
81     free_list[bucket] = free_list[bucket]->next;
82 greg 1.9 #ifdef MSTATS
83     b_nscrounged += *np;
84     #endif
85 greg 1.3 return(p);
86     }
87     *np = 0;
88     return(NULL);
89     }
90    
91    
92     char *
93 greg 1.1 bmalloc(n) /* allocate a block of n bytes, sans header */
94     register unsigned n;
95     {
96     extern char *sbrk();
97 greg 1.3 static unsigned pagesz = 0;
98     static unsigned amnt;
99 greg 1.1 static char *bpos;
100 greg 1.3 static unsigned nrem;
101     unsigned thisamnt;
102 greg 1.1 register char *p;
103    
104 greg 1.9 #ifdef MSTATS
105     b_nalloced += n;
106     #endif
107 greg 1.1 if (pagesz == 0) { /* initialize */
108 greg 1.2 pagesz = amnt = getpagesize();
109 greg 1.1 nrem = (int)sbrk(0); /* page align break */
110     nrem = pagesz - (nrem&(pagesz-1));
111     bpos = sbrk(nrem); /* word aligned! */
112     if ((int)bpos == -1)
113     return(NULL);
114     }
115    
116     n = (n+(BYTES_WORD-1))&~(BYTES_WORD-1); /* word align rqst. */
117    
118     if (n > nrem) { /* need more core */
119 greg 1.3 if (n > amnt) { /* big chunk */
120     thisamnt = (n+(pagesz-1))&~(pagesz-1);
121     if (thisamnt <= MAXINCR) /* increase amnt */
122     amnt = thisamnt;
123     } else
124     thisamnt = amnt;
125     p = sbrk(thisamnt);
126 greg 1.4 if ((int)p == -1) { /* uh-oh, ENOMEM */
127 greg 1.3 thisamnt = n; /* search free lists */
128     p = mscrounge(&thisamnt);
129     if (p == NULL) /* we're really out */
130     return(NULL);
131     }
132     if (p != bpos+nrem) { /* not an increment */
133 greg 1.4 bfree(bpos, nrem); /* free what we have */
134 greg 1.1 bpos = p;
135 greg 1.3 nrem = thisamnt;
136 greg 1.4 } else /* otherwise tack on */
137 greg 1.3 nrem += thisamnt;
138 greg 1.1 }
139     p = bpos;
140     bpos += n; /* advance */
141     nrem -= n;
142     return(p);
143     }
144    
145    
146     bfree(p, n) /* free n bytes of random memory */
147 greg 1.2 register char *p;
148     register unsigned n;
149 greg 1.1 {
150     register int bucket;
151     register unsigned bsiz;
152 greg 1.9
153     #ifdef MSTATS
154     b_nfreed += n;
155     #endif
156 greg 1.4 /* align pointer */
157 greg 1.6 bsiz = BYTES_WORD - ((unsigned)p&(BYTES_WORD-1));
158 greg 1.4 if (bsiz < BYTES_WORD) {
159     p += bsiz;
160     n -= bsiz;
161 greg 1.1 }
162 greg 1.4 /* fill big buckets first */
163     for (bucket = NBUCKETS-1, bsiz = 1<<(NBUCKETS-1);
164     bucket >= FIRSTBUCKET; bucket--, bsiz >>= 1)
165     if (n >= bsiz+sizeof(M_HEAD)) {
166     ((M_HEAD *)p)->next = free_list[bucket];
167     free_list[bucket] = (M_HEAD *)p;
168     p += bsiz+sizeof(M_HEAD);
169     n -= bsiz+sizeof(M_HEAD);
170     }
171 greg 1.1 }
172    
173    
174     char *
175     malloc(n) /* allocate n bytes of memory */
176     unsigned n;
177     {
178 greg 1.6 extern int errno;
179 greg 1.1 register M_HEAD *mp;
180     register int bucket;
181     register unsigned bsiz;
182 greg 1.10 /* don't return NULL on 0 request */
183     if (n == 0)
184     return(DUMMYLOC);
185 greg 1.2 /* find first bucket that fits */
186 greg 1.6 for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
187     bucket < NBUCKETS; bucket++, bsiz <<= 1)
188     if (bsiz >= n)
189     break;
190     if (bucket >= NBUCKETS) {
191     errno = EINVAL;
192     return(NULL);
193     }
194 greg 1.9 #ifdef MSTATS
195     m_nalloced += bsiz + sizeof(M_HEAD);
196     m_nwasted += bsiz + sizeof(M_HEAD) - n;
197     #endif
198 greg 1.4 if (free_list[bucket] == NULL) { /* need more core */
199 greg 1.1 mp = (M_HEAD *)bmalloc(bsiz+sizeof(M_HEAD));
200     if (mp == NULL)
201     return(NULL);
202 greg 1.4 } else { /* got it */
203 greg 1.1 mp = free_list[bucket];
204     free_list[bucket] = mp->next;
205     }
206 greg 1.12 mp->a.magic = MAGIC; /* tag block */
207     mp->a.bucket = bucket;
208 greg 1.1 return((char *)(mp+1));
209     }
210    
211    
212     char *
213     realloc(op, n) /* reallocate memory using malloc() */
214 greg 1.6 register char *op;
215 greg 1.1 unsigned n;
216     {
217 greg 1.6 char *p;
218 greg 1.1 register unsigned on;
219 greg 1.6 /* get old size */
220 greg 1.12 if (op != NULL && op != DUMMYLOC && ((M_HEAD *)op-1)->a.magic == MAGIC)
221     on = 1 << ((M_HEAD *)op-1)->a.bucket;
222 greg 1.5 else
223     on = 0;
224 greg 1.6 if (n <= on && (n > on>>1 || on == 1<<FIRSTBUCKET))
225 greg 1.5 return(op); /* same bucket */
226     p = malloc(n);
227     if (p != NULL)
228 greg 1.1 #ifdef BSD
229 greg 1.2 bcopy(op, p, n>on ? on : n);
230 greg 1.1 #else
231 greg 1.2 (void)memcpy(p, op, n>on ? on : n);
232 greg 1.1 #endif
233 greg 1.5 free(op);
234 greg 1.1 return(p);
235     }
236    
237    
238     free(p) /* free memory allocated by malloc */
239     char *p;
240     {
241     register M_HEAD *mp;
242     register int bucket;
243    
244 greg 1.10 if (p == NULL || p == DUMMYLOC)
245 greg 1.2 return;
246 greg 1.1 mp = (M_HEAD *)p - 1;
247 greg 1.12 if (mp->a.magic != MAGIC) /* sanity check */
248     return;
249     bucket = mp->a.bucket;
250 greg 1.1 mp->next = free_list[bucket];
251     free_list[bucket] = mp;
252 greg 1.9 #ifdef MSTATS
253     m_nfreed += (1 << bucket) + sizeof(M_HEAD);
254     #endif
255 greg 1.1 }
256    
257    
258     #ifndef NOVMEM
259     #ifndef BSD
260     #include <sys/var.h>
261     int
262     getpagesize() /* use SYSV var structure to get page size */
263     {
264     struct var v;
265    
266 greg 1.8 uvar(&v);
267     return(1 << v.v_pageshift);
268 greg 1.1 }
269     #endif
270 greg 1.9 #endif
271    
272    
273     #ifdef MSTATS
274     printmemstats(fp) /* print memory statistics to stream */
275     FILE *fp;
276     {
277     register int i;
278     int n;
279     register M_HEAD *mp;
280     unsigned int total = 0;
281    
282     fprintf(fp, "Memory statistics:\n");
283     fprintf(fp, "\tbmalloc: %d bytes allocated\n", b_nalloced);
284     fprintf(fp, "\tbmalloc: %d bytes freed\n", b_nfreed);
285     fprintf(fp, "\tbmalloc: %d bytes scrounged\n", b_nscrounged);
286     fprintf(fp, "\tmalloc: %d bytes allocated\n", m_nalloced);
287     fprintf(fp, "\tmalloc: %d bytes wasted (%.1f%%)\n", m_nwasted,
288     100.0*m_nwasted/m_nalloced);
289     fprintf(fp, "\tmalloc: %d bytes freed\n", m_nfreed);
290     for (i = NBUCKETS-1; i >= FIRSTBUCKET; i--) {
291     n = 0;
292     for (mp = free_list[i]; mp != NULL; mp = mp->next)
293     n++;
294     if (n) {
295     fprintf(fp, "\t%d * %u\n", n, 1<<i);
296     total += n * ((1<<i) + sizeof(M_HEAD));
297     }
298     }
299     fprintf(fp, "\t %u total bytes in free list\n", total);
300     }
301 greg 1.1 #endif