Browse Source

Make struct chunk_info a variable sized struct, wasting less

space for meta data by only allocating space actually needed for
the bitmap (modulo alignment requirements). ok deraadt@
OPENBSD_5_1
otto 13 years ago
parent
commit
7f73468da7
1 changed files with 55 additions and 28 deletions
  1. +55
    -28
      src/lib/libc/stdlib/malloc.c

+ 55
- 28
src/lib/libc/stdlib/malloc.c View File

@ -1,4 +1,4 @@
/* $OpenBSD: malloc.c,v 1.139 2011/07/12 14:43:42 otto Exp $ */
/* $OpenBSD: malloc.c,v 1.140 2011/10/06 14:37:04 otto Exp $ */
/* /*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
* *
@ -109,8 +109,8 @@ struct dir_info {
struct region_info *r; /* region slots */ struct region_info *r; /* region slots */
size_t regions_total; /* number of region slots */ size_t regions_total; /* number of region slots */
size_t regions_free; /* number of free slots */ size_t regions_free; /* number of free slots */
/* list of free chunk info structs */
struct chunk_head chunk_info_list;
/* lists of free chunk info structs */
struct chunk_head chunk_info_list[MALLOC_MAXSHIFT + 1];
/* lists of chunks with free slots */ /* lists of chunks with free slots */
struct chunk_head chunk_dir[MALLOC_MAXSHIFT + 1]; struct chunk_head chunk_dir[MALLOC_MAXSHIFT + 1];
size_t free_regions_size; /* free pages cached */ size_t free_regions_size; /* free pages cached */
@ -156,7 +156,7 @@ struct chunk_info {
u_short free; /* how many free chunks */ u_short free; /* how many free chunks */
u_short total; /* how many chunk */ u_short total; /* how many chunk */
/* which chunks are free */ /* which chunks are free */
u_short bits[(MALLOC_PAGESIZE / MALLOC_MINSIZE) / MALLOC_BITS];
u_short bits[1];
}; };
struct malloc_readonly { struct malloc_readonly {
@ -622,9 +622,10 @@ omalloc_init(struct dir_info **dp)
d->regions_total = 0; d->regions_total = 0;
return 1; return 1;
} }
LIST_INIT(&d->chunk_info_list);
for (i = 0; i <= MALLOC_MAXSHIFT; i++)
for (i = 0; i <= MALLOC_MAXSHIFT; i++) {
LIST_INIT(&d->chunk_info_list[i]);
LIST_INIT(&d->chunk_dir[i]); LIST_INIT(&d->chunk_dir[i]);
}
malloc_used += regioninfo_size; malloc_used += regioninfo_size;
d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d; d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d;
d->canary2 = ~d->canary1; d->canary2 = ~d->canary1;
@ -689,22 +690,36 @@ omalloc_grow(struct dir_info *d)
} }
static struct chunk_info * static struct chunk_info *
alloc_chunk_info(struct dir_info *d)
alloc_chunk_info(struct dir_info *d, int bits)
{ {
struct chunk_info *p; struct chunk_info *p;
int i;
if (LIST_EMPTY(&d->chunk_info_list)) {
p = MMAP(MALLOC_PAGESIZE);
if (p == MAP_FAILED)
size_t size, count;
if (bits == 0)
count = MALLOC_PAGESIZE / MALLOC_MINSIZE;
else
count = MALLOC_PAGESIZE >> bits;
size = howmany(count, MALLOC_BITS);
size = sizeof(struct chunk_info) + (size - 1) * sizeof(u_short);
size = ALIGN(size);
if (LIST_EMPTY(&d->chunk_info_list[bits])) {
void *q;
int i;
q = MMAP(MALLOC_PAGESIZE);
if (q == MAP_FAILED)
return NULL; return NULL;
malloc_used += MALLOC_PAGESIZE; malloc_used += MALLOC_PAGESIZE;
for (i = 0; i < MALLOC_PAGESIZE / sizeof(*p); i++)
LIST_INSERT_HEAD(&d->chunk_info_list, &p[i], entries);
count = MALLOC_PAGESIZE / size;
for (i = 0; i < count; i++, q += size)
LIST_INSERT_HEAD(&d->chunk_info_list[bits],
(struct chunk_info *)q, entries);
} }
p = LIST_FIRST(&d->chunk_info_list);
p = LIST_FIRST(&d->chunk_info_list[bits]);
LIST_REMOVE(p, entries); LIST_REMOVE(p, entries);
memset(p, 0, sizeof *p);
memset(p, 0, size);
p->canary = d->canary1; p->canary = d->canary1;
return p; return p;
} }
@ -803,14 +818,14 @@ omalloc_make_chunks(struct dir_info *d, int bits)
{ {
struct chunk_info *bp; struct chunk_info *bp;
void *pp; void *pp;
long i, k;
int i, k;
/* Allocate a new bucket */ /* Allocate a new bucket */
pp = map(d, MALLOC_PAGESIZE, 0); pp = map(d, MALLOC_PAGESIZE, 0);
if (pp == MAP_FAILED) if (pp == MAP_FAILED)
return NULL; return NULL;
bp = alloc_chunk_info(d);
bp = alloc_chunk_info(d, bits);
if (bp == NULL) { if (bp == NULL) {
unmap(d, pp, MALLOC_PAGESIZE); unmap(d, pp, MALLOC_PAGESIZE);
return NULL; return NULL;
@ -829,7 +844,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE); k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE);
if (k < 0) { if (k < 0) {
unmap(d, pp, MALLOC_PAGESIZE); unmap(d, pp, MALLOC_PAGESIZE);
LIST_INSERT_HEAD(&d->chunk_info_list, bp, entries);
LIST_INSERT_HEAD(&d->chunk_info_list[0], bp, entries);
return NULL; return NULL;
} }
} else { } else {
@ -956,7 +971,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
{ {
struct chunk_head *mp; struct chunk_head *mp;
struct chunk_info *info; struct chunk_info *info;
long i;
int i;
info = (struct chunk_info *)r->size; info = (struct chunk_info *)r->size;
if (info->canary != d->canary1) if (info->canary != d->canary1)
@ -997,7 +1012,11 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
unmap(d, info->page, MALLOC_PAGESIZE); unmap(d, info->page, MALLOC_PAGESIZE);
delete(d, r); delete(d, r);
LIST_INSERT_HEAD(&d->chunk_info_list, info, entries);
if (info->size != 0)
mp = &d->chunk_info_list[info->shift];
else
mp = &d->chunk_info_list[0];
LIST_INSERT_HEAD(mp, info, entries);
} }
@ -1521,7 +1540,7 @@ dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist)
} }
p = LIST_NEXT(p, entries); p = LIST_NEXT(p, entries);
if (p != NULL) { if (p != NULL) {
snprintf(buf, sizeof(buf), " ");
snprintf(buf, sizeof(buf), " ");
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
} }
} }
@ -1531,17 +1550,25 @@ static void
dump_free_chunk_info(int fd, struct dir_info *d) dump_free_chunk_info(int fd, struct dir_info *d)
{ {
char buf[64]; char buf[64];
int i;
int i, count;
snprintf(buf, sizeof(buf), "Free chunk structs:\n"); snprintf(buf, sizeof(buf), "Free chunk structs:\n");
write(fd, buf, strlen(buf)); write(fd, buf, strlen(buf));
for (i = 0; i <= MALLOC_MAXSHIFT; i++) { for (i = 0; i <= MALLOC_MAXSHIFT; 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));
struct chunk_info *p;
count = 0;
LIST_FOREACH(p, &d->chunk_info_list[i], entries)
count++;
p = LIST_FIRST(&d->chunk_dir[i]);
if (p == NULL && count == 0)
continue;
snprintf(buf, sizeof(buf), "%2d) %3d ", i, count);
write(fd, buf, strlen(buf));
if (p != NULL)
dump_chunk(fd, p, NULL, 1); dump_chunk(fd, p, NULL, 1);
}
else
write(fd, "\n", 1);
} }
} }


Loading…
Cancel
Save