📄 pool.c
字号:
t = B2T(b); t->size = b->size; t->magic0 = TAIL_MAGIC0; t->magic1 = TAIL_MAGIC1; return b;}/* getdsize: return the requested data size for an allocated block */static ulonggetdsize(Alloc *b){ Btail *t; t = B2T(b); return b->size - SHORT(t->datasize);}/* blocksetdsize: set the user data size of a block */static Alloc*blocksetdsize(Pool *p, Alloc *b, ulong dsize){ Btail *t; uchar *q, *eq; assert(b->size >= dsize2bsize(p, dsize)); assert(b->size - dsize < 0x10000); t = B2T(b); PSHORT(t->datasize, b->size - dsize); q=(uchar*)_B2D(b)+dsize; eq = (uchar*)t; if(eq > q+4) eq = q+4; for(; q<eq; q++) *q = datamagic[((ulong)(uintptr)q)%nelem(datamagic)]; return b;}/* trim: trim a block down to what is needed to hold dsize bytes of user data */static Alloc*trim(Pool *p, Alloc *b, ulong dsize){ ulong extra, bsize; Alloc *frag; bsize = dsize2bsize(p, dsize); extra = b->size - bsize; if(b->size - dsize >= 0x10000 || (extra >= bsize>>2 && extra >= MINBLOCKSIZE && extra >= p->minblock)) { blocksetsize(b, bsize); frag = (Alloc*) B2NB(b); antagonism { memmark(frag, 0xF1, extra); } frag->magic = UNALLOC_MAGIC; blocksetsize(frag, extra); pooladd(p, frag); } b->magic = ALLOC_MAGIC; blocksetdsize(p, b, dsize); return b;}static Alloc*freefromfront(Pool *p, Alloc *b, ulong skip){ Alloc *bb; skip = skip&~(p->quantum-1); if(skip >= 0x1000 || (skip >= b->size>>2 && skip >= MINBLOCKSIZE && skip >= p->minblock)){ bb = (Alloc*)((uchar*)b+skip); blocksetsize(bb, b->size-skip); bb->magic = UNALLOC_MAGIC; blocksetsize(b, skip); b->magic = UNALLOC_MAGIC; pooladd(p, b); return bb; } return b; }/* * Arena maintenance *//* arenasetsize: set arena size, updating tail */static voidarenasetsize(Arena *a, ulong asize){ Bhdr *atail; a->asize = asize; atail = A2TB(a); atail->magic = ARENATAIL_MAGIC; atail->size = 0;}/* poolnewarena: allocate new arena */static voidpoolnewarena(Pool *p, ulong asize){ Arena *a; Arena *ap, *lastap; Alloc *b; LOG(p, "newarena %lud\n", asize); if(p->cursize+asize > p->maxsize) { if(poolcompactl(p) == 0){ LOG(p, "pool too big: %lud+%lud > %lud\n", p->cursize, asize, p->maxsize); werrstr("memory pool too large"); } return; } if((a = p->alloc(asize)) == nil) { /* assume errstr set by p->alloc */ return; } p->cursize += asize; /* arena hdr */ a->magic = ARENA_MAGIC; blocksetsize(a, sizeof(Arena)); arenasetsize(a, asize); blockcheck(p, a); /* create one large block in arena */ b = (Alloc*)A2B(a); b->magic = UNALLOC_MAGIC; blocksetsize(b, (uchar*)A2TB(a)-(uchar*)b); blockcheck(p, b); pooladd(p, b); blockcheck(p, b); /* sort arena into descending sorted arena list */ for(lastap=nil, ap=p->arenalist; ap > a; lastap=ap, ap=ap->down) ; if(a->down = ap) /* assign = */ a->down->aup = a; if(a->aup = lastap) /* assign = */ a->aup->down = a; else p->arenalist = a; /* merge with surrounding arenas if possible */ /* must do a with up before down with a (think about it) */ if(a->aup) arenamerge(p, a, a->aup); if(a->down) arenamerge(p, a->down, a);}/* blockresize: grow a block to encompass space past its end, possibly by *//* trimming it into two different blocks. */static voidblockgrow(Pool *p, Bhdr *b, ulong nsize){ if(b->magic == FREE_MAGIC) { Alloc *a; Bhdr *bnxt; a = pooldel(p, (Free*)b); blockcheck(p, a); blocksetsize(a, nsize); blockcheck(p, a); bnxt = B2NB(a); if(bnxt->magic == FREE_MAGIC) a = blockmerge(p, a, bnxt); blockcheck(p, a); pooladd(p, a); } else { Alloc *a; ulong dsize; a = (Alloc*)b; dsize = getdsize(a); blocksetsize(a, nsize); trim(p, a, dsize); }}/* arenamerge: attempt to coalesce to arenas that might be adjacent */static Arena*arenamerge(Pool *p, Arena *bot, Arena *top){ Bhdr *bbot, *btop; Btail *t; blockcheck(p, bot); blockcheck(p, top); assert(bot->aup == top && top > bot); if(p->merge == nil || p->merge(bot, top) == 0) return nil; /* remove top from list */ if(bot->aup = top->aup) /* assign = */ bot->aup->down = bot; else p->arenalist = bot; /* save ptrs to last block in bot, first block in top */ t = B2PT(A2TB(bot)); bbot = T2HDR(t); btop = A2B(top); blockcheck(p, bbot); blockcheck(p, btop); /* grow bottom arena to encompass top */ arenasetsize(bot, top->asize + ((uchar*)top - (uchar*)bot)); /* grow bottom block to encompass space between arenas */ blockgrow(p, bbot, (uchar*)btop-(uchar*)bbot); blockcheck(p, bbot); return bot;}/* dumpblock: print block's vital stats */static voiddumpblock(Pool *p, Bhdr *b){ ulong *dp; ulong dsize; uchar *cp; dp = (ulong*)b; p->print(p, "pool %s block %p\nhdr %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\n", p->name, b, dp[0], dp[1], dp[2], dp[3], dp[4], dp[5], dp[6]); if(b->size >= 1024*1024*1024) /* tail pointer corrupt; printing tail will fault */ return; dp = (ulong*)B2T(b); p->print(p, "tail %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux | %.8lux %.8lux\n", dp[-6], dp[-5], dp[-4], dp[-3], dp[-2], dp[-1], dp[0], dp[1]); if(b->magic == ALLOC_MAGIC){ dsize = getdsize((Alloc*)b); if(dsize >= b->size) /* user data size corrupt */ return; cp = (uchar*)_B2D(b)+dsize; p->print(p, "user data "); p->print(p, "%.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux", cp[-8], cp[-7], cp[-6], cp[-5], cp[-4], cp[-3], cp[-2], cp[-1]); p->print(p, " | %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux %.2ux\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); }}static voidprintblock(Pool *p, Bhdr *b, char *msg){ p->print(p, "%s\n", msg); dumpblock(p, b);}static voidpanicblock(Pool *p, Bhdr *b, char *msg){ p->print(p, "%s\n", msg); dumpblock(p, b); p->panic(p, "pool panic");}/* blockcheck: ensure a block consistent with our expectations *//* should only be called when holding pool lock */static voidblockcheck(Pool *p, Bhdr *b){ Alloc *a; Btail *t; int i, n; uchar *q, *bq, *eq; ulong dsize; switch(b->magic) { default: panicblock(p, b, "bad magic"); case FREE_MAGIC: case UNALLOC_MAGIC: t = B2T(b); if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) panicblock(p, b, "corrupt tail magic"); if(T2HDR(t) != b) panicblock(p, b, "corrupt tail ptr"); break; case DEAD_MAGIC: t = B2T(b); if(t->magic0 != TAIL_MAGIC0 || t->magic1 != TAIL_MAGIC1) panicblock(p, b, "corrupt tail magic"); if(T2HDR(t) != b) panicblock(p, b, "corrupt tail ptr"); n = getdsize((Alloc*)b); q = _B2D(b); q += 8; for(i=8; i<n; i++) if(*q++ != 0xDA) panicblock(p, b, "dangling pointer write"); break; case ARENA_MAGIC: b = A2TB((Arena*)b); if(b->magic != ARENATAIL_MAGIC) panicblock(p, b, "bad arena size"); /* fall through */ case ARENATAIL_MAGIC: if(b->size != 0) panicblock(p, b, "bad arena tail size"); break; case ALLOC_MAGIC: a = (Alloc*)b; if(a->size > 1024*1024*1024) panicblock(p, b, "block too big"); t = B2T(b); dsize = getdsize(a); bq = (uchar*)_B2D(a)+dsize; eq = (uchar*)t; if(t->magic0 != TAIL_MAGIC0){ /* if someone wrote exactly one byte over and it was a NUL, we sometimes only complain. */ if((p->flags & POOL_TOLERANCE) && bq == eq && t->magic0 == 0) printblock(p, b, "mem user overflow (magic0)"); else panicblock(p, b, "corrupt tail magic0"); } if(t->magic1 != TAIL_MAGIC1) panicblock(p, b, "corrupt tail magic1"); if(T2HDR(t) != b) panicblock(p, b, "corrupt tail ptr"); if(dsize2bsize(p, dsize) > a->size) panicblock(p, b, "too much block data"); if(eq > bq+4) eq = bq+4; for(q=bq; q<eq; q++){ if(*q != datamagic[((uintptr)q)%nelem(datamagic)]){ if(q == bq && *q == 0 && (p->flags & POOL_TOLERANCE)){ printblock(p, b, "mem user overflow"); continue; } panicblock(p, b, "mem user overflow"); } } break; }}/* * compact an arena by shifting all the free blocks to the end. * assumes pool lock is held. */enum { FLOATING_MAGIC = 0xCBCBCBCB, /* temporarily neither allocated nor in the free tree */};static intarenacompact(Pool *p, Arena *a){ Bhdr *b, *wb, *eb, *nxt; int compacted; if(p->move == nil) p->panic(p, "don't call me when pool->move is nil\n"); poolcheckarena(p, a); eb = A2TB(a); compacted = 0; for(b=wb=A2B(a); b && b < eb; b=nxt) { nxt = B2NB(b); switch(b->magic) { case FREE_MAGIC: pooldel(p, (Free*)b); b->magic = FLOATING_MAGIC; break; case ALLOC_MAGIC: if(wb != b) { memmove(wb, b, b->size); p->move(_B2D(b), _B2D(wb)); compacted = 1; } wb = B2NB(wb); break; } } /* * the only free data is now at the end of the arena, pointed * at by wb. all we need to do is set its size and get out. */ if(wb < eb) { wb->magic = UNALLOC_MAGIC; blocksetsize(wb, (uchar*)eb-(uchar*)wb); pooladd(p, (Alloc*)wb); } return compacted; }/* * compact a pool by compacting each individual arena. * 'twould be nice to shift blocks from one arena to the * next but it's a pain to code. */static intpoolcompactl(Pool *pool){ Arena *a; int compacted; if(pool->move == nil || pool->lastcompact == pool->nfree) return 0; pool->lastcompact = pool->nfree; compacted = 0; for(a=pool->arenalist; a; a=a->down) compacted |= arenacompact(pool, a); return compacted;}/*static intpoolcompactl(Pool*){ return 0;}*//* * Actual allocators *//*static void*_B2D(void *a){ return (uchar*)a+sizeof(Bhdr);}*/static void*B2D(Pool *p, Alloc *a){ if(a->magic != ALLOC_MAGIC) p->panic(p, "B2D called on unworthy block"); return _B2D(a);}/*static void*_D2B(void *v){ Alloc *a; a = (Alloc*)((uchar*)v-sizeof(Bhdr)); return a;}*/static Alloc*D2B(Pool *p, void *v){ Alloc *a; ulong *u; if((uintptr)v&(sizeof(ulong)-1)) v = (char*)v - ((uintptr)v&(sizeof(ulong)-1)); u = v; while(u[-1] == ALIGN_MAGIC) u--; a = _D2B(u); if(a->magic != ALLOC_MAGIC) p->panic(p, "D2B called on non-block %p (double-free?)", v); return a;}/* poolallocl: attempt to allocate block to hold dsize user bytes; assumes lock held */static void*poolallocl(Pool *p, ulong dsize){ ulong bsize; Free *fb; Alloc *ab;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -