summaryrefslogtreecommitdiff
path: root/lib/libc/stdlib/malloc.c
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2009-11-27 20:11:02 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2009-11-27 20:11:02 +0000
commite634701296759141d92e679ac6b35662f7afc267 (patch)
treeb3c72acac8b58ff1c46406af5fdc8f4799ffa305 /lib/libc/stdlib/malloc.c
parent1a40a0b1d4c082966c06bf954c762e0ba4537a19 (diff)
Switch the chunk_info lists to doubly-linked lists and use the queue
macros for them. Avoids walking the lists and greatly enhances speed of freeing chunks in reverse or random order at the cost of a little space. Suggested by Fabien Romano and Jonathan Armani; ok djm@
Diffstat (limited to 'lib/libc/stdlib/malloc.c')
-rw-r--r--lib/libc/stdlib/malloc.c85
1 files changed, 34 insertions, 51 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index f3f0a97c3a7..b364a0c28b6 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.c,v 1.120 2009/11/27 20:05:03 otto Exp $ */
+/* $OpenBSD: malloc.c,v 1.121 2009/11/27 20:11:01 otto Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <errno.h>
@@ -93,6 +94,8 @@ struct region_info {
uintptr_t size; /* size for pages, or chunk_info pointer */
};
+LIST_HEAD(chunk_head, chunk_info);
+
struct dir_info {
u_int32_t canary1;
struct region_info *r; /* region slots */
@@ -100,9 +103,9 @@ struct dir_info {
size_t regions_bits; /* log2 of total */
size_t regions_free; /* number of free slots */
/* list of free chunk info structs */
- struct chunk_info *chunk_info_list;
+ struct chunk_head chunk_info_list;
/* lists of chunks with free slots */
- struct chunk_info *chunk_dir[MALLOC_MAXSHIFT];
+ struct chunk_head chunk_dir[MALLOC_MAXSHIFT];
size_t free_regions_size; /* free pages cached */
/* free pages cache */
struct region_info free_regions[MALLOC_MAXCACHE];
@@ -135,7 +138,7 @@ struct dir_info {
*/
#define MALLOC_BITS (NBBY * sizeof(u_long))
struct chunk_info {
- struct chunk_info *next; /* next on the free list */
+ LIST_ENTRY(chunk_info) entries;
void *page; /* pointer to the page */
u_int32_t canary;
u_short size; /* size of this page's chunks */
@@ -217,13 +220,13 @@ dump_chunk(int fd, struct chunk_info *p, int fromfreelist)
{
char buf[64];
- while (p) {
+ while (p != NULL) {
snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size,
p->free, p->total, p->page);
write(fd, buf, strlen(buf));
if (!fromfreelist)
break;
- p = p->next;
+ p = LIST_NEXT(p, entries);
if (p != NULL) {
snprintf(buf, sizeof(buf), " ");
write(fd, buf, strlen(buf));
@@ -240,7 +243,7 @@ dump_free_chunk_info(int fd, struct dir_info *d)
snprintf(buf, sizeof(buf), "Free chunk structs:\n");
write(fd, buf, strlen(buf));
for (i = 0; i < MALLOC_MAXSHIFT; i++) {
- struct chunk_info *p = d->chunk_dir[i];
+ struct chunk_info *p = LIST_FIRST(&d->chunk_dir[i]);
if (p != NULL) {
snprintf(buf, sizeof(buf), "%2d) ", i);
write(fd, buf, strlen(buf));
@@ -716,6 +719,9 @@ omalloc_init(struct dir_info **dp)
d->regions_total = 0;
return 1;
}
+ LIST_INIT(&d->chunk_info_list);
+ for (i = 0; i < MALLOC_MAXSHIFT; i++)
+ LIST_INIT(&d->chunk_dir[i]);
malloc_used += regioninfo_size;
d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d;
d->canary2 = ~d->canary1;
@@ -788,31 +794,21 @@ alloc_chunk_info(struct dir_info *d)
struct chunk_info *p;
int i;
- if (d->chunk_info_list == NULL) {
+ if (LIST_EMPTY(&d->chunk_info_list)) {
p = MMAP(MALLOC_PAGESIZE);
if (p == MAP_FAILED)
return NULL;
malloc_used += MALLOC_PAGESIZE;
- for (i = 0; i < MALLOC_PAGESIZE / sizeof(*p); i++) {
- p[i].next = d->chunk_info_list;
- d->chunk_info_list = &p[i];
- }
+ for (i = 0; i < MALLOC_PAGESIZE / sizeof(*p); i++)
+ LIST_INSERT_HEAD(&d->chunk_info_list, &p[i], entries);
}
- p = d->chunk_info_list;
- d->chunk_info_list = p->next;
+ p = LIST_FIRST(&d->chunk_info_list);
+ LIST_REMOVE(p, entries);
memset(p, 0, sizeof *p);
p->canary = d->canary1;
return p;
}
-
-static void
-put_chunk_info(struct dir_info *d, struct chunk_info *p)
-{
- p->next = d->chunk_info_list;
- d->chunk_info_list = p;
-}
-
static int
insert(struct dir_info *d, void *p, size_t sz)
{
@@ -930,7 +926,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE);
if (k < 0) {
unmap(d, pp, MALLOC_PAGESIZE);
- put_chunk_info(d, bp);
+ LIST_INSERT_HEAD(&d->chunk_info_list, bp, entries);
return NULL;
}
} else {
@@ -951,8 +947,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
for (; i < k; i++)
bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
- bp->next = d->chunk_dir[bits];
- d->chunk_dir[bits] = bp;
+ LIST_INSERT_HEAD(&d->chunk_dir[bits], bp, entries);
bits++;
if ((uintptr_t)pp & bits)
@@ -993,9 +988,12 @@ malloc_bytes(struct dir_info *d, size_t size)
}
/* If it's empty, make a page more of that size chunks */
- bp = d->chunk_dir[j];
- if (bp == NULL && (bp = omalloc_make_chunks(d, j)) == NULL)
- return NULL;
+ if (LIST_EMPTY(&d->chunk_dir[j])) {
+ bp = omalloc_make_chunks(d, j);
+ if (bp == NULL)
+ return NULL;
+ } else
+ bp = LIST_FIRST(&d->chunk_dir[j]);
if (bp->canary != d->canary1)
wrterror("chunk info corrupted");
@@ -1033,10 +1031,9 @@ malloc_bytes(struct dir_info *d, size_t size)
*lp ^= u;
/* If there are no more free, remove from free-list */
- if (!--bp->free) {
- d->chunk_dir[j] = bp->next;
- bp->next = NULL;
- }
+ if (!--bp->free)
+ LIST_REMOVE(bp, entries);
+
/* Adjust to the real offset of that chunk */
k += (lp - bp->bits) * MALLOC_BITS;
k <<= bp->shift;
@@ -1053,7 +1050,8 @@ malloc_bytes(struct dir_info *d, size_t size)
static void
free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
{
- struct chunk_info *info, **mp;
+ struct chunk_head *mp;
+ struct chunk_info *info;
long i;
info = (struct chunk_info *)r->size;
@@ -1082,35 +1080,20 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
if (info->free == 1) {
/* Page became non-full */
-
- /* Insert in address order */
- while (*mp != NULL && (*mp)->next != NULL &&
- (*mp)->next->page < info->page)
- mp = &(*mp)->next;
- info->next = *mp;
- *mp = info;
+ LIST_INSERT_HEAD(mp, info, entries);
return;
}
if (info->free != info->total)
return;
- /* Find & remove this page in the queue */
- while (*mp != info) {
- mp = &((*mp)->next);
- if (!*mp) {
- wrterror("not on queue");
- errno = EFAULT;
- return;
- }
- }
- *mp = info->next;
+ LIST_REMOVE(info, entries);
if (info->size == 0 && !mopts.malloc_freeprot)
mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
unmap(d, info->page, MALLOC_PAGESIZE);
delete(d, r);
- put_chunk_info(d, info);
+ LIST_INSERT_HEAD(&d->chunk_info_list, info, entries);
}