summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorotto <>2009-11-27 20:11:01 +0000
committerotto <>2009-11-27 20:11:01 +0000
commit3d3d1405a7100bc32d8e0a7ca73cb68cf4219ca7 (patch)
tree4867d3c5308815e824306c492a7c70f75b5ae4d7 /src
parent40a957c6c401170c2ef2c75c1a3353742dad7322 (diff)
downloadopenbsd-3d3d1405a7100bc32d8e0a7ca73cb68cf4219ca7.tar.gz
openbsd-3d3d1405a7100bc32d8e0a7ca73cb68cf4219ca7.tar.bz2
openbsd-3d3d1405a7100bc32d8e0a7ca73cb68cf4219ca7.zip
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 'src')
-rw-r--r--src/lib/libc/stdlib/malloc.c85
1 files changed, 34 insertions, 51 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index f3f0a97c3a..b364a0c28b 100644
--- a/src/lib/libc/stdlib/malloc.c
+++ b/src/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: malloc.c,v 1.120 2009/11/27 20:05:03 otto Exp $ */ 1/* $OpenBSD: malloc.c,v 1.121 2009/11/27 20:11:01 otto Exp $ */
2/* 2/*
3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
4 * 4 *
@@ -32,6 +32,7 @@
32 32
33#include <sys/types.h> 33#include <sys/types.h>
34#include <sys/param.h> 34#include <sys/param.h>
35#include <sys/queue.h>
35#include <sys/mman.h> 36#include <sys/mman.h>
36#include <sys/uio.h> 37#include <sys/uio.h>
37#include <errno.h> 38#include <errno.h>
@@ -93,6 +94,8 @@ struct region_info {
93 uintptr_t size; /* size for pages, or chunk_info pointer */ 94 uintptr_t size; /* size for pages, or chunk_info pointer */
94}; 95};
95 96
97LIST_HEAD(chunk_head, chunk_info);
98
96struct dir_info { 99struct dir_info {
97 u_int32_t canary1; 100 u_int32_t canary1;
98 struct region_info *r; /* region slots */ 101 struct region_info *r; /* region slots */
@@ -100,9 +103,9 @@ struct dir_info {
100 size_t regions_bits; /* log2 of total */ 103 size_t regions_bits; /* log2 of total */
101 size_t regions_free; /* number of free slots */ 104 size_t regions_free; /* number of free slots */
102 /* list of free chunk info structs */ 105 /* list of free chunk info structs */
103 struct chunk_info *chunk_info_list; 106 struct chunk_head chunk_info_list;
104 /* lists of chunks with free slots */ 107 /* lists of chunks with free slots */
105 struct chunk_info *chunk_dir[MALLOC_MAXSHIFT]; 108 struct chunk_head chunk_dir[MALLOC_MAXSHIFT];
106 size_t free_regions_size; /* free pages cached */ 109 size_t free_regions_size; /* free pages cached */
107 /* free pages cache */ 110 /* free pages cache */
108 struct region_info free_regions[MALLOC_MAXCACHE]; 111 struct region_info free_regions[MALLOC_MAXCACHE];
@@ -135,7 +138,7 @@ struct dir_info {
135 */ 138 */
136#define MALLOC_BITS (NBBY * sizeof(u_long)) 139#define MALLOC_BITS (NBBY * sizeof(u_long))
137struct chunk_info { 140struct chunk_info {
138 struct chunk_info *next; /* next on the free list */ 141 LIST_ENTRY(chunk_info) entries;
139 void *page; /* pointer to the page */ 142 void *page; /* pointer to the page */
140 u_int32_t canary; 143 u_int32_t canary;
141 u_short size; /* size of this page's chunks */ 144 u_short size; /* size of this page's chunks */
@@ -217,13 +220,13 @@ dump_chunk(int fd, struct chunk_info *p, int fromfreelist)
217{ 220{
218 char buf[64]; 221 char buf[64];
219 222
220 while (p) { 223 while (p != NULL) {
221 snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size, 224 snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size,
222 p->free, p->total, p->page); 225 p->free, p->total, p->page);
223 write(fd, buf, strlen(buf)); 226 write(fd, buf, strlen(buf));
224 if (!fromfreelist) 227 if (!fromfreelist)
225 break; 228 break;
226 p = p->next; 229 p = LIST_NEXT(p, entries);
227 if (p != NULL) { 230 if (p != NULL) {
228 snprintf(buf, sizeof(buf), " "); 231 snprintf(buf, sizeof(buf), " ");
229 write(fd, buf, strlen(buf)); 232 write(fd, buf, strlen(buf));
@@ -240,7 +243,7 @@ dump_free_chunk_info(int fd, struct dir_info *d)
240 snprintf(buf, sizeof(buf), "Free chunk structs:\n"); 243 snprintf(buf, sizeof(buf), "Free chunk structs:\n");
241 write(fd, buf, strlen(buf)); 244 write(fd, buf, strlen(buf));
242 for (i = 0; i < MALLOC_MAXSHIFT; i++) { 245 for (i = 0; i < MALLOC_MAXSHIFT; i++) {
243 struct chunk_info *p = d->chunk_dir[i]; 246 struct chunk_info *p = LIST_FIRST(&d->chunk_dir[i]);
244 if (p != NULL) { 247 if (p != NULL) {
245 snprintf(buf, sizeof(buf), "%2d) ", i); 248 snprintf(buf, sizeof(buf), "%2d) ", i);
246 write(fd, buf, strlen(buf)); 249 write(fd, buf, strlen(buf));
@@ -716,6 +719,9 @@ omalloc_init(struct dir_info **dp)
716 d->regions_total = 0; 719 d->regions_total = 0;
717 return 1; 720 return 1;
718 } 721 }
722 LIST_INIT(&d->chunk_info_list);
723 for (i = 0; i < MALLOC_MAXSHIFT; i++)
724 LIST_INIT(&d->chunk_dir[i]);
719 malloc_used += regioninfo_size; 725 malloc_used += regioninfo_size;
720 d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d; 726 d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d;
721 d->canary2 = ~d->canary1; 727 d->canary2 = ~d->canary1;
@@ -788,31 +794,21 @@ alloc_chunk_info(struct dir_info *d)
788 struct chunk_info *p; 794 struct chunk_info *p;
789 int i; 795 int i;
790 796
791 if (d->chunk_info_list == NULL) { 797 if (LIST_EMPTY(&d->chunk_info_list)) {
792 p = MMAP(MALLOC_PAGESIZE); 798 p = MMAP(MALLOC_PAGESIZE);
793 if (p == MAP_FAILED) 799 if (p == MAP_FAILED)
794 return NULL; 800 return NULL;
795 malloc_used += MALLOC_PAGESIZE; 801 malloc_used += MALLOC_PAGESIZE;
796 for (i = 0; i < MALLOC_PAGESIZE / sizeof(*p); i++) { 802 for (i = 0; i < MALLOC_PAGESIZE / sizeof(*p); i++)
797 p[i].next = d->chunk_info_list; 803 LIST_INSERT_HEAD(&d->chunk_info_list, &p[i], entries);
798 d->chunk_info_list = &p[i];
799 }
800 } 804 }
801 p = d->chunk_info_list; 805 p = LIST_FIRST(&d->chunk_info_list);
802 d->chunk_info_list = p->next; 806 LIST_REMOVE(p, entries);
803 memset(p, 0, sizeof *p); 807 memset(p, 0, sizeof *p);
804 p->canary = d->canary1; 808 p->canary = d->canary1;
805 return p; 809 return p;
806} 810}
807 811
808
809static void
810put_chunk_info(struct dir_info *d, struct chunk_info *p)
811{
812 p->next = d->chunk_info_list;
813 d->chunk_info_list = p;
814}
815
816static int 812static int
817insert(struct dir_info *d, void *p, size_t sz) 813insert(struct dir_info *d, void *p, size_t sz)
818{ 814{
@@ -930,7 +926,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
930 k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE); 926 k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE);
931 if (k < 0) { 927 if (k < 0) {
932 unmap(d, pp, MALLOC_PAGESIZE); 928 unmap(d, pp, MALLOC_PAGESIZE);
933 put_chunk_info(d, bp); 929 LIST_INSERT_HEAD(&d->chunk_info_list, bp, entries);
934 return NULL; 930 return NULL;
935 } 931 }
936 } else { 932 } else {
@@ -951,8 +947,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
951 for (; i < k; i++) 947 for (; i < k; i++)
952 bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS); 948 bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
953 949
954 bp->next = d->chunk_dir[bits]; 950 LIST_INSERT_HEAD(&d->chunk_dir[bits], bp, entries);
955 d->chunk_dir[bits] = bp;
956 951
957 bits++; 952 bits++;
958 if ((uintptr_t)pp & bits) 953 if ((uintptr_t)pp & bits)
@@ -993,9 +988,12 @@ malloc_bytes(struct dir_info *d, size_t size)
993 } 988 }
994 989
995 /* If it's empty, make a page more of that size chunks */ 990 /* If it's empty, make a page more of that size chunks */
996 bp = d->chunk_dir[j]; 991 if (LIST_EMPTY(&d->chunk_dir[j])) {
997 if (bp == NULL && (bp = omalloc_make_chunks(d, j)) == NULL) 992 bp = omalloc_make_chunks(d, j);
998 return NULL; 993 if (bp == NULL)
994 return NULL;
995 } else
996 bp = LIST_FIRST(&d->chunk_dir[j]);
999 997
1000 if (bp->canary != d->canary1) 998 if (bp->canary != d->canary1)
1001 wrterror("chunk info corrupted"); 999 wrterror("chunk info corrupted");
@@ -1033,10 +1031,9 @@ malloc_bytes(struct dir_info *d, size_t size)
1033 *lp ^= u; 1031 *lp ^= u;
1034 1032
1035 /* If there are no more free, remove from free-list */ 1033 /* If there are no more free, remove from free-list */
1036 if (!--bp->free) { 1034 if (!--bp->free)
1037 d->chunk_dir[j] = bp->next; 1035 LIST_REMOVE(bp, entries);
1038 bp->next = NULL; 1036
1039 }
1040 /* Adjust to the real offset of that chunk */ 1037 /* Adjust to the real offset of that chunk */
1041 k += (lp - bp->bits) * MALLOC_BITS; 1038 k += (lp - bp->bits) * MALLOC_BITS;
1042 k <<= bp->shift; 1039 k <<= bp->shift;
@@ -1053,7 +1050,8 @@ malloc_bytes(struct dir_info *d, size_t size)
1053static void 1050static void
1054free_bytes(struct dir_info *d, struct region_info *r, void *ptr) 1051free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1055{ 1052{
1056 struct chunk_info *info, **mp; 1053 struct chunk_head *mp;
1054 struct chunk_info *info;
1057 long i; 1055 long i;
1058 1056
1059 info = (struct chunk_info *)r->size; 1057 info = (struct chunk_info *)r->size;
@@ -1082,35 +1080,20 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1082 1080
1083 if (info->free == 1) { 1081 if (info->free == 1) {
1084 /* Page became non-full */ 1082 /* Page became non-full */
1085 1083 LIST_INSERT_HEAD(mp, info, entries);
1086 /* Insert in address order */
1087 while (*mp != NULL && (*mp)->next != NULL &&
1088 (*mp)->next->page < info->page)
1089 mp = &(*mp)->next;
1090 info->next = *mp;
1091 *mp = info;
1092 return; 1084 return;
1093 } 1085 }
1094 if (info->free != info->total) 1086 if (info->free != info->total)
1095 return; 1087 return;
1096 1088
1097 /* Find & remove this page in the queue */ 1089 LIST_REMOVE(info, entries);
1098 while (*mp != info) {
1099 mp = &((*mp)->next);
1100 if (!*mp) {
1101 wrterror("not on queue");
1102 errno = EFAULT;
1103 return;
1104 }
1105 }
1106 *mp = info->next;
1107 1090
1108 if (info->size == 0 && !mopts.malloc_freeprot) 1091 if (info->size == 0 && !mopts.malloc_freeprot)
1109 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); 1092 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
1110 unmap(d, info->page, MALLOC_PAGESIZE); 1093 unmap(d, info->page, MALLOC_PAGESIZE);
1111 1094
1112 delete(d, r); 1095 delete(d, r);
1113 put_chunk_info(d, info); 1096 LIST_INSERT_HEAD(&d->chunk_info_list, info, entries);
1114} 1097}
1115 1098
1116 1099