Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <pool.h>
4
#include <tos.h>
5
 
6
static void*	sbrkalloc(ulong);
7
static int		sbrkmerge(void*, void*);
8
static void		plock(Pool*);
9
static void		punlock(Pool*);
10
static void		pprint(Pool*, char*, ...);
11
static void		ppanic(Pool*, char*, ...);
12
 
13
typedef struct Private Private;
14
struct Private {
15
	Lock		lk;
16
	int		pid;
17
	int		printfd;	/* gets debugging output if set */
18
};
19
 
20
Private sbrkmempriv;
21
 
22
static Pool sbrkmem = {
23
	.name=		"sbrkmem",
24
	.maxsize=	(3840UL-1)*1024*1024,	/* up to ~0xf0000000 */
25
	.minarena=	4*1024,
26
	.quantum=	32,
27
	.alloc=		sbrkalloc,
28
	.merge=		sbrkmerge,
29
	.flags=		0,
30
 
31
	.lock=		plock,
32
	.unlock=		punlock,
33
	.print=		pprint,
34
	.panic=		ppanic,
35
	.private=		&sbrkmempriv,
36
};
37
Pool *mainmem = &sbrkmem;
38
Pool *imagmem = &sbrkmem;
39
 
40
/*
41
 * we do minimal bookkeeping so we can tell pool
42
 * whether two blocks are adjacent and thus mergeable.
43
 */
44
static void*
45
sbrkalloc(ulong n)
46
{
47
	ulong *x;
48
 
49
	n += 2*sizeof(ulong);	/* two longs for us */
50
	x = sbrk(n);
51
	if(x == (void*)-1)
52
		return nil;
53
	x[0] = (n+7)&~7;	/* sbrk rounds size up to mult. of 8 */
54
	x[1] = 0xDeadBeef;
55
	return x+2;
56
}
57
 
58
static int
59
sbrkmerge(void *x, void *y)
60
{
61
	ulong *lx, *ly;
62
 
63
	lx = x;
64
	if(lx[-1] != 0xDeadBeef)
65
		abort();
66
 
67
	if((uchar*)lx+lx[-2] == (uchar*)y) {
68
		ly = y;
69
		lx[-2] += ly[-2];
70
		return 1;
71
	}
72
	return 0;
73
}
74
 
75
static void
76
plock(Pool *p)
77
{
78
	Private *pv;
79
	pv = p->private;
80
	lock(&pv->lk);
81
	if(pv->pid != 0)
82
		abort();
83
	pv->pid = _tos->pid;
84
}
85
 
86
static void
87
punlock(Pool *p)
88
{
89
	Private *pv;
90
	pv = p->private;
91
	if(pv->pid != _tos->pid)
92
		abort();
93
	pv->pid = 0;
94
	unlock(&pv->lk);
95
}
96
 
97
static int
98
checkenv(void)
99
{
100
	int n, fd;
101
	char buf[20];
102
	fd = open("/env/MALLOCFD", OREAD);
103
	if(fd < 0)
104
		return -1;
105
	if((n = read(fd, buf, sizeof buf)) < 0) {
106
		close(fd);
107
		return -1;
108
	}
109
	if(n >= sizeof buf)
110
		n = sizeof(buf)-1;
111
	buf[n] = 0;
112
	n = atoi(buf);
113
	if(n == 0)
114
		n = -1;
115
	return n;
116
}
117
 
118
static void
119
pprint(Pool *p, char *fmt, ...)
120
{
121
	va_list v;
122
	Private *pv;
123
 
124
	pv = p->private;
125
	if(pv->printfd == 0)
126
		pv->printfd = checkenv();
127
 
128
	if(pv->printfd <= 0)
129
		pv->printfd = 2;
130
 
131
	va_start(v, fmt);
132
	vfprint(pv->printfd, fmt, v);
133
	va_end(v);
134
}
135
 
136
static char panicbuf[256];
137
static void
138
ppanic(Pool *p, char *fmt, ...) 
139
{
140
	va_list v;
141
	int n;
142
	char *msg;
143
	Private *pv;
144
 
145
	pv = p->private;
146
	assert(canlock(&pv->lk)==0);
147
 
148
	if(pv->printfd == 0)
149
		pv->printfd = checkenv();
150
	if(pv->printfd <= 0)
151
		pv->printfd = 2;
152
 
153
	msg = panicbuf;
154
	va_start(v, fmt);
155
	n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg;
156
	write(2, "panic: ", 7);
157
	write(2, msg, n);
158
	write(2, "\n", 1);
159
	if(pv->printfd != 2){
160
		write(pv->printfd, "panic: ", 7);
161
		write(pv->printfd, msg, n);
162
		write(pv->printfd, "\n", 1);
163
	}
164
	va_end(v);
165
//	unlock(&pv->lk);
166
	abort();
167
}
168
 
