FreeBSD/Linux Kernel Cross Reference
sys/port/alloc.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "error.h"
7 #include <pool.h>
8
9 static void poolprint(Pool*, char*, ...);
10 static void ppanic(Pool*, char*, ...);
11 static void plock(Pool*);
12 static void punlock(Pool*);
13
14 typedef struct Private Private;
15 struct Private {
16 Lock lk;
17 char msg[256]; /* a rock for messages to be printed at unlock */
18 };
19
20 static Private pmainpriv;
21 static Pool pmainmem = {
22 .name= "Main",
23 .maxsize= 4*1024*1024,
24 .minarena= 128*1024,
25 .quantum= 32,
26 .alloc= xalloc,
27 .merge= xmerge,
28 .flags= POOL_TOLERANCE,
29
30 .lock= plock,
31 .unlock= punlock,
32 .print= poolprint,
33 .panic= ppanic,
34
35 .private= &pmainpriv,
36 };
37
38 static Private pimagpriv;
39 static Pool pimagmem = {
40 .name= "Image",
41 .maxsize= 16*1024*1024,
42 .minarena= 2*1024*1024,
43 .quantum= 32,
44 .alloc= xalloc,
45 .merge= xmerge,
46 .flags= 0,
47
48 .lock= plock,
49 .unlock= punlock,
50 .print= poolprint,
51 .panic= ppanic,
52
53 .private= &pimagpriv,
54 };
55
56 Pool* mainmem = &pmainmem;
57 Pool* imagmem = &pimagmem;
58
59 /*
60 * because we can't print while we're holding the locks,
61 * we have the save the message and print it once we let go.
62 */
63 static void
64 poolprint(Pool *p, char *fmt, ...)
65 {
66 va_list v;
67 Private *pv;
68
69 pv = p->private;
70 va_start(v, fmt);
71 vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
72 va_end(v);
73 }
74
75 static void
76 ppanic(Pool *p, char *fmt, ...)
77 {
78 va_list v;
79 Private *pv;
80 char msg[sizeof pv->msg];
81
82 pv = p->private;
83 va_start(v, fmt);
84 vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
85 va_end(v);
86 memmove(msg, pv->msg, sizeof msg);
87 iunlock(&pv->lk);
88 panic("%s", msg);
89 }
90
91 static void
92 plock(Pool *p)
93 {
94 Private *pv;
95
96 pv = p->private;
97 ilock(&pv->lk);
98 pv->lk.pc = getcallerpc(&p);
99 pv->msg[0] = 0;
100 }
101
102 static void
103 punlock(Pool *p)
104 {
105 Private *pv;
106 char msg[sizeof pv->msg];
107
108 pv = p->private;
109 if(pv->msg[0] == 0){
110 iunlock(&pv->lk);
111 return;
112 }
113
114 memmove(msg, pv->msg, sizeof msg);
115 iunlock(&pv->lk);
116 iprint("%.*s", sizeof pv->msg, msg);
117 }
118
119 void
120 poolsummary(Pool *p)
121 {
122 print("%s max %lud cur %lud free %lud alloc %lud\n", p->name,
123 p->maxsize, p->cursize, p->curfree, p->curalloc);
124 }
125
126 void
127 mallocsummary(void)
128 {
129 poolsummary(mainmem);
130 poolsummary(imagmem);
131 }
132
133 /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
134 /* - except the code for malloc(), which alternately doesn't clear or does. */
135 /* - except the code for smalloc(), which lives only in the kernel. */
136
137 /*
138 * Npadlong is the number of 32-bit longs to leave at the beginning of
139 * each allocated buffer for our own bookkeeping. We return to the callers
140 * a pointer that points immediately after our bookkeeping area. Incoming pointers
141 * must be decremented by that much, and outgoing pointers incremented.
142 * The malloc tag is stored at MallocOffset from the beginning of the block,
143 * and the realloc tag at ReallocOffset. The offsets are from the true beginning
144 * of the block, not the beginning the caller sees.
145 *
146 * The extra if(Npadlong != 0) in various places is a hint for the compiler to
147 * compile out function calls that would otherwise be no-ops.
148 */
149
150 /* non tracing
151 *
152 enum {
153 Npadlong = 0,
154 MallocOffset = 0,
155 ReallocOffset = 0,
156 };
157 *
158 */
159
160 /* tracing */
161 enum {
162 Npadlong = 2,
163 MallocOffset = 0,
164 ReallocOffset = 1
165 };
166
167
168 void*
169 smalloc(ulong size)
170 {
171 void *v;
172
173 for(;;) {
174 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
175 if(v != nil)
176 break;
177 tsleep(&up->sleep, return0, 0, 100);
178 }
179 if(Npadlong){
180 v = (ulong*)v+Npadlong;
181 setmalloctag(v, getcallerpc(&size));
182 }
183 memset(v, 0, size);
184 return v;
185 }
186
187 void*
188 malloc(ulong size)
189 {
190 void *v;
191
192 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
193 if(v == nil)
194 return nil;
195 if(Npadlong){
196 v = (ulong*)v+Npadlong;
197 setmalloctag(v, getcallerpc(&size));
198 setrealloctag(v, 0);
199 }
200 memset(v, 0, size);
201 return v;
202 }
203
204 void*
205 mallocz(ulong size, int clr)
206 {
207 void *v;
208
209 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
210 if(Npadlong && v != nil){
211 v = (ulong*)v+Npadlong;
212 setmalloctag(v, getcallerpc(&size));
213 setrealloctag(v, 0);
214 }
215 if(clr && v != nil)
216 memset(v, 0, size);
217 return v;
218 }
219
220 void*
221 mallocalign(ulong size, ulong align, long offset, ulong span)
222 {
223 void *v;
224
225 v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
226 if(Npadlong && v != nil){
227 v = (ulong*)v+Npadlong;
228 setmalloctag(v, getcallerpc(&size));
229 setrealloctag(v, 0);
230 }
231 if(v)
232 memset(v, 0, size);
233 return v;
234 }
235
236 void
237 free(void *v)
238 {
239 if(v != nil)
240 poolfree(mainmem, (ulong*)v-Npadlong);
241 }
242
243 void*
244 realloc(void *v, ulong size)
245 {
246 void *nv;
247
248 if(v != nil)
249 v = (ulong*)v-Npadlong;
250 if(Npadlong !=0 && size != 0)
251 size += Npadlong*sizeof(ulong);
252
253 if(nv = poolrealloc(mainmem, v, size)){
254 nv = (ulong*)nv+Npadlong;
255 setrealloctag(nv, getcallerpc(&v));
256 if(v == nil)
257 setmalloctag(nv, getcallerpc(&v));
258 }
259 return nv;
260 }
261
262 ulong
263 msize(void *v)
264 {
265 return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
266 }
267
268 void*
269 calloc(ulong n, ulong szelem)
270 {
271 void *v;
272 if(v = mallocz(n*szelem, 1))
273 setmalloctag(v, getcallerpc(&n));
274 return v;
275 }
276
277 void
278 setmalloctag(void *v, ulong pc)
279 {
280 ulong *u;
281 USED(v, pc);
282 if(Npadlong <= MallocOffset || v == nil)
283 return;
284 u = v;
285 u[-Npadlong+MallocOffset] = pc;
286 }
287
288 void
289 setrealloctag(void *v, ulong pc)
290 {
291 ulong *u;
292 USED(v, pc);
293 if(Npadlong <= ReallocOffset || v == nil)
294 return;
295 u = v;
296 u[-Npadlong+ReallocOffset] = pc;
297 }
298
299 ulong
300 getmalloctag(void *v)
301 {
302 USED(v);
303 if(Npadlong <= MallocOffset)
304 return ~0;
305 return ((ulong*)v)[-Npadlong+MallocOffset];
306 }
307
308 ulong
309 getrealloctag(void *v)
310 {
311 USED(v);
312 if(Npadlong <= ReallocOffset)
313 return ((ulong*)v)[-Npadlong+ReallocOffset];
314 return ~0;
315 }
Cache object: 86dde55b70d1f0f6c73abce839b91fa3
|