]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/alloc.c
devshr: fixed crash
[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                 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 }