From da0a7d7b8f896bc2117ce488c4e245d626ef8aba Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 19 Dec 2008 03:13:39 -0800 Subject: malloc bug fixes. use malloc by default. free stacks. R=r DELTA=424 (333 added, 29 deleted, 62 changed) OCL=21553 CL=21584 --- src/runtime/malloc.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 127 insertions(+), 14 deletions(-) (limited to 'src/runtime/malloc.c') diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c index 6246fa9d52..744e1222b7 100644 --- a/src/runtime/malloc.c +++ b/src/runtime/malloc.c @@ -25,6 +25,10 @@ malloc(uintptr size) MSpan *s; void *v; + if(m->mallocing) + throw("malloc - deadlock"); + m->mallocing = 1; + if(size == 0) size = 1; @@ -35,22 +39,24 @@ malloc(uintptr size) c = m->mcache; v = MCache_Alloc(c, sizeclass, size); if(v == nil) - return nil; + throw("out of memory"); mstats.alloc += size; - return v; + } else { + // TODO(rsc): Report tracebacks for very large allocations. + + // Allocate directly from heap. + npages = size >> PageShift; + if((size & PageMask) != 0) + npages++; + s = MHeap_Alloc(&mheap, npages, 0); + if(s == nil) + throw("out of memory"); + mstats.alloc += npages<start << PageShift); } - // TODO(rsc): Report tracebacks for very large allocations. - - // Allocate directly from heap. - npages = size >> PageShift; - if((size & PageMask) != 0) - npages++; - s = MHeap_Alloc(&mheap, npages, 0); - if(s == nil) - return nil; - mstats.alloc += npages<start << PageShift); + m->mallocing = 0; + return v; } // Free the object whose base pointer is v. @@ -89,6 +95,34 @@ free(void *v) MCache_Free(c, v, sizeclass, size); } +void +mlookup(void *v, byte **base, uintptr *size) +{ + uintptr n, off; + byte *p; + MSpan *s; + + s = MHeap_Lookup(&mheap, (uintptr)v>>PageShift); + if(s == nil) { + *base = nil; + *size = 0; + return; + } + + p = (byte*)((uintptr)s->start<sizeclass == 0) { + // Large object. + *base = p; + *size = s->npages<sizeclass]; + off = ((byte*)v - p)/n * n; + *base = p+off; + *size = n; +} + MCache* allocmcache(void) { @@ -144,6 +178,80 @@ SysFree(void *v, uintptr n) // TODO(rsc): call munmap } +// Runtime stubs. + +extern void *oldmal(uint32); + +void* +mal(uint32 n) +{ +//return oldmal(n); + void *v; + + v = malloc(n); + + if(0) { + byte *p; + int32 i; + p = v; + for(i=0; i %p: byte %d is non-zero\n", n, v, i); + throw("mal"); + } + } + } + +//printf("mal %d %p\n", n, v); // |checkmal to check for overlapping returns. + return v; +} + +// Stack allocator uses malloc/free most of the time, +// but if we're in the middle of malloc and need stack, +// we have to do something else to avoid deadlock. +// In that case, we fall back on a fixed-size free-list +// allocator, assuming that inside malloc all the stack +// frames are small, so that all the stack allocations +// will be a single size, the minimum (right now, 5k). +struct { + Lock; + FixAlloc; +} stacks; + +void* +stackalloc(uint32 n) +{ + void *v; + +//return oldmal(n); + if(m->mallocing) { + lock(&stacks); + if(stacks.size == 0) + FixAlloc_Init(&stacks, n, SysAlloc); + if(stacks.size != n) { + printf("stackalloc: in malloc, size=%D want %d", stacks.size, n); + throw("stackalloc"); + } + v = FixAlloc_Alloc(&stacks); + unlock(&stacks); + return v; + } + return malloc(n); +} + +void +stackfree(void *v) +{ +//return; + + if(m->mallocing) { + lock(&stacks); + FixAlloc_Free(&stacks, v); + unlock(&stacks); + return; + } + free(v); +} // Go function stubs. @@ -160,10 +268,15 @@ malloc·Free(byte *p) free(p); } +void +malloc·Lookup(byte *p, byte *base, uintptr size) +{ + mlookup(p, &base, &size); +} + void malloc·GetStats(MStats *s) { s = &mstats; FLUSH(&s); } - -- cgit v1.3