]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/alloc.c
merge
[plan9front.git] / sys / src / 9 / 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                 if(!waserror()){
178                         tsleep(&up->sleep, return0, 0, 100);
179                         poperror();
180                 }
181         }
182         if(Npadlong){
183                 v = (ulong*)v+Npadlong;
184                 setmalloctag(v, getcallerpc(&size));
185         }
186         memset(v, 0, size);
187         return v;
188 }
189
190 void*
191 malloc(ulong size)
192 {
193         void *v;
194
195         v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
196         if(v == nil)
197                 return nil;
198         if(Npadlong){
199                 v = (ulong*)v+Npadlong;
200                 setmalloctag(v, getcallerpc(&size));
201                 setrealloctag(v, 0);
202         }
203         memset(v, 0, size);
204         return v;
205 }
206
207 void*
208 mallocz(ulong size, int clr)
209 {
210         void *v;
211
212         v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
213         if(Npadlong && v != nil){
214                 v = (ulong*)v+Npadlong;
215                 setmalloctag(v, getcallerpc(&size));
216                 setrealloctag(v, 0);
217         }
218         if(clr && v != nil)
219                 memset(v, 0, size);
220         return v;
221 }
222
223 void*
224 mallocalign(ulong size, ulong align, long offset, ulong span)
225 {
226         void *v;
227
228         v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
229         if(Npadlong && v != nil){
230                 v = (ulong*)v+Npadlong;
231                 setmalloctag(v, getcallerpc(&size));
232                 setrealloctag(v, 0);
233         }
234         if(v)
235                 memset(v, 0, size);
236         return v;
237 }
238
239 void
240 free(void *v)
241 {
242         if(v != nil)
243                 poolfree(mainmem, (ulong*)v-Npadlong);
244 }
245
246 void*
247 realloc(void *v, ulong size)
248 {
249         void *nv;
250
251         if(v != nil)
252                 v = (ulong*)v-Npadlong;
253         if(Npadlong !=0 && size != 0)
254                 size += Npadlong*sizeof(ulong);
255
256         if(nv = poolrealloc(mainmem, v, size)){
257                 nv = (ulong*)nv+Npadlong;
258                 setrealloctag(nv, getcallerpc(&v));
259                 if(v == nil)
260                         setmalloctag(nv, getcallerpc(&v));
261         }               
262         return nv;
263 }
264
265 ulong
266 msize(void *v)
267 {
268         return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
269 }
270
271 void*
272 calloc(ulong n, ulong szelem)
273 {
274         void *v;
275         if(v = mallocz(n*szelem, 1))
276                 setmalloctag(v, getcallerpc(&n));
277         return v;
278 }
279
280 void
281 setmalloctag(void *v, ulong pc)
282 {
283         ulong *u;
284         USED(v, pc);
285         if(Npadlong <= MallocOffset || v == nil)
286                 return;
287         u = v;
288         u[-Npadlong+MallocOffset] = pc;
289 }
290
291 void
292 setrealloctag(void *v, ulong pc)
293 {
294         ulong *u;
295         USED(v, pc);
296         if(Npadlong <= ReallocOffset || v == nil)
297                 return;
298         u = v;
299         u[-Npadlong+ReallocOffset] = pc;
300 }
301
302 ulong
303 getmalloctag(void *v)
304 {
305         USED(v);
306         if(Npadlong <= MallocOffset)
307                 return ~0;
308         return ((ulong*)v)[-Npadlong+MallocOffset];
309 }
310
311 ulong
312 getrealloctag(void *v)
313 {
314         USED(v);
315         if(Npadlong <= ReallocOffset)
316                 return ((ulong*)v)[-Npadlong+ReallocOffset];
317         return ~0;
318 }