From: "Mark E." To: djgpp-workers AT delorie DOT com Date: Fri, 5 Jan 2001 12:42:26 -0500 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: valloc and memalign draft Message-ID: <3A55C132.12287.6F26E9@localhost> X-mailer: Pegasus Mail for Win32 (v3.12c) Reply-To: djgpp-workers AT delorie DOT com Hi guys, This is a draft of valloc (and memalign) designed to used mainly by the GCC's garbage collection routines. I designed it to be memory efficient and return a pointer that can safely be passed to free(). While a generic valloc is in the works for inclusion in libiberty, it's always better to have our own version if possible. I would have split off memalign and valloc, but I wanted to get them working first. *** malloc.c.orig Wed Jun 28 15:46:34 2000 --- malloc.c Fri Jan 5 12:30:40 2001 *************** *** 360,362 **** --- 360,458 ---- free(ptr); return newptr; } + + /* Make VAL a multiple of ALIGN. */ + inline + size_t + align_val (size_t val, size_t align) + { + return ((val + (align - 1)) & ~(align - 1)); + } + + /* Split a chunk of previously allocated memory into two chunks in a way + that requires both to be released with a call to free(). */ + void * + split_alloc (char *ptr, size_t split_pos) + { + BLOCK *b1, *b2; + char *split_ptr; + + b1 = (BLOCK *)(ptr - 4); + + /* Set location of second pointer and its block info. */ + split_ptr = ptr + split_pos; + b2 = (BLOCK *)(split_ptr - 4); + + /* Temporarily clear chunk-in-use bit so macros work correctly. */ + b1->size &= ~1; + + /* Set up the two blocks. */ + b2->size = b1->size - split_pos; + b2->bucket = -1; + b1->size = split_pos - 8; + + ENDSZ(b1) = b1->size; + ENDSZ(b2) = b2->size; + CHECK(b1); + CHECK(b2); + + /* Finish up by setting the chunk-in-use bit for the first chunk and + returning a pointer to the chunk just split off. */ + ENDSZ(b1) |= 1; + b1->size |= 1; + + RET (b2); + } + + /* Return a block of memory AMT bytes long whose address is a multiple + ALIGN. ALIGN must be a power of 2. */ + + void * + memalign (size_t align, size_t amt) + { + char *ptr, *aligned_ptr; + BLOCK *b; + size_t alloc_size, before_size, after_size; + + if (align != align_val(align, align)) + return NULL; + + if (align < ALIGN) + align = ALIGN; + + amt = align_val (amt, ALIGN); + alloc_size = amt + align; + + ptr = malloc(alloc_size); + if (ptr == NULL) + return ptr; + + aligned_ptr = (char *)align_val((size_t)ptr, align); + + /* Release any space between the malloc'ed pointer + and the aligned pointer. */ + before_size = (aligned_ptr - ptr); + if (before_size) + { + aligned_ptr = split_alloc (ptr, before_size); + free (ptr); + } + + /* Release extra space not requested if it's large enough + to bother with. */ + after_size = alloc_size - amt - 8; + if (after_size > 8) + { + char *after = split_alloc (aligned_ptr, amt + 8); + free (after); + } + + return aligned_ptr; + } + + void * + valloc (size_t amt) + { + return memalign (getpagesize(), amt); + } +