summaryrefslogtreecommitdiff
path: root/sys/src/libc/port/malloc.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/libc/port/malloc.c338
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];
+}