ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/malloc.c
Revision: 1.7
Committed: Tue Oct 2 12:00:03 1990 UTC (33 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.6: +0 -3 lines
Log Message:
made sure malloc(0) doesn't return NULL -- Xlib bug

File Contents

# Content
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 * 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 * just a buffered call to sbrk(2). However, bmalloc will
15 * call mscrounge() if sbrk fails.
16 * mscrounge() returns whatever memory it can find to satisfy the
17 * request along with the number of bytes (modified).
18 *
19 * Greg Ward Lawrence Berkeley Laboratory
20 */
21
22 #include <errno.h>
23
24 #define NULL 0
25
26 #ifndef ALIGN
27 #define ALIGN int /* align type */
28 #endif
29 #define BYTES_WORD sizeof(ALIGN)
30
31 #define MAXINCR (1<<18) /* largest sbrk(2) increment */
32
33 #ifdef NOVMEM
34 #define getpagesize() BYTES_WORD
35 #endif
36 /* malloc free lists */
37 typedef union m_head {
38 union m_head *next;
39 int bucket;
40 ALIGN dummy;
41 } M_HEAD;
42
43 #define FIRSTBUCKET 3
44 #define NBUCKETS 30
45
46 static M_HEAD *free_list[NBUCKETS];
47
48
49 char *
50 mscrounge(np) /* search free lists to satisfy request */
51 register unsigned *np;
52 {
53 char *p;
54 register int bucket;
55 register unsigned bsiz;
56
57 for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
58 bucket < NBUCKETS; bucket++, bsiz <<= 1)
59 if (free_list[bucket] != NULL && bsiz+sizeof(M_HEAD) >= *np) {
60 *np = bsiz+sizeof(M_HEAD);
61 p = (char *)free_list[bucket];
62 free_list[bucket] = free_list[bucket]->next;
63 return(p);
64 }
65 *np = 0;
66 return(NULL);
67 }
68
69
70 char *
71 bmalloc(n) /* allocate a block of n bytes, sans header */
72 register unsigned n;
73 {
74 extern char *sbrk();
75 static unsigned pagesz = 0;
76 static unsigned amnt;
77 static char *bpos;
78 static unsigned nrem;
79 unsigned thisamnt;
80 register char *p;
81
82 if (pagesz == 0) { /* initialize */
83 pagesz = amnt = getpagesize();
84 nrem = (int)sbrk(0); /* page align break */
85 nrem = pagesz - (nrem&(pagesz-1));
86 bpos = sbrk(nrem); /* word aligned! */
87 if ((int)bpos == -1)
88 return(NULL);
89 }
90
91 n = (n+(BYTES_WORD-1))&~(BYTES_WORD-1); /* word align rqst. */
92
93 if (n > nrem) { /* need more core */
94 if (n > amnt) { /* big chunk */
95 thisamnt = (n+(pagesz-1))&~(pagesz-1);
96 if (thisamnt <= MAXINCR) /* increase amnt */
97 amnt = thisamnt;
98 } else
99 thisamnt = amnt;
100 p = sbrk(thisamnt);
101 if ((int)p == -1) { /* uh-oh, ENOMEM */
102 thisamnt = n; /* search free lists */
103 p = mscrounge(&thisamnt);
104 if (p == NULL) /* we're really out */
105 return(NULL);
106 }
107 if (p != bpos+nrem) { /* not an increment */
108 bfree(bpos, nrem); /* free what we have */
109 bpos = p;
110 nrem = thisamnt;
111 } else /* otherwise tack on */
112 nrem += thisamnt;
113 }
114 p = bpos;
115 bpos += n; /* advance */
116 nrem -= n;
117 return(p);
118 }
119
120
121 bfree(p, n) /* free n bytes of random memory */
122 register char *p;
123 register unsigned n;
124 {
125 register int bucket;
126 register unsigned bsiz;
127 /* align pointer */
128 bsiz = BYTES_WORD - ((unsigned)p&(BYTES_WORD-1));
129 if (bsiz < BYTES_WORD) {
130 p += bsiz;
131 n -= bsiz;
132 }
133 /* fill big buckets first */
134 for (bucket = NBUCKETS-1, bsiz = 1<<(NBUCKETS-1);
135 bucket >= FIRSTBUCKET; bucket--, bsiz >>= 1)
136 if (n >= bsiz+sizeof(M_HEAD)) {
137 ((M_HEAD *)p)->next = free_list[bucket];
138 free_list[bucket] = (M_HEAD *)p;
139 p += bsiz+sizeof(M_HEAD);
140 n -= bsiz+sizeof(M_HEAD);
141 }
142 }
143
144
145 char *
146 malloc(n) /* allocate n bytes of memory */
147 unsigned n;
148 {
149 extern int errno;
150 register M_HEAD *mp;
151 register int bucket;
152 register unsigned bsiz;
153 /* find first bucket that fits */
154 for (bucket = FIRSTBUCKET, bsiz = 1<<FIRSTBUCKET;
155 bucket < NBUCKETS; bucket++, bsiz <<= 1)
156 if (bsiz >= n)
157 break;
158 if (bucket >= NBUCKETS) {
159 errno = EINVAL;
160 return(NULL);
161 }
162 if (free_list[bucket] == NULL) { /* need more core */
163 mp = (M_HEAD *)bmalloc(bsiz+sizeof(M_HEAD));
164 if (mp == NULL)
165 return(NULL);
166 } else { /* got it */
167 mp = free_list[bucket];
168 free_list[bucket] = mp->next;
169 }
170 mp->bucket = bucket; /* tag block */
171 return((char *)(mp+1));
172 }
173
174
175 char *
176 realloc(op, n) /* reallocate memory using malloc() */
177 register char *op;
178 unsigned n;
179 {
180 char *p;
181 register unsigned on;
182 /* get old size */
183 if (op != NULL)
184 on = 1 << ((M_HEAD *)op-1)->bucket;
185 else
186 on = 0;
187 if (n <= on && (n > on>>1 || on == 1<<FIRSTBUCKET))
188 return(op); /* same bucket */
189 p = malloc(n);
190 if (p != NULL)
191 #ifdef BSD
192 bcopy(op, p, n>on ? on : n);
193 #else
194 (void)memcpy(p, op, n>on ? on : n);
195 #endif
196 free(op);
197 return(p);
198 }
199
200
201 free(p) /* free memory allocated by malloc */
202 char *p;
203 {
204 register M_HEAD *mp;
205 register int bucket;
206
207 if (p == NULL)
208 return;
209 mp = (M_HEAD *)p - 1;
210 bucket = mp->bucket;
211 mp->next = free_list[bucket];
212 free_list[bucket] = mp;
213 }
214
215
216 #ifndef NOVMEM
217 #ifndef BSD
218 #include <sys/var.h>
219 int
220 getpagesize() /* use SYSV var structure to get page size */
221 {
222 static int pagesz = 0;
223 struct var v;
224
225 if (pagesz == 0) {
226 uvar(&v);
227 pagesz = 1 << v.v_pageshift;
228 }
229 return(pagesz);
230 }
231 #endif
232 #endif