ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
Revision: 1.10
Committed: Tue Nov 13 14:39:05 1990 UTC (33 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.9: +7 -3 lines
Log Message:
added check for zero request

File Contents

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