📄 pool.c
字号:
if(dsize < 0 || dsize >= 0x80000000UL){ /* for sanity, overflow */ werrstr("invalid allocation size"); return nil; } bsize = dsize2bsize(p, dsize); fb = treelookupgt(p->freeroot, bsize); if(fb == nil) { poolnewarena(p, bsize2asize(p, bsize)); if((fb = treelookupgt(p->freeroot, bsize)) == nil) { /* assume poolnewarena failed and set %r */ return nil; } } ab = trim(p, pooldel(p, fb), dsize); p->curalloc += ab->size; antagonism { memset(B2D(p, ab), 0xDF, dsize); } return B2D(p, ab);}/* poolreallocl: attempt to grow v to ndsize bytes; assumes lock held */static void*poolreallocl(Pool *p, void *v, ulong ndsize){ Alloc *a; Bhdr *left, *right, *newb; Btail *t; ulong nbsize; ulong odsize; ulong obsize; void *nv; if(v == nil) /* for ANSI */ return poolallocl(p, ndsize); if(ndsize == 0) { poolfreel(p, v); return nil; } a = D2B(p, v); blockcheck(p, a); odsize = getdsize(a); obsize = a->size; /* can reuse the same block? */ nbsize = dsize2bsize(p, ndsize); if(nbsize <= a->size) { Returnblock: if(v != _B2D(a)) memmove(_B2D(a), v, odsize); a = trim(p, a, ndsize); p->curalloc -= obsize; p->curalloc += a->size; v = B2D(p, a); return v; } /* can merge with surrounding blocks? */ right = B2NB(a); if(right->magic == FREE_MAGIC && a->size+right->size >= nbsize) { a = blockmerge(p, a, right); goto Returnblock; } t = B2PT(a); left = T2HDR(t); if(left->magic == FREE_MAGIC && left->size+a->size >= nbsize) { a = blockmerge(p, left, a); goto Returnblock; } if(left->magic == FREE_MAGIC && right->magic == FREE_MAGIC && left->size+a->size+right->size >= nbsize) { a = blockmerge(p, blockmerge(p, left, a), right); goto Returnblock; } if((nv = poolallocl(p, ndsize)) == nil) return nil; /* maybe the new block is next to us; if so, merge */ left = T2HDR(B2PT(a)); right = B2NB(a); newb = D2B(p, nv); if(left == newb || right == newb) { if(left == newb || left->magic == FREE_MAGIC) a = blockmerge(p, left, a); if(right == newb || right->magic == FREE_MAGIC) a = blockmerge(p, a, right); assert(a->size >= nbsize); goto Returnblock; } /* enough cleverness */ memmove(nv, v, odsize); antagonism { memset((char*)nv+odsize, 0xDE, ndsize-odsize); } poolfreel(p, v); return nv;}static void*alignptr(void *v, ulong align, long offset){ char *c; ulong off; c = v; if(align){ off = (uintptr)c%align; if(off != offset){ c += offset - off; if(off > offset) c += align; } } return c;}/* poolspanallocl: allocate as described below; assumes pool locked */static void*poolallocalignl(Pool *p, ulong dsize, ulong align, long offset, ulong span){ ulong asize; void *v; char *c; ulong *u; int skip; Alloc *b; /* * allocate block * dsize bytes * addr == offset (modulo align) * does not cross span-byte block boundary * * to satisfy alignment, just allocate an extra * align bytes and then shift appropriately. * * to satisfy span, try once and see if we're * lucky. the second time, allocate 2x asize * so that we definitely get one not crossing * the boundary. */ if(align){ if(offset < 0) offset = align - ((-offset)%align); else offset %= align; } asize = dsize+align; v = poolallocl(p, asize); if(v == nil) return nil; if(span && (uintptr)v/span != ((uintptr)v+asize)/span){ /* try again */ poolfreel(p, v); v = poolallocl(p, 2*asize); if(v == nil) return nil; } /* * figure out what pointer we want to return */ c = alignptr(v, align, offset); if(span && (uintptr)c/span != (uintptr)(c+dsize-1)/span){ c += span - (uintptr)c%span; c = alignptr(c, align, offset); if((uintptr)c/span != (uintptr)(c+dsize-1)/span){ poolfreel(p, v); werrstr("cannot satisfy dsize %lud span %lud with align %lud+%ld", dsize, span, align, offset); return nil; } } skip = c - (char*)v; /* * free up the skip bytes before that pointer * or mark it as unavailable. */ b = _D2B(v); b = freefromfront(p, b, skip); v = _B2D(b); skip = c - (char*)v; if(c > (char*)v){ u = v; while(c >= (char*)u+sizeof(ulong)) *u++ = ALIGN_MAGIC; } trim(p, b, skip+dsize); assert(D2B(p, c) == b); antagonism { memset(c, 0xDD, dsize); } return c;}/* poolfree: free block obtained from poolalloc; assumes lock held */static voidpoolfreel(Pool *p, void *v){ Alloc *ab; Bhdr *back, *fwd; if(v == nil) /* for ANSI */ return; ab = D2B(p, v); blockcheck(p, ab); if(p->flags&POOL_NOREUSE){ int n; ab->magic = DEAD_MAGIC; n = getdsize(ab)-8; if(n > 0) memset((uchar*)v+8, 0xDA, n); return; } p->nfree++; p->curalloc -= ab->size; back = T2HDR(B2PT(ab)); if(back->magic == FREE_MAGIC) ab = blockmerge(p, back, ab); fwd = B2NB(ab); if(fwd->magic == FREE_MAGIC) ab = blockmerge(p, ab, fwd); pooladd(p, ab);}void*poolalloc(Pool *p, ulong n){ void *v; p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } v = poolallocl(p, n); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); LOG(p, "poolalloc %p %lud = %p\n", p, n, v); p->unlock(p); return v;}void*poolallocalign(Pool *p, ulong n, ulong align, long offset, ulong span){ void *v; p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } v = poolallocalignl(p, n, align, offset, span); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); LOG(p, "poolalignspanalloc %p %lud %lud %lud %ld = %p\n", p, n, align, span, offset, v); p->unlock(p); return v;}intpoolcompact(Pool *p){ int rv; p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } rv = poolcompactl(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } LOG(p, "poolcompact %p\n", p); p->unlock(p); return rv;}void*poolrealloc(Pool *p, void *v, ulong n){ void *nv; p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } nv = poolreallocl(p, v, n); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); LOG(p, "poolrealloc %p %p %ld = %p\n", p, v, n, nv); p->unlock(p); return nv;}voidpoolfree(Pool *p, void *v){ p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } poolfreel(p, v); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); LOG(p, "poolfree %p %p\n", p, v); p->unlock(p);}/* * Return the real size of a block, and let the user use it. */ulongpoolmsize(Pool *p, void *v){ Alloc *b; ulong dsize; p->lock(p); paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(v == nil) /* consistency with other braindead ANSI-ness */ dsize = 0; else { b = D2B(p, v); dsize = (b->size&~(p->quantum-1)) - sizeof(Bhdr) - sizeof(Btail); assert(dsize >= getdsize(b)); blocksetdsize(p, b, dsize); } paranoia { poolcheckl(p); } verbosity { pooldumpl(p); } if(p->logstack && (p->flags & POOL_LOGGING)) p->logstack(p); LOG(p, "poolmsize %p %p = %ld\n", p, v, dsize); p->unlock(p); return dsize;}/* * Debugging */static voidpoolcheckarena(Pool *p, Arena *a){ Bhdr *b; Bhdr *atail; atail = A2TB(a); for(b=a; b->magic != ARENATAIL_MAGIC && b<atail; b=B2NB(b)) blockcheck(p, b); blockcheck(p, b); if(b != atail) p->panic(p, "found wrong tail");}static voidpoolcheckl(Pool *p){ Arena *a; for(a=p->arenalist; a; a=a->down) poolcheckarena(p, a); if(p->freeroot) checktree(p->freeroot, 0, 1<<30);}voidpoolcheck(Pool *p){ p->lock(p); poolcheckl(p); p->unlock(p);}voidpoolblockcheck(Pool *p, void *v){ if(v == nil) return; p->lock(p); blockcheck(p, D2B(p, v)); p->unlock(p);}static voidpooldumpl(Pool *p){ Arena *a; p->print(p, "pool %p %s\n", p, p->name); for(a=p->arenalist; a; a=a->down) pooldumparena(p, a);}voidpooldump(Pool *p){ p->lock(p); pooldumpl(p); p->unlock(p);}static voidpooldumparena(Pool *p, Arena *a){ Bhdr *b; for(b=a; b->magic != ARENATAIL_MAGIC; b=B2NB(b)) p->print(p, "(%p %.8lux %lud)", b, b->magic, b->size); p->print(p, "\n");}/* * mark the memory in such a way that we know who marked it * (via the signature) and we know where the marking started. */static voidmemmark(void *v, int sig, ulong size){ uchar *p, *ep; ulong *lp, *elp; lp = v; elp = lp+size/4; while(lp < elp) *lp++ = (sig<<24) ^ ((uintptr)lp-(uintptr)v); p = (uchar*)lp; ep = (uchar*)v+size; while(p<ep) *p++ = sig;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -