File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / pool_alloc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 5 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    1: #include "rsync.h"
    2: 
    3: #define POOL_DEF_EXTENT	(32 * 1024)
    4: 
    5: struct alloc_pool
    6: {
    7: 	size_t			size;		/* extent size		*/
    8: 	size_t			quantum;	/* allocation quantum	*/
    9: 	struct pool_extent	*extents;	/* top extent is "live" */
   10: 	void			(*bomb)();	/* function to call if
   11: 						 * malloc fails		*/
   12: 	int			flags;
   13: 
   14: 	/* statistical data */
   15: 	unsigned long		e_created;	/* extents created	*/
   16: 	unsigned long		e_freed;	/* extents detroyed	*/
   17: 	int64			n_allocated;	/* calls to alloc	*/
   18: 	int64			n_freed;	/* calls to free	*/
   19: 	int64			b_allocated;	/* cum. bytes allocated	*/
   20: 	int64			b_freed;	/* cum. bytes freed	*/
   21: };
   22: 
   23: struct pool_extent
   24: {
   25: 	void			*start;		/* starting address	*/
   26: 	size_t			free;		/* free bytecount	*/
   27: 	size_t			bound;		/* bytes bound by padding,
   28: 						 * overhead and freed	*/
   29: 	struct pool_extent	*next;
   30: };
   31: 
   32: struct align_test {
   33: 	void *foo;
   34: 	int64 bar;
   35: };
   36: 
   37: #define MINALIGN	offsetof(struct align_test, bar)
   38: 
   39: /* Temporarily cast a void* var into a char* var when adding an offset (to
   40:  * keep some compilers from complaining about the pointer arithmetic). */
   41: #define PTR_ADD(b,o)	( (void*) ((char*)(b) + (o)) )
   42: 
   43: alloc_pool_t
   44: pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
   45: {
   46: 	struct alloc_pool	*pool;
   47: 
   48: 	if (!(pool = new(struct alloc_pool)))
   49: 		return pool;
   50: 	memset(pool, 0, sizeof (struct alloc_pool));
   51: 
   52: 	pool->size = size	/* round extent size to min alignment reqs */
   53: 	    ? (size + MINALIGN - 1) & ~(MINALIGN - 1)
   54: 	    : POOL_DEF_EXTENT;
   55: 	if (flags & POOL_INTERN) {
   56: 		pool->size -= sizeof (struct pool_extent);
   57: 		flags |= POOL_APPEND;
   58: 	}
   59: 	pool->quantum = quantum ? quantum : MINALIGN;
   60: 	pool->bomb = bomb;
   61: 	pool->flags = flags;
   62: 
   63: 	return pool;
   64: }
   65: 
   66: void
   67: pool_destroy(alloc_pool_t p)
   68: {
   69: 	struct alloc_pool *pool = (struct alloc_pool *) p;
   70: 	struct pool_extent	*cur, *next;
   71: 
   72: 	if (!pool)
   73: 		return;
   74: 
   75: 	for (cur = pool->extents; cur; cur = next) {
   76: 		next = cur->next;
   77: 		free(cur->start);
   78: 		if (!(pool->flags & POOL_APPEND))
   79: 			free(cur);
   80: 	}
   81: 	free(pool);
   82: }
   83: 
   84: void *
   85: pool_alloc(alloc_pool_t p, size_t len, const char *bomb_msg)
   86: {
   87: 	struct alloc_pool *pool = (struct alloc_pool *) p;
   88: 	if (!pool)
   89: 		return NULL;
   90: 
   91: 	if (!len)
   92: 		len = pool->quantum;
   93: 	else if (pool->quantum > 1 && len % pool->quantum)
   94: 		len += pool->quantum - len % pool->quantum;
   95: 
   96: 	if (len > pool->size)
   97: 		goto bomb_out;
   98: 
   99: 	if (!pool->extents || len > pool->extents->free) {
  100: 		void	*start;
  101: 		size_t	free;
  102: 		size_t	bound;
  103: 		size_t	skew;
  104: 		size_t	asize;
  105: 		struct pool_extent *ext;
  106: 
  107: 		free = pool->size;
  108: 		bound = 0;
  109: 
  110: 		asize = pool->size;
  111: 		if (pool->flags & POOL_APPEND)
  112: 			asize += sizeof (struct pool_extent);
  113: 
  114: 		if (!(start = new_array(char, asize)))
  115: 			goto bomb_out;
  116: 
  117: 		if (pool->flags & POOL_CLEAR)
  118: 			memset(start, 0, free);
  119: 
  120: 		if (pool->flags & POOL_APPEND)
  121: 			ext = PTR_ADD(start, free);
  122: 		else if (!(ext = new(struct pool_extent)))
  123: 			goto bomb_out;
  124: 		if (pool->flags & POOL_QALIGN && pool->quantum > 1
  125: 		    && (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
  126: 			bound  += skew;
  127: 			free -= skew;
  128: 		}
  129: 		ext->start = start;
  130: 		ext->free = free;
  131: 		ext->bound = bound;
  132: 		ext->next = pool->extents;
  133: 		pool->extents = ext;
  134: 
  135: 		pool->e_created++;
  136: 	}
  137: 
  138: 	pool->n_allocated++;
  139: 	pool->b_allocated += len;
  140: 
  141: 	pool->extents->free -= len;
  142: 
  143: 	return PTR_ADD(pool->extents->start, pool->extents->free);
  144: 
  145:   bomb_out:
  146: 	if (pool->bomb)
  147: 		(*pool->bomb)(bomb_msg);
  148: 	return NULL;
  149: }
  150: 
  151: /* This function allows you to declare memory in the pool that you are done
  152:  * using.  If you free all the memory in a pool's extent, that extent will
  153:  * be freed. */
  154: void
  155: pool_free(alloc_pool_t p, size_t len, void *addr)
  156: {
  157: 	struct alloc_pool *pool = (struct alloc_pool *)p;
  158: 	struct pool_extent *cur, *prev;
  159: 
  160: 	if (!pool)
  161: 		return;
  162: 
  163: 	if (!len)
  164: 		len = pool->quantum;
  165: 	else if (pool->quantum > 1 && len % pool->quantum)
  166: 		len += pool->quantum - len % pool->quantum;
  167: 
  168: 	pool->n_freed++;
  169: 	pool->b_freed += len;
  170: 
  171: 	for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
  172: 		if (addr >= cur->start
  173: 		    && addr < PTR_ADD(cur->start, pool->size))
  174: 			break;
  175: 	}
  176: 	if (!cur)
  177: 		return;
  178: 
  179: 	if (!prev) {
  180: 		/* The "live" extent is kept ready for more allocations. */
  181: 		if (cur->free + cur->bound + len >= pool->size) {
  182: 			size_t skew;
  183: 
  184: 			if (pool->flags & POOL_CLEAR) {
  185: 				memset(PTR_ADD(cur->start, cur->free), 0,
  186: 				       pool->size - cur->free);
  187: 			}
  188: 			cur->free = pool->size;
  189: 			cur->bound = 0;
  190: 			if (pool->flags & POOL_QALIGN && pool->quantum > 1
  191: 			    && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
  192: 				cur->bound += skew;
  193: 				cur->free -= skew;
  194: 			}
  195: 		} else if (addr == PTR_ADD(cur->start, cur->free)) {
  196: 			if (pool->flags & POOL_CLEAR)
  197: 				memset(addr, 0, len);
  198: 			cur->free += len;
  199: 		} else
  200: 			cur->bound += len;
  201: 	} else {
  202: 		cur->bound += len;
  203: 
  204: 		if (cur->free + cur->bound >= pool->size) {
  205: 			prev->next = cur->next;
  206: 			free(cur->start);
  207: 			if (!(pool->flags & POOL_APPEND))
  208: 				free(cur);
  209: 			pool->e_freed++;
  210: 		} else if (prev != pool->extents) {
  211: 			/* Move the extent to be the first non-live extent. */
  212: 			prev->next = cur->next;
  213: 			cur->next = pool->extents->next;
  214: 			pool->extents->next = cur;
  215: 		}
  216: 	}
  217: }
  218: 
  219: /* This allows you to declare that the given address marks the edge of some
  220:  * pool memory that is no longer needed.  Any extents that hold only data
  221:  * older than the boundary address are freed.  NOTE: You MUST NOT USE BOTH
  222:  * pool_free() and pool_free_old() on the same pool!! */
  223: void
  224: pool_free_old(alloc_pool_t p, void *addr)
  225: {
  226: 	struct alloc_pool *pool = (struct alloc_pool *)p;
  227: 	struct pool_extent *cur, *prev, *next;
  228: 
  229: 	if (!pool || !addr)
  230: 		return;
  231: 
  232: 	for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
  233: 		if (addr >= cur->start
  234: 		    && addr < PTR_ADD(cur->start, pool->size))
  235: 			break;
  236: 	}
  237: 	if (!cur)
  238: 		return;
  239: 
  240: 	if (addr == PTR_ADD(cur->start, cur->free)) {
  241: 		if (prev) {
  242: 			prev->next = NULL;
  243: 			next = cur;
  244: 		} else {
  245: 			size_t skew;
  246: 
  247: 			/* The most recent live extent can just be reset. */
  248: 			if (pool->flags & POOL_CLEAR)
  249: 				memset(addr, 0, pool->size - cur->free);
  250: 			cur->free = pool->size;
  251: 			cur->bound = 0;
  252: 			if (pool->flags & POOL_QALIGN && pool->quantum > 1
  253: 			    && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
  254: 				cur->bound += skew;
  255: 				cur->free -= skew;
  256: 			}
  257: 			next = cur->next;
  258: 			cur->next = NULL;
  259: 		}
  260: 	} else {
  261: 		next = cur->next;
  262: 		cur->next = NULL;
  263: 	}
  264: 
  265: 	while ((cur = next) != NULL) {
  266: 		next = cur->next;
  267: 		free(cur->start);
  268: 		if (!(pool->flags & POOL_APPEND))
  269: 			free(cur);
  270: 		pool->e_freed++;
  271: 	}
  272: }
  273: 
  274: /* If the current extent doesn't have "len" free space in it, mark it as full
  275:  * so that the next alloc will start a new extent.  If len is (size_t)-1, this
  276:  * bump will always occur.  The function returns a boundary address that can
  277:  * be used with pool_free_old(), or a NULL if no memory is allocated. */
  278: void *
  279: pool_boundary(alloc_pool_t p, size_t len)
  280: {
  281: 	struct alloc_pool *pool = (struct alloc_pool *)p;
  282: 	struct pool_extent *cur;
  283: 
  284: 	if (!pool || !pool->extents)
  285: 		return NULL;
  286: 
  287: 	cur = pool->extents;
  288: 
  289: 	if (cur->free < len) {
  290: 		cur->bound += cur->free;
  291: 		cur->free = 0;
  292: 	}
  293: 
  294: 	return PTR_ADD(cur->start, cur->free);
  295: }
  296: 
  297: #define FDPRINT(label, value) \
  298: 	do { \
  299: 		int len = snprintf(buf, sizeof buf, label, value); \
  300: 		if (write(fd, buf, len) != len) \
  301: 			ret = -1; \
  302: 	} while (0)
  303: 
  304: #define FDEXTSTAT(ext) \
  305: 	do { \
  306: 		int len = snprintf(buf, sizeof buf, "  %12ld  %5ld\n", \
  307: 				   (long)ext->free, (long)ext->bound); \
  308: 		if (write(fd, buf, len) != len) \
  309: 			ret = -1; \
  310: 	} while (0)
  311: 
  312: int
  313: pool_stats(alloc_pool_t p, int fd, int summarize)
  314: {
  315: 	struct alloc_pool *pool = (struct alloc_pool *) p;
  316: 	struct pool_extent	*cur;
  317: 	char buf[BUFSIZ];
  318: 	int ret = 0;
  319: 
  320: 	if (!pool)
  321: 		return ret;
  322: 
  323: 	FDPRINT("  Extent size:       %12ld\n",	(long)	pool->size);
  324: 	FDPRINT("  Alloc quantum:     %12ld\n",	(long)	pool->quantum);
  325: 	FDPRINT("  Extents created:   %12ld\n",		pool->e_created);
  326: 	FDPRINT("  Extents freed:     %12ld\n",		pool->e_freed);
  327: 	FDPRINT("  Alloc count:       %12.0f\n", (double) pool->n_allocated);
  328: 	FDPRINT("  Free Count:        %12.0f\n", (double) pool->n_freed);
  329: 	FDPRINT("  Bytes allocated:   %12.0f\n", (double) pool->b_allocated);
  330: 	FDPRINT("  Bytes freed:       %12.0f\n", (double) pool->b_freed);
  331: 
  332: 	if (summarize)
  333: 		return ret;
  334: 
  335: 	if (!pool->extents)
  336: 		return ret;
  337: 
  338: 	if (write(fd, "\n", 1) != 1)
  339: 		ret = -1;
  340: 
  341: 	for (cur = pool->extents; cur; cur = cur->next)
  342: 		FDEXTSTAT(cur);
  343: 
  344: 	return ret;
  345: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>