]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/alloc.c
pc kernel: fix wrong simd exception mask (fixes go bootstrap)
[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 static Private psecrpriv;
57 static Pool psecrmem = {
58         .name=  "Secrets",
59         .maxsize=       16*1024*1024,
60         .minarena=      64*1024,
61         .quantum=       32,
62         .alloc= xalloc,
63         .merge= xmerge,
64         .flags= POOL_ANTAGONISM,
65
66         .lock=  plock,
67         .unlock=        punlock,
68         .print= poolprint,
69         .panic= ppanic,
70
71         .private=       &psecrpriv,
72 };
73
74 Pool*   mainmem = &pmainmem;
75 Pool*   imagmem = &pimagmem;
76 Pool*   secrmem = &psecrmem;
77
78 /*
79  * because we can't print while we're holding the locks, 
80  * we have the save the message and print it once we let go.
81  */
82 static void
83 poolprint(Pool *p, char *fmt, ...)
84 {
85         va_list v;
86         Private *pv;
87
88         pv = p->private;
89         va_start(v, fmt);
90         vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
91         va_end(v);
92 }
93
94 static void
95 ppanic(Pool *p, char *fmt, ...)
96 {
97         va_list v;
98         Private *pv;
99         char msg[sizeof pv->msg];
100
101         pv = p->private;
102         va_start(v, fmt);
103         vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
104         va_end(v);
105         memmove(msg, pv->msg, sizeof msg);
106         iunlock(&pv->lk);
107         panic("%s", msg);
108 }
109
110 static void
111 plock(Pool *p)
112 {
113         Private *pv;
114
115         pv = p->private;
116         ilock(&pv->lk);
117         pv->lk.pc = getcallerpc(&p);
118         pv->msg[0] = 0;
119 }
120
121 static void
122 punlock(Pool *p)
123 {
124         Private *pv;
125         char msg[sizeof pv->msg];
126
127         pv = p->private;
128         if(pv->msg[0] == 0){
129                 iunlock(&pv->lk);
130                 return;
131         }
132
133         memmove(msg, pv->msg, sizeof msg);
134         iunlock(&pv->lk);
135         iprint("%.*s", sizeof pv->msg, msg);
136 }
137
138 void
139 poolsummary(Pool *p)
140 {
141         print("%s max %llud cur %llud free %llud alloc %llud\n", p->name,
142                 (uvlong)p->maxsize, (uvlong)p->cursize,
143                 (uvlong)p->curfree, (uvlong)p->curalloc);
144 }
145
146 void
147 mallocsummary(void)
148 {
149         poolsummary(mainmem);
150         poolsummary(imagmem);
151         poolsummary(secrmem);
152 }
153
154 /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
155 /* - except the code for malloc(), which alternately doesn't clear or does. */
156 /* - except the code for smalloc(), which lives only in the kernel. */
157
158 /*
159  * Npadlong is the number of ulong's to leave at the beginning of 
160  * each allocated buffer for our own bookkeeping.  We return to the callers
161  * a pointer that points immediately after our bookkeeping area.  Incoming pointers
162  * must be decremented by that much, and outgoing pointers incremented.
163  * The malloc tag is stored at MallocOffset from the beginning of the block,
164  * and the realloc tag at ReallocOffset.  The offsets are from the true beginning
165  * of the block, not the beginning the caller sees.
166  *
167  * The extra if(Npadlong != 0) in various places is a hint for the compiler to
168  * compile out function calls that would otherwise be no-ops.
169  */
170
171 /*      non tracing
172  *
173 enum {
174         Npadlong        = 0,
175         MallocOffset = 0,
176         ReallocOffset = 0,
177 };
178  *
179  */
180
181 /* tracing */
182 enum {
183         Npadlong        = 2,
184         MallocOffset = 0,
185         ReallocOffset = 1
186 };
187
188
189 void*
190 smalloc(ulong size)
191 {
192         void *v;
193
194         while((v = poolalloc(mainmem, size+Npadlong*sizeof(ulong))) == nil){
195                 if(!waserror()){
196                         resrcwait(nil);
197                         poperror();
198                 }
199         }
200         if(Npadlong){
201                 v = (ulong*)v+Npadlong;
202                 setmalloctag(v, getcallerpc(&size));
203         }
204         memset(v, 0, size);
205         return v;
206 }
207
208 void*
209 malloc(ulong size)
210 {
211         void *v;
212
213         v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
214         if(v == nil)
215                 return nil;
216         if(Npadlong){
217                 v = (ulong*)v+Npadlong;
218                 setmalloctag(v, getcallerpc(&size));
219                 setrealloctag(v, 0);
220         }
221         memset(v, 0, size);
222         return v;
223 }
224
225 void*
226 mallocz(ulong size, int clr)
227 {
228         void *v;
229
230         v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
231         if(Npadlong && v != nil){
232                 v = (ulong*)v+Npadlong;
233                 setmalloctag(v, getcallerpc(&size));
234                 setrealloctag(v, 0);
235         }
236         if(clr && v != nil)
237                 memset(v, 0, size);
238         return v;
239 }
240
241 void*
242 mallocalign(ulong size, ulong align, long offset, ulong span)
243 {
244         void *v;
245
246         v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
247         if(Npadlong && v != nil){
248                 v = (ulong*)v+Npadlong;
249                 setmalloctag(v, getcallerpc(&size));
250                 setrealloctag(v, 0);
251         }
252         if(v)
253                 memset(v, 0, size);
254         return v;
255 }
256
257 void
258 free(void *v)
259 {
260         if(v != nil)
261                 poolfree(mainmem, (ulong*)v-Npadlong);
262 }
263
264 void*
265 realloc(void *v, ulong size)
266 {
267         void *nv;
268
269         if(v != nil)
270                 v = (ulong*)v-Npadlong;
271         if(Npadlong !=0 && size != 0)
272                 size += Npadlong*sizeof(ulong);
273
274         if(nv = poolrealloc(mainmem, v, size)){
275                 nv = (ulong*)nv+Npadlong;
276                 setrealloctag(nv, getcallerpc(&v));
277                 if(v == nil)
278                         setmalloctag(nv, getcallerpc(&v));
279         }               
280         return nv;
281 }
282
283 ulong
284 msize(void *v)
285 {
286         return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
287 }
288
289 /* secret memory, used to back cryptographic keys and cipher states */
290 void*
291 secalloc(ulong size)
292 {
293         void *v;
294
295         while((v = poolalloc(secrmem, size+Npadlong*sizeof(ulong))) == nil){
296                 if(!waserror()){
297                         resrcwait(nil);
298                         poperror();
299                 }
300         }
301         if(Npadlong){
302                 v = (ulong*)v+Npadlong;
303                 setmalloctag(v, getcallerpc(&size));
304                 setrealloctag(v, 0);
305         }
306         memset(v, 0, size);
307         return v;
308 }
309
310 void
311 secfree(void *v)
312 {
313         if(v != nil)
314                 poolfree(secrmem, (ulong*)v-Npadlong);
315 }
316
317 void
318 setmalloctag(void *v, uintptr pc)
319 {
320         USED(v, pc);
321         if(Npadlong <= MallocOffset || v == nil)
322                 return;
323         ((ulong*)v)[-Npadlong+MallocOffset] = (ulong)pc;
324 }
325
326 void
327 setrealloctag(void *v, uintptr pc)
328 {
329         USED(v, pc);
330         if(Npadlong <= ReallocOffset || v == nil)
331                 return;
332         ((ulong*)v)[-Npadlong+ReallocOffset] = (ulong)pc;
333 }
334
335 uintptr
336 getmalloctag(void *v)
337 {
338         USED(v);
339         if(Npadlong <= MallocOffset)
340                 return ~0;
341         return (int)((ulong*)v)[-Npadlong+MallocOffset];
342 }
343
344 uintptr
345 getrealloctag(void *v)
346 {
347         USED(v);
348         if(Npadlong <= ReallocOffset)
349                 return ~0;
350         return (int)((ulong*)v)[-Npadlong+ReallocOffset];
351 }