169
/* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */
170
/* - except the code for malloc(), which alternately doesn't clear or does. - */
171
 
172
/*
173
 * Npadlong is the number of 32-bit longs to leave at the beginning of 
174
 * each allocated buffer for our own bookkeeping.  We return to the callers
175
 * a pointer that points immediately after our bookkeeping area.  Incoming pointers
176
 * must be decremented by that much, and outgoing pointers incremented.
177
 * The malloc tag is stored at MallocOffset from the beginning of the block,
178
 * and the realloc tag at ReallocOffset.  The offsets are from the true beginning
179
 * of the block, not the beginning the caller sees.
180
 *
181
 * The extra if(Npadlong != 0) in various places is a hint for the compiler to
182
 * compile out function calls that would otherwise be no-ops.
183
 */
184
 
185
/*	non tracing
186
 *
187
enum {
188
	Npadlong	= 0,
189
	MallocOffset = 0,
190
	ReallocOffset = 0,
191
};
192
 *
193
 */
194
 
195
/* tracing */
196
enum {
197
	Npadlong	= 2,
198
	MallocOffset = 0,
199
	ReallocOffset = 1
200
};
201
 
202
void*
203
malloc(ulong size)
204
{
205
	void *v;
206
 
207
	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
208
	if(Npadlong && v != nil) {
209
		v = (ulong*)v+Npadlong;
210
		setmalloctag(v, getcallerpc(&size));
211
		setrealloctag(v, 0);
212
	}
213
	return v;
214
}
215
 
216
void*
217
mallocz(ulong size, int clr)
218
{
219
	void *v;
220
 
221
	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
222
	if(Npadlong && v != nil){
223
		v = (ulong*)v+Npadlong;
224
		setmalloctag(v, getcallerpc(&size));
225
		setrealloctag(v, 0);
226
	}
227
	if(clr && v != nil)
228
		memset(v, 0, size);
229
	return v;
230
}
231
 
232
void*
233
mallocalign(ulong size, ulong align, long offset, ulong span)
234
{
235
	void *v;
236
 
237
	v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
238
	if(Npadlong && v != nil){
239
		v = (ulong*)v+Npadlong;
240
		setmalloctag(v, getcallerpc(&size));
241
		setrealloctag(v, 0);
242
	}
243
	return v;
244
}
245
 
246
void
247
free(void *v)
248
{
249
	if(v != nil)
250
		poolfree(mainmem, (ulong*)v-Npadlong);
251
}
252
 
253
void*
254
realloc(void *v, ulong size)
255
{
256
	void *nv;
257
 
258
	if(size == 0){
259
		free(v);
260
		return nil;
261
	}
262
 
263
	if(v)
264
		v = (ulong*)v-Npadlong;
265
	size += Npadlong*sizeof(ulong);
266
 
267
	if(nv = poolrealloc(mainmem, v, size)){
268
		nv = (ulong*)nv+Npadlong;
269
		setrealloctag(nv, getcallerpc(&v));
270
		if(v == nil)
271
			setmalloctag(nv, getcallerpc(&v));
272
	}		
273
	return nv;
274
}
275
 
276
ulong
277
msize(void *v)
278
{
279
	return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
280
}
281
 
282
void*
283
calloc(ulong n, ulong szelem)
284
{
285
	void *v;
286
	if(v = mallocz(n*szelem, 1))
287
		setmalloctag(v, getcallerpc(&n));
288
	return v;
289
}
290
 
291
void
292
setmalloctag(void *v, ulong pc)
293
{
294
	ulong *u;
295
	USED(v, pc);
296
	if(Npadlong <= MallocOffset || v == nil)
297
		return;
298
	u = v;
299
	u[-Npadlong+MallocOffset] = pc;
300
}
301
 
302
void
303
setrealloctag(void *v, ulong pc)
304
{
305
	ulong *u;
306
	USED(v, pc);
307
	if(Npadlong <= ReallocOffset || v == nil)
308
		return;
309
	u = v;
310
	u[-Npadlong+ReallocOffset] = pc;
311
}
312
 
313
ulong
314
getmalloctag(void *v)
315
{
316
	USED(v);
317
	if(Npadlong <= MallocOffset)
318
		return ~0;
319
	return ((ulong*)v)[-Npadlong+MallocOffset];
320
}
321
 
322
ulong
323
getrealloctag(void *v)
324
{
325
	USED(v);
326
	if(Npadlong <= ReallocOffset)
327
		return ((ulong*)v)[-Npadlong+ReallocOffset];
328
	return ~0;
329
}
330
 
331
void*
332
malloctopoolblock(void *v)
333
{
334
	if(v == nil)
335
		return nil;
336
 
337
	return &((ulong*)v)[-Npadlong];
338
}