⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pool.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This allocator takes blocks from a coarser allocator (p->alloc) and * uses them as arenas. *  * An arena is split into a sequence of blocks of variable size.  The * blocks begin with a Bhdr that denotes the length (including the Bhdr) * of the block.  An arena begins with an Arena header block (Arena, * ARENA_MAGIC) and ends with a Bhdr block with magic ARENATAIL_MAGIC and * size 0.  Intermediate blocks are either allocated or free.  At the end * of each intermediate block is a Btail, which contains information * about where the block starts.  This is useful for walking backwards. *  * Free blocks (Free*) have a magic value of FREE_MAGIC in their Bhdr * headers.  They are kept in a binary tree (p->freeroot) traversible by * walking ->left and ->right.  Each node of the binary tree is a pointer * to a circular doubly-linked list (next, prev) of blocks of identical * size.  Blocks are added to this ``tree of lists'' by pooladd(), and * removed by pooldel(). *  * When freed, adjacent blocks are coalesced to create larger blocks when * possible. *  * Allocated blocks (Alloc*) have one of two magic values: KEMPT_MAGIC or * UNKEMPT_MAGIC.  When blocks are released from the pool, they have * magic value UNKEMPT_MAGIC.  Once the block has been trimmed by kemb() * and the amount of user-requested data has been recorded in the * datasize field of the tail, the magic value is changed to KEMPT_MAGIC. * All blocks returned to callers should be of type KEMPT_MAGIC, as * should all blocks passed to us by callers.  The amount of data the user * asked us for can be found by subtracting the short in tail->datasize  * from header->size.  Further, the up to at most four bytes between the * end of the user-requested data block and the actual Btail structure are * marked with a magic value, which is checked to detect user overflow. *  * The arenas returned by p->alloc are kept in a doubly-linked list * (p->arenalist) running through the arena headers, sorted by descending * base address (prev, next).  When a new arena is allocated, we attempt * to merge it with its two neighbors via p->merge. */#include <u.h>#include <libc.h>#include <pool.h>typedef struct Alloc	Alloc;typedef struct Arena	Arena;typedef struct Bhdr	Bhdr;typedef struct Btail	Btail;typedef struct Free	Free;struct Bhdr {	ulong	magic;	ulong	size;};enum {	NOT_MAGIC = 0xdeadfa11,};#define B2NB(b) ((Bhdr*)((uchar*)(b)+(b)->size))#define SHORT(x) (((x)[0] << 8) | (x)[1])#define PSHORT(p, x) \	(((uchar*)(p))[0] = ((x)>>8)&0xFF, \	((uchar*)(p))[1] = (x)&0xFF)enum {	TAIL_MAGIC0 = 0xBE,	TAIL_MAGIC1 = 0xEF};struct Btail {	uchar	magic0;	uchar	datasize[2];	uchar	magic1;	ulong	size;	/* same as Bhdr->size */};#define B2T(b)	((Btail*)((uchar*)(b)+(b)->size-sizeof(Btail)))#define B2PT(b) ((Btail*)((uchar*)(b)-sizeof(Btail)))#define T2HDR(t) ((Bhdr*)((uchar*)(t)+sizeof(Btail)-(t)->size))struct Free {			Bhdr;	Free*	left;	Free*	right;	Free*	next;	Free*	prev;};enum {	FREE_MAGIC = 0xBA5EBA11,};/* * the point of the notused fields is to make 8c differentiate * between Bhdr and Allocblk, and between Kempt and Unkempt. */struct Alloc {			Bhdr;};enum {	KEMPT_MAGIC = 0x0A110C09,	UNKEMPT_MAGIC = 0xCAB00D1E+1,};struct Arena {			Bhdr;	Arena*	aup;	Arena*	down;	ulong	asize;	ulong	pad;	/* to a multiple of 8 bytes */};enum {	ARENA_MAGIC = 0xC0A1E5CE+1,	ARENATAIL_MAGIC = 0xEC5E1A0C+1,};#define A2TB(a)	((Bhdr*)((uchar*)(a)+(a)->asize-sizeof(Bhdr)))#define A2B(a)	B2NB(a)enum {	MINBLOCKSIZE = sizeof(Free)+sizeof(Btail)};static uchar datamagic[] = { 0xFE, 0xF1, 0xF0, 0xFA };#define	Poison	(void*)0xCafeBabe#define _B2D(a)	((void*)((uchar*)a+sizeof(Bhdr)))#define _D2B(v)	((Alloc*)((uchar*)v-sizeof(Bhdr)))// static void*	_B2D(void*);// static void*	_D2B(void*);static void*	B2D(Pool*, Alloc*);static Alloc*	D2B(Pool*, void*);static Arena*	arenamerge(Pool*, Arena*, Arena*);static void		blockcheck(Pool*, Bhdr*);static Alloc*	blockmerge(Pool*, Bhdr*, Bhdr*);static Alloc*	blocksetdsize(Pool*, Alloc*, ulong);static Bhdr*	blocksetsize(Bhdr*, ulong);static ulong	bsize2asize(Pool*, ulong);static ulong	dsize2bsize(Pool*, ulong);static ulong	getdsize(Alloc*);static Alloc*	kemb(Pool*, Alloc*, ulong);static Free*	listadd(Free*, Free*);static Free*	listdelete(Free*, Free*);static void		logstack(Pool*);static Free**	ltreewalk(Free**, ulong);static void		memmark(void*, int, ulong);static Free*	pooladd(Pool*, Alloc*);static void*	poolallocl(Pool*, ulong);static void		poolcheckl(Pool*);static void		poolcheckarena(Pool*, Arena*);static int		poolcompactl(Pool*);static Alloc*	pooldel(Pool*, Free*);static void		pooldumpl(Pool*);static void		pooldumparena(Pool*, Arena*);static void		poolfreel(Pool*, void*);static void		poolnewarena(Pool*, ulong);static void*	poolreallocl(Pool*, void*, ulong);static Free*	treedelete(Free*, Free*);static Free*	treeinsert(Free*, Free*);static Free*	treelookup(Free*, ulong);static Free*	treelookupgt(Free*, ulong);/* * Debugging *  * Antagonism causes blocks to always be filled with garbage if their * contents are undefined.  This tickles both programs and the library. * It's a linear time hit but not so noticeable during nondegenerate use. * It would be worth leaving in except that it negates the benefits of the * kernel's demand-paging.  The tail magic and end-of-data magic  * provide most of the user-visible benefit that antagonism does anyway. * * Paranoia causes the library to recheck the entire pool on each lock * or unlock.  A failed check on unlock means we tripped over ourselves, * while a failed check on lock tends to implicate the user.  Paranoia has * the potential to slow things down a fair amount for pools with large * numbers of allocated blocks.  It completely negates all benefits won * by the binary tree.  Turning on paranoia in the kernel makes it painfully * slow. * * Verbosity induces the dumping of the pool via p->print at each lock operation. * By default, only one line is logged for each alloc, free, and realloc. *//* the if(!x);else avoids ``dangling else'' problems */#define antagonism	if(!(p->flags & POOL_ANTAGONISM));else#define paranoia	if(!(p->flags & POOL_PARANOIA));else#define verbosity	if(!(p->flags & POOL_VERBOSITY));else#define DPRINT	if(!(p->flags & POOL_DEBUGGING));else p->print#define LOG		if(!(p->flags & POOL_LOGGING));else p->print/* * Tree walking *//* ltreewalk: return address of pointer to node of size == size */static Free**ltreewalk(Free **t, ulong size){	assert(t != nil /* ltreewalk */);	for(;;) {		if(*t == nil)			return t;		assert((*t)->magic == FREE_MAGIC);		if(size == (*t)->size)			return t;		if(size < (*t)->size)			t = &(*t)->left;		else			t = &(*t)->right;	}	return nil;	/* not reached */}/* treelookup: find node in tree with size == size */static Free*treelookup(Free *t, ulong size){	return *ltreewalk(&t, size);}/* treeinsert: insert node into tree */static Free*treeinsert(Free *tree, Free *node){	Free **loc, *repl;	assert(node != nil /* treeinsert */);	loc = ltreewalk(&tree, node->size);	if(*loc == nil) {		node->left = nil;		node->right = nil;	} else {	/* replace existing node */		repl = *loc;		node->left = repl->left;		node->right = repl->right;	}	*loc = node;	return tree;}/* treedelete: remove node from tree */static Free*treedelete(Free *tree, Free *node){	Free **loc, **lsucc, *succ;	assert(node != nil /* treedelete */);	loc = ltreewalk(&tree, node->size);	assert(*loc == node);	if(node->left == nil)		*loc = node->right;	else if(node->right == nil)		*loc = node->left;	else {		/* have two children, use inorder successor as replacement */		for(lsucc = &node->right; (*lsucc)->left; lsucc = &(*lsucc)->left)			;		succ = *lsucc;		*lsucc = succ->right;		succ->left = node->left;		succ->right = node->right;		*loc = succ;	}	node->left = node->right = Poison;	return tree;}/* treelookupgt: find smallest node in tree with size >= size */static Free*treelookupgt(Free *t, ulong size){	Free *lastgood;	/* last node we saw that was big enough */	lastgood = nil;	for(;;) {		if(t == nil)			return lastgood;		if(size == t->size)			return t;		if(size < t->size) {			lastgood = t;			t = t->left;		} else {			t = t->right;		}	}	return nil;	/* not reached */}/*  * List maintenance *//* listadd: add a node to a doubled linked list */static Free*listadd(Free *list, Free *node){	if(list == nil) {		node->next = node;		node->prev = node;		return node;	}	node->prev = list->prev;	node->next = list;	node->prev->next = node;	node->next->prev = node;	return list;}/* listdelete: remove node from a doubly linked list */static Free*listdelete(Free *list, Free *node){	if(node->next == node) {	/* singular list */		node->prev = node->next = Poison;		return nil;	}	node->next->prev = node->prev;	node->prev->next = node->next;	if(list == node)		list = node->next;	node->prev = node->next = Poison;	return list;}/* * Pool maintenance *//* pooladd: add anode to the free pool */static Free*pooladd(Pool *p, Alloc *anode){	Free *lst, *olst;	Free *node;	Free **parent;	antagonism {		memmark(_B2D(anode), 0xF7, anode->size-sizeof(Bhdr)-sizeof(Btail));	}	node = (Free*)anode;	node->magic = FREE_MAGIC;	parent = ltreewalk(&p->freeroot, node->size);	olst = *parent;	lst = listadd(olst, node);	if(olst != lst)	/* need to update tree */		*parent = treeinsert(*parent, lst);	p->curfree += node->size;	return node;}/* pooldel: remove node from the free pool */static Alloc*pooldel(Pool *p, Free *node){	Free *lst, *olst;	Free **parent;	parent = ltreewalk(&p->freeroot, node->size);	olst = *parent;	assert(olst != nil /* pooldel */);	lst = listdelete(olst, node);	if(lst == nil)		*parent = treedelete(*parent, olst);	else if(lst != olst)		*parent = treeinsert(*parent, lst);	node->left = node->right = Poison;	p->curfree -= node->size;	antagonism {		memmark(_B2D(node), 0xF9, node->size-sizeof(Bhdr)-sizeof(Btail));	}	node->magic = UNKEMPT_MAGIC;	return (Alloc*)node;}/* * Block maintenance  *//* block allocation */static ulongdsize2bsize(Pool *p, ulong sz){	sz += sizeof(Bhdr)+sizeof(Btail);	if(sz < p->minblock)		sz = p->minblock;	sz = (sz+p->quantum-1)&~(p->quantum-1);	return sz;}static ulongbsize2asize(Pool *p, ulong sz){	sz += sizeof(Arena)+sizeof(Btail);	if(sz < p->minarena)		sz = p->minarena;	sz = (sz+p->quantum)&~(p->quantum-1);	return sz;}/* blockmerge: merge a and b, known to be adjacent *//* both are removed from pool if necessary. */static Alloc*blockmerge(Pool *pool, Bhdr *a, Bhdr *b){	Btail *t;	assert(B2NB(a) == b);	if(a->magic == FREE_MAGIC)		pooldel(pool, (Free*)a);	if(b->magic == FREE_MAGIC)		pooldel(pool, (Free*)b);	t = B2T(a);	t->size = (ulong)Poison;	t->magic0 = NOT_MAGIC;	t->magic1 = NOT_MAGIC;	PSHORT(t->datasize, NOT_MAGIC);	a->size += b->size;	t = B2T(a);	t->size = a->size;	PSHORT(t->datasize, 0xFFFF);	b->size = NOT_MAGIC;	b->magic = NOT_MAGIC;	a->magic = UNKEMPT_MAGIC;	return (Alloc*)a;}/* blocksetsize: set the total size of a block, fixing tail pointers */static Bhdr*blocksetsize(Bhdr *b, ulong bsize){	Btail *t;	assert(b->magic != FREE_MAGIC /* blocksetsize */);	b->size = bsize;	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)q)%nelem(datamagic)];	return b;}/* kemb: trim a block down to what is needed to hold dsize bytes of user data */static Alloc*kemb(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 = UNKEMPT_MAGIC;		blocksetsize(frag, extra);		pooladd(p, frag);	}	b->magic = KEMPT_MAGIC;	blocksetdsize(p, b, dsize);	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);		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 = UNKEMPT_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);		kemb(p, a, dsize);	}}/* arenamerge: attempt to coalesce to arenas that might be adjacent */static Arena*arenamerge(Pool *p, Arena *bot, Arena *top)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -