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

📄 rheap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Validate size */	if (size <= 0)		return (unsigned long) -EINVAL;	/* The region must be aligned */	s = start;	e = s + size;	m = info->alignment - 1;	/* Round start up */	s = (s + m) & ~m;	/* Round end down */	e = e & ~m;	if (assure_empty(info, 1) < 0)		return (unsigned long) -ENOMEM;	blk = NULL;	list_for_each(l, &info->free_list) {		blk = list_entry(l, rh_block_t, list);		/* The range must lie entirely inside one free block */		bs = blk->start;		be = blk->start + blk->size;		if (s >= bs && e <= be)			break;		blk = NULL;	}	if (blk == NULL)		return (unsigned long) -ENOMEM;	/* Perfect fit */	if (bs == s && be == e) {		/* Delete from free list, release slot */		list_del(&blk->list);		release_slot(info, blk);		return s;	}	/* blk still in free list, with updated start and/or size */	if (bs == s || be == e) {		if (bs == s)			blk->start += size;		blk->size -= size;	} else {		/* The front free fragment */		blk->size = s - bs;		/* the back free fragment */		newblk = get_slot(info);		newblk->start = e;		newblk->size = be - e;		list_add(&newblk->list, &blk->list);	}	return s;}EXPORT_SYMBOL_GPL(rh_detach_region);/* Allocate a block of memory at the specified alignment.  The value returned * is an offset into the buffer initialized by rh_init(), or a negative number * if there is an error. */unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner){	struct list_head *l;	rh_block_t *blk;	rh_block_t *newblk;	unsigned long start, sp_size;	/* Validate size, and alignment must be power of two */	if (size <= 0 || (alignment & (alignment - 1)) != 0)		return (unsigned long) -EINVAL;	/* Align to configured alignment */	size = (size + (info->alignment - 1)) & ~(info->alignment - 1);	if (assure_empty(info, 2) < 0)		return (unsigned long) -ENOMEM;	blk = NULL;	list_for_each(l, &info->free_list) {		blk = list_entry(l, rh_block_t, list);		if (size <= blk->size) {			start = (blk->start + alignment - 1) & ~(alignment - 1);			if (start + size <= blk->start + blk->size)				break;		}		blk = NULL;	}	if (blk == NULL)		return (unsigned long) -ENOMEM;	/* Just fits */	if (blk->size == size) {		/* Move from free list to taken list */		list_del(&blk->list);		newblk = blk;	} else {		/* Fragment caused, split if needed */		/* Create block for fragment in the beginning */		sp_size = start - blk->start;		if (sp_size) {			rh_block_t *spblk;			spblk = get_slot(info);			spblk->start = blk->start;			spblk->size = sp_size;			/* add before the blk */			list_add(&spblk->list, blk->list.prev);		}		newblk = get_slot(info);		newblk->start = start;		newblk->size = size;		/* blk still in free list, with updated start and size		 * for fragment in the end */		blk->start = start + size;		blk->size -= sp_size + size;		/* No fragment in the end, remove blk */		if (blk->size == 0) {			list_del(&blk->list);			release_slot(info, blk);		}	}	newblk->owner = owner;	attach_taken_block(info, newblk);	return start;}EXPORT_SYMBOL_GPL(rh_alloc_align);/* Allocate a block of memory at the default alignment.  The value returned is * an offset into the buffer initialized by rh_init(), or a negative number if * there is an error. */unsigned long rh_alloc(rh_info_t * info, int size, const char *owner){	return rh_alloc_align(info, size, info->alignment, owner);}EXPORT_SYMBOL_GPL(rh_alloc);/* Allocate a block of memory at the given offset, rounded up to the default * alignment.  The value returned is an offset into the buffer initialized by * rh_init(), or a negative number if there is an error. */unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, const char *owner){	struct list_head *l;	rh_block_t *blk, *newblk1, *newblk2;	unsigned long s, e, m, bs = 0, be = 0;	/* Validate size */	if (size <= 0)		return (unsigned long) -EINVAL;	/* The region must be aligned */	s = start;	e = s + size;	m = info->alignment - 1;	/* Round start up */	s = (s + m) & ~m;	/* Round end down */	e = e & ~m;	if (assure_empty(info, 2) < 0)		return (unsigned long) -ENOMEM;	blk = NULL;	list_for_each(l, &info->free_list) {		blk = list_entry(l, rh_block_t, list);		/* The range must lie entirely inside one free block */		bs = blk->start;		be = blk->start + blk->size;		if (s >= bs && e <= be)			break;	}	if (blk == NULL)		return (unsigned long) -ENOMEM;	/* Perfect fit */	if (bs == s && be == e) {		/* Move from free list to taken list */		list_del(&blk->list);		blk->owner = owner;		start = blk->start;		attach_taken_block(info, blk);		return start;	}	/* blk still in free list, with updated start and/or size */	if (bs == s || be == e) {		if (bs == s)			blk->start += size;		blk->size -= size;	} else {		/* The front free fragment */		blk->size = s - bs;		/* The back free fragment */		newblk2 = get_slot(info);		newblk2->start = e;		newblk2->size = be - e;		list_add(&newblk2->list, &blk->list);	}	newblk1 = get_slot(info);	newblk1->start = s;	newblk1->size = e - s;	newblk1->owner = owner;	start = newblk1->start;	attach_taken_block(info, newblk1);	return start;}EXPORT_SYMBOL_GPL(rh_alloc_fixed);/* Deallocate the memory previously allocated by one of the rh_alloc functions. * The return value is the size of the deallocated block, or a negative number * if there is an error. */int rh_free(rh_info_t * info, unsigned long start){	rh_block_t *blk, *blk2;	struct list_head *l;	int size;	/* Linear search for block */	blk = NULL;	list_for_each(l, &info->taken_list) {		blk2 = list_entry(l, rh_block_t, list);		if (start < blk2->start)			break;		blk = blk2;	}	if (blk == NULL || start > (blk->start + blk->size))		return -EINVAL;	/* Remove from taken list */	list_del(&blk->list);	/* Get size of freed block */	size = blk->size;	attach_free_block(info, blk);	return size;}EXPORT_SYMBOL_GPL(rh_free);int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats){	rh_block_t *blk;	struct list_head *l;	struct list_head *h;	int nr;	switch (what) {	case RHGS_FREE:		h = &info->free_list;		break;	case RHGS_TAKEN:		h = &info->taken_list;		break;	default:		return -EINVAL;	}	/* Linear search for block */	nr = 0;	list_for_each(l, h) {		blk = list_entry(l, rh_block_t, list);		if (stats != NULL && nr < max_stats) {			stats->start = blk->start;			stats->size = blk->size;			stats->owner = blk->owner;			stats++;		}		nr++;	}	return nr;}EXPORT_SYMBOL_GPL(rh_get_stats);int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner){	rh_block_t *blk, *blk2;	struct list_head *l;	int size;	/* Linear search for block */	blk = NULL;	list_for_each(l, &info->taken_list) {		blk2 = list_entry(l, rh_block_t, list);		if (start < blk2->start)			break;		blk = blk2;	}	if (blk == NULL || start > (blk->start + blk->size))		return -EINVAL;	blk->owner = owner;	size = blk->size;	return size;}EXPORT_SYMBOL_GPL(rh_set_owner);void rh_dump(rh_info_t * info){	static rh_stats_t st[32];	/* XXX maximum 32 blocks */	int maxnr;	int i, nr;	maxnr = ARRAY_SIZE(st);	printk(KERN_INFO	       "info @0x%p (%d slots empty / %d max)\n",	       info, info->empty_slots, info->max_blocks);	printk(KERN_INFO "  Free:\n");	nr = rh_get_stats(info, RHGS_FREE, maxnr, st);	if (nr > maxnr)		nr = maxnr;	for (i = 0; i < nr; i++)		printk(KERN_INFO		       "    0x%lx-0x%lx (%u)\n",		       st[i].start, st[i].start + st[i].size,		       st[i].size);	printk(KERN_INFO "\n");	printk(KERN_INFO "  Taken:\n");	nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st);	if (nr > maxnr)		nr = maxnr;	for (i = 0; i < nr; i++)		printk(KERN_INFO		       "    0x%lx-0x%lx (%u) %s\n",		       st[i].start, st[i].start + st[i].size,		       st[i].size, st[i].owner != NULL ? st[i].owner : "");	printk(KERN_INFO "\n");}EXPORT_SYMBOL_GPL(rh_dump);void rh_dump_blk(rh_info_t * info, rh_block_t * blk){	printk(KERN_INFO	       "blk @0x%p: 0x%lx-0x%lx (%u)\n",	       blk, blk->start, blk->start + blk->size, blk->size);}EXPORT_SYMBOL_GPL(rh_dump_blk);

⌨️ 快捷键说明

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