xref: /plan9-contrib/sys/src/9/port/alloc.c (revision 4d44ba9b9ee4246ddbd96c7fcaf0918ab92ab35a)
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->msg[0] = 0;
99 }
100 
101 static void
102 punlock(Pool *p)
103 {
104 	Private *pv;
105 	char msg[sizeof pv->msg];
106 
107 	pv = p->private;
108 	if(pv->msg[0] == 0){
109 		iunlock(&pv->lk);
110 		return;
111 	}
112 
113 	memmove(msg, pv->msg, sizeof msg);
114 	iunlock(&pv->lk);
115 	iprint("%.*s", sizeof pv->msg, msg);
116 }
117 
118 void
119 poolsummary(Pool *p)
120 {
121 	print("%s max %lud cur %lud free %lud alloc %lud\n", p->name,
122 		p->maxsize, p->cursize, p->curfree, p->curalloc);
123 }
124 
125 void
126 mallocsummary(void)
127 {
128 	poolsummary(mainmem);
129 	poolsummary(imagmem);
130 }
131 
132 /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
133 /* - except the code for malloc(), which alternately doesn't clear or does. */
134 /* - except the code for smalloc(), which lives only in the kernel. */
135 
136 /*
137  * Npadlong is the number of 32-bit longs to leave at the beginning of
138  * each allocated buffer for our own bookkeeping.  We return to the callers
139  * a pointer that points immediately after our bookkeeping area.  Incoming pointers
140  * must be decremented by that much, and outgoing pointers incremented.
141  * The malloc tag is stored at MallocOffset from the beginning of the block,
142  * and the realloc tag at ReallocOffset.  The offsets are from the true beginning
143  * of the block, not the beginning the caller sees.
144  *
145  * The extra if(Npadlong != 0) in various places is a hint for the compiler to
146  * compile out function calls that would otherwise be no-ops.
147  */
148 
149 /*	non tracing
150  *
151 enum {
152 	Npadlong	= 0,
153 	MallocOffset = 0,
154 	ReallocOffset = 0,
155 };
156  *
157  */
158 
159 /* tracing */
160 enum {
161 	Npadlong	= 2,
162 	MallocOffset = 0,
163 	ReallocOffset = 1
164 };
165 
166 
167 void*
168 smalloc(ulong size)
169 {
170 	void *v;
171 
172 	for(;;) {
173 		v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
174 		if(v != nil)
175 			break;
176 		tsleep(&up->sleep, return0, 0, 100);
177 	}
178 	if(Npadlong){
179 		v = (ulong*)v+Npadlong;
180 		setmalloctag(v, getcallerpc(&size));
181 	}
182 	memset(v, 0, size);
183 	return v;
184 }
185 
186 void*
187 malloc(ulong size)
188 {
189 	void *v;
190 
191 	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
192 	if(v == nil)
193 		return nil;
194 	if(Npadlong){
195 		v = (ulong*)v+Npadlong;
196 		setmalloctag(v, getcallerpc(&size));
197 		setrealloctag(v, 0);
198 	}
199 	memset(v, 0, size);
200 	return v;
201 }
202 
203 void*
204 mallocz(ulong size, int clr)
205 {
206 	void *v;
207 
208 	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
209 	if(Npadlong && v != nil){
210 		v = (ulong*)v+Npadlong;
211 		setmalloctag(v, getcallerpc(&size));
212 		setrealloctag(v, 0);
213 	}
214 	if(clr && v != nil)
215 		memset(v, 0, size);
216 	return v;
217 }
218 
219 void*
220 mallocalign(ulong size, ulong align, long offset, ulong span)
221 {
222 	void *v;
223 
224 	v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
225 	if(Npadlong && v != nil){
226 		v = (ulong*)v+Npadlong;
227 		setmalloctag(v, getcallerpc(&size));
228 		setrealloctag(v, 0);
229 	}
230 	return v;
231 }
232 
233 void
234 free(void *v)
235 {
236 	if(v != nil)
237 		poolfree(mainmem, (ulong*)v-Npadlong);
238 }
239 
240 void*
241 realloc(void *v, ulong size)
242 {
243 	void *nv;
244 
245 	if(v != nil)
246 		v = (ulong*)v-Npadlong;
247 	if(Npadlong !=0 && size != 0)
248 		size += Npadlong*sizeof(ulong);
249 
250 	if(nv = poolrealloc(mainmem, v, size)){
251 		nv = (ulong*)nv+Npadlong;
252 		setrealloctag(nv, getcallerpc(&v));
253 		if(v == nil)
254 			setmalloctag(nv, getcallerpc(&v));
255 	}
256 	return nv;
257 }
258 
259 ulong
260 msize(void *v)
261 {
262 	return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
263 }
264 
265 void*
266 calloc(ulong n, ulong szelem)
267 {
268 	void *v;
269 	if(v = mallocz(n*szelem, 1))
270 		setmalloctag(v, getcallerpc(&n));
271 	return v;
272 }
273 
274 void
275 setmalloctag(void *v, ulong pc)
276 {
277 	ulong *u;
278 	USED(v, pc);
279 	if(Npadlong <= MallocOffset || v == nil)
280 		return;
281 	u = v;
282 	u[-Npadlong+MallocOffset] = pc;
283 }
284 
285 void
286 setrealloctag(void *v, ulong pc)
287 {
288 	ulong *u;
289 	USED(v, pc);
290 	if(Npadlong <= ReallocOffset || v == nil)
291 		return;
292 	u = v;
293 	u[-Npadlong+ReallocOffset] = pc;
294 }
295 
296 ulong
297 getmalloctag(void *v)
298 {
299 	USED(v);
300 	if(Npadlong <= MallocOffset)
301 		return ~0;
302 	return ((ulong*)v)[-Npadlong+MallocOffset];
303 }
304 
305 ulong
306 getrealloctag(void *v)
307 {
308 	USED(v);
309 	if(Npadlong <= ReallocOffset)
310 		return ((ulong*)v)[-Npadlong+ReallocOffset];
311 	return ~0;
312 }
313