diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libc/port/malloc.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libc/port/malloc.c')
-rwxr-xr-x | sys/src/libc/port/malloc.c | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/sys/src/libc/port/malloc.c b/sys/src/libc/port/malloc.c new file mode 100755 index 000000000..741316926 --- /dev/null +++ b/sys/src/libc/port/malloc.c @@ -0,0 +1,338 @@ +#include <u.h> +#include <libc.h> +#include <pool.h> +#include <tos.h> + +static void* sbrkalloc(ulong); +static int sbrkmerge(void*, void*); +static void plock(Pool*); +static void punlock(Pool*); +static void pprint(Pool*, char*, ...); +static void ppanic(Pool*, char*, ...); + +typedef struct Private Private; +struct Private { + Lock lk; + int pid; + int printfd; /* gets debugging output if set */ +}; + +Private sbrkmempriv; + +static Pool sbrkmem = { + .name= "sbrkmem", + .maxsize= (3840UL-1)*1024*1024, /* up to ~0xf0000000 */ + .minarena= 4*1024, + .quantum= 32, + .alloc= sbrkalloc, + .merge= sbrkmerge, + .flags= 0, + + .lock= plock, + .unlock= punlock, + .print= pprint, + .panic= ppanic, + .private= &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) +{ + ulong *x; + + n += 2*sizeof(ulong); /* two longs for us */ + x = sbrk(n); + if(x == (void*)-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) +{ + ulong *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); + if(pv->pid != 0) + abort(); + pv->pid = _tos->pid; +} + +static void +punlock(Pool *p) +{ + Private *pv; + pv = p->private; + if(pv->pid != _tos->pid) + abort(); + pv->pid = 0; + unlock(&pv->lk); +} + +static int +checkenv(void) +{ + int n, fd; + char buf[20]; + fd = open("/env/MALLOCFD", OREAD); + if(fd < 0) + return -1; + if((n = read(fd, buf, sizeof buf)) < 0) { + close(fd); + return -1; + } + if(n >= sizeof buf) + n = sizeof(buf)-1; + buf[n] = 0; + n = atoi(buf); + if(n == 0) + n = -1; + return n; +} + +static void +pprint(Pool *p, char *fmt, ...) +{ + va_list v; + Private *pv; + + pv = p->private; + if(pv->printfd == 0) + pv->printfd = checkenv(); + + if(pv->printfd <= 0) + pv->printfd = 2; + + va_start(v, fmt); + vfprint(pv->printfd, fmt, v); + va_end(v); +} + +static char panicbuf[256]; +static void +ppanic(Pool *p, char *fmt, ...) +{ + va_list v; + int n; + char *msg; + Private *pv; + + pv = p->private; + assert(canlock(&pv->lk)==0); + + if(pv->printfd == 0) + pv->printfd = checkenv(); + if(pv->printfd <= 0) + pv->printfd = 2; + + msg = panicbuf; + va_start(v, fmt); + n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg; + write(2, "panic: ", 7); + write(2, msg, n); + write(2, "\n", 1); + if(pv->printfd != 2){ + write(pv->printfd, "panic: ", 7); + write(pv->printfd, msg, n); + write(pv->printfd, "\n", 1); + } + va_end(v); +// unlock(&pv->lk); + 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* +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); + } + 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* +mallocalign(ulong size, ulong align, long offset, ulong span) +{ + void *v; + + v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span); + if(Npadlong && v != nil){ + v = (ulong*)v+Npadlong; + setmalloctag(v, getcallerpc(&size)); + setrealloctag(v, 0); + } + 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, pc); + if(Npadlong <= MallocOffset || v == nil) + return; + u = v; + u[-Npadlong+MallocOffset] = pc; +} + +void +setrealloctag(void *v, ulong pc) +{ + ulong *u; + USED(v, 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]; +} |