#include <9pm/u.h>
#include <9pm/libc.h>
#include <9pm/pool.h>
#include "dat.h"
#include "fns.h"
static void* sbrkalloc(ulong);
static int sbrkmerge(void*, void*);
static void plock(Pool*);
static void punlock(Pool*);
static void mpprint(Pool*, char*, ...);
static void ppanic(Pool*, char*, ...);
typedef struct Private Private;
struct Private {
Lock lk;
};
Private sbrkmempriv;
static Pool sbrkmem = {
"sbrkmem",
2UL*1024*1024*1024,
0,
0,
0,
4*1024,
32,
0,
0,
0,
sbrkalloc,
sbrkmerge,
0,
0,
0,
0,
plock,
punlock,
mpprint,
ppanic,
0,
&sbrkmempriv
};
Pool *mainmem = &sbrkmem;
Pool *imagmem = &sbrkmem;
/*
* we do minimal bookkeeping so we can tell pool
* whether two blocks are adjacent and thus mergeable.
*/
static void*
sbrkalloc(ulong n)
{
long *x;
n += 8; /* two longs for us */
x = sbrk(n);
if((int)x == -1)
return nil;
x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */
x[1] = 0xDeadBeef;
return x+2;
}
static int
sbrkmerge(void *x, void *y)
{
long *lx, *ly;
lx = x;
if(lx[-1] != 0xDeadBeef)
abort();
if((uchar*)lx+lx[-2] == (uchar*)y) {
ly = y;
lx[-2] += ly[-2];
return 1;
}
return 0;
}
static void
plock(Pool *p)
{
Private *pv;
pv = p->private;
lock(&pv->lk);
}
static void
punlock(Pool *p)
{
Private *pv;
pv = p->private;
unlock(&pv->lk);
}
static void
mpprint(Pool *p, char *fmt, ...)
{
va_list v;
char buf[128];
char *msg;
Private *pv;
pv = p->private;
msg = buf;
va_start(v, fmt);
doprint(buf, buf+sizeof buf, fmt, v);
dwrite(buf);
va_end(v);
}
static char panicbuf[256];
static void
ppanic(Pool *p, char *fmt, ...)
{
va_list v;
char *msg;
Private *pv;
pv = p->private;
canlock(&pv->lk);
msg = panicbuf;
va_start(v, fmt);
doprint(msg, msg+sizeof panicbuf, fmt, v);
va_end(v);
panic(msg);
abort();
}
/* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */
/* - except the code for malloc(), which alternately doesn't clear or does. - */
/*
* Npadlong is the number of 32-bit longs to leave at the beginning of
* each allocated buffer for our own bookkeeping. We return to the callers
* a pointer that points immediately after our bookkeeping area. Incoming pointers
* must be decremented by that much, and outgoing pointers incremented.
* The malloc tag is stored at MallocOffset from the beginning of the block,
* and the realloc tag at ReallocOffset. The offsets are from the true beginning
* of the block, not the beginning the caller sees.
*
* The extra if(Npadlong != 0) in various places is a hint for the compiler to
* compile out function calls that would otherwise be no-ops.
*/
/* non tracing
*
enum {
Npadlong = 0,
MallocOffset = 0,
ReallocOffset = 0,
};
*
*/
/* tracing */
enum {
Npadlong = 2,
MallocOffset = 0,
ReallocOffset = 1
};
void*
smalloc(ulong size)
{
void *v;
for(;;) {
v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
if(v != nil)
break;
rendtsleep(&up->sleep, return0, 0, 100);
}
if(Npadlong){
v = (ulong*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
}
memset(v, 0, size);
return v;
}
void*
malloc(ulong size)
{
void *v;
v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
if(Npadlong && v != nil) {
v = (ulong*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
if(v != nil)
memset(v, 0, size);
return v;
}
void*
mallocz(ulong size, int clr)
{
void *v;
v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
if(Npadlong && v != nil){
v = (ulong*)v+Npadlong;
setmalloctag(v, getcallerpc(&size));
setrealloctag(v, 0);
}
if(clr && v != nil)
memset(v, 0, size);
return v;
}
void
free(void *v)
{
if(v != nil)
poolfree(mainmem, (ulong*)v-Npadlong);
}
void*
realloc(void *v, ulong size)
{
void *nv;
if(size == 0){
free(v);
return nil;
}
if(v)
v = (ulong*)v-Npadlong;
size += Npadlong*sizeof(ulong);
if(nv = poolrealloc(mainmem, v, size)){
nv = (ulong*)nv+Npadlong;
setrealloctag(nv, getcallerpc(&v));
if(v == nil)
setmalloctag(nv, getcallerpc(&v));
}
return nv;
}
ulong
msize(void *v)
{
return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
}
void*
calloc(ulong n, ulong szelem)
{
void *v;
if(v = mallocz(n*szelem, 1))
setmalloctag(v, getcallerpc(&n));
return v;
}
void
setmalloctag(void *v, ulong pc)
{
ulong *u;
USED(v);
USED(pc);
if(Npadlong <= MallocOffset || v == nil)
return;
u = v;
u[-Npadlong+MallocOffset] = pc;
}
void
setrealloctag(void *v, ulong pc)
{
ulong *u;
USED(v);
USED(pc);
if(Npadlong <= ReallocOffset || v == nil)
return;
u = v;
u[-Npadlong+ReallocOffset] = pc;
}
ulong
getmalloctag(void *v)
{
USED(v);
if(Npadlong <= MallocOffset)
return ~0;
return ((ulong*)v)[-Npadlong+MallocOffset];
}
ulong
getrealloctag(void *v)
{
USED(v);
if(Npadlong <= ReallocOffset)
return ((ulong*)v)[-Npadlong+ReallocOffset];
return ~0;
}
void*
malloctopoolblock(void *v)
{
if(v == nil)
return nil;
return &((ulong*)v)[-Npadlong];
}
syntax highlighted by Code2HTML, v. 0.9.1