summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libc/stdlib/malloc.c186
1 files changed, 125 insertions, 61 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index 028eff2b2d..ace34c96f6 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.83 2006/05/14 19:53:40 otto Exp $ */ 1/* $OpenBSD: malloc.c,v 1.84 2006/10/24 04:35:30 tedu Exp $ */
2 2
3/* 3/*
4 * ---------------------------------------------------------------------------- 4 * ----------------------------------------------------------------------------
@@ -75,6 +75,18 @@
75#define malloc_pageshift (PGSHIFT) 75#define malloc_pageshift (PGSHIFT)
76#endif 76#endif
77 77
78#ifndef malloc_minsize
79#define malloc_minsize 16UL
80#endif
81
82#if !defined(malloc_pagesize)
83#define malloc_pagesize (1UL<<malloc_pageshift)
84#endif
85
86/* How many bits per u_long in the bitmap */
87#define MALLOC_BITS (NBBY * sizeof(u_long))
88
89
78/* 90/*
79 * No user serviceable parts behind this point. 91 * No user serviceable parts behind this point.
80 * 92 *
@@ -87,12 +99,9 @@ struct pginfo {
87 u_short shift; /* How far to shift for this size chunks */ 99 u_short shift; /* How far to shift for this size chunks */
88 u_short free; /* How many free chunks */ 100 u_short free; /* How many free chunks */
89 u_short total; /* How many chunk */ 101 u_short total; /* How many chunk */
90 u_long bits[1];/* Which chunks are free */ 102 u_long bits[(malloc_pagesize / malloc_minsize) / MALLOC_BITS];/* Which chunks are free */
91}; 103};
92 104
93/* How many bits per u_long in the bitmap */
94#define MALLOC_BITS (NBBY * sizeof(u_long))
95
96/* 105/*
97 * This structure describes a number of free pages. 106 * This structure describes a number of free pages.
98 */ 107 */
@@ -113,14 +122,6 @@ struct pgfree {
113#define MALLOC_FOLLOW ((struct pginfo*) 3) 122#define MALLOC_FOLLOW ((struct pginfo*) 3)
114#define MALLOC_MAGIC ((struct pginfo*) 4) 123#define MALLOC_MAGIC ((struct pginfo*) 4)
115 124
116#ifndef malloc_minsize
117#define malloc_minsize 16UL
118#endif
119
120#if !defined(malloc_pagesize)
121#define malloc_pagesize (1UL<<malloc_pageshift)
122#endif
123
124#if ((1UL<<malloc_pageshift) != malloc_pagesize) 125#if ((1UL<<malloc_pageshift) != malloc_pagesize)
125#error "(1UL<<malloc_pageshift) != malloc_pagesize" 126#error "(1UL<<malloc_pageshift) != malloc_pagesize"
126#endif 127#endif
@@ -254,6 +255,66 @@ static void ifree(void *ptr);
254static void *irealloc(void *ptr, size_t size); 255static void *irealloc(void *ptr, size_t size);
255static void *malloc_bytes(size_t size); 256static void *malloc_bytes(size_t size);
256 257
258static struct pginfo *pginfo_list;
259
260static struct pgfree *pgfree_list;
261
262static struct pgfree *
263alloc_pgfree()
264{
265 struct pgfree *p;
266 int i;
267
268 if (pgfree_list == NULL) {
269 p = MMAP(malloc_pagesize);
270 if (!p)
271 return NULL;
272 for (i = 0; i < malloc_pagesize / sizeof(*p); i++) {
273 p[i].next = pgfree_list;
274 pgfree_list = &p[i];
275 }
276 }
277 p = pgfree_list;
278 pgfree_list = p->next;
279 memset(p, 0, sizeof *p);
280 return p;
281}
282
283static struct pginfo *
284alloc_pginfo()
285{
286 struct pginfo *p;
287 int i;
288
289 if (pginfo_list == NULL) {
290 p = MMAP(malloc_pagesize);
291 if (!p)
292 return NULL;
293 for (i = 0; i < malloc_pagesize / sizeof(*p); i++) {
294 p[i].next = pginfo_list;
295 pginfo_list = &p[i];
296 }
297 }
298 p = pginfo_list;
299 pginfo_list = p->next;
300 memset(p, 0, sizeof *p);
301 return p;
302}
303
304static void
305put_pgfree(struct pgfree *p)
306{
307 p->next = pgfree_list;
308 pgfree_list = p;
309}
310
311static void
312put_pginfo(struct pginfo *p)
313{
314 p->next = pginfo_list;
315 pginfo_list = p;
316}
317
257/* 318/*
258 * Function for page directory lookup. 319 * Function for page directory lookup.
259 */ 320 */
@@ -764,12 +825,12 @@ malloc_init(void)
764static void * 825static void *
765malloc_pages(size_t size) 826malloc_pages(size_t size)
766{ 827{
767 void *p, *delay_free = NULL, *tp; 828 void *p, *tp;
768 int i; 829 int i;
769 struct pginfo **pd; 830 struct pginfo **pd;
770 struct pdinfo *pi; 831 struct pdinfo *pi;
771 u_long pidx, index; 832 u_long pidx, index;
772 struct pgfree *pf; 833 struct pgfree *pf, *delay_free = NULL;
773 834
774 size = pageround(size) + malloc_guard; 835 size = pageround(size) + malloc_guard;
775 836
@@ -936,7 +997,7 @@ malloc_pages(size_t size)
936 if (px == NULL) 997 if (px == NULL)
937 px = delay_free; 998 px = delay_free;
938 else 999 else
939 ifree(delay_free); 1000 put_pgfree(delay_free);
940 } 1001 }
941 return (p); 1002 return (p);
942} 1003}
@@ -945,7 +1006,7 @@ malloc_pages(size_t size)
945 * Allocate a page of fragments 1006 * Allocate a page of fragments
946 */ 1007 */
947 1008
948static __inline__ int 1009static int
949malloc_make_chunks(int bits) 1010malloc_make_chunks(int bits)
950{ 1011{
951 struct pginfo *bp, **pd; 1012 struct pginfo *bp, **pd;
@@ -955,17 +1016,13 @@ malloc_make_chunks(int bits)
955#endif /* MALLOC_EXTRA_SANITY */ 1016#endif /* MALLOC_EXTRA_SANITY */
956 void *pp; 1017 void *pp;
957 long i, k; 1018 long i, k;
958 size_t l;
959 1019
960 /* Allocate a new bucket */ 1020 /* Allocate a new bucket */
961 pp = malloc_pages((size_t) malloc_pagesize); 1021 pp = malloc_pages((size_t)malloc_pagesize);
962 if (pp == NULL) 1022 if (pp == NULL)
963 return (0); 1023 return (0);
964 1024
965 /* Find length of admin structure */ 1025 /* Find length of admin structure */
966 l = sizeof *bp - sizeof(u_long);
967 l += sizeof(u_long) *
968 (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
969 1026
970 /* Don't waste more than two chunks on this */ 1027 /* Don't waste more than two chunks on this */
971 1028
@@ -975,14 +1032,10 @@ malloc_make_chunks(int bits)
975 * pginfo page. 1032 * pginfo page.
976 * --> Treat it like the big chunk alloc, get a second data page. 1033 * --> Treat it like the big chunk alloc, get a second data page.
977 */ 1034 */
978 if (bits != 0 && (1UL << (bits)) <= l + l) { 1035 bp = alloc_pginfo();
979 bp = (struct pginfo *) pp; 1036 if (bp == NULL) {
980 } else { 1037 ifree(pp);
981 bp = (struct pginfo *) imalloc(l); 1038 return (0);
982 if (bp == NULL) {
983 ifree(pp);
984 return (0);
985 }
986 } 1039 }
987 1040
988 /* memory protect the page allocated in the malloc(0) case */ 1041 /* memory protect the page allocated in the malloc(0) case */
@@ -998,7 +1051,7 @@ malloc_make_chunks(int bits)
998 k = mprotect(pp, malloc_pagesize, PROT_NONE); 1051 k = mprotect(pp, malloc_pagesize, PROT_NONE);
999 if (k < 0) { 1052 if (k < 0) {
1000 ifree(pp); 1053 ifree(pp);
1001 ifree(bp); 1054 put_pginfo(bp);
1002 return (0); 1055 return (0);
1003 } 1056 }
1004 } else { 1057 } else {
@@ -1019,18 +1072,6 @@ malloc_make_chunks(int bits)
1019 for (; i < k; i++) 1072 for (; i < k; i++)
1020 bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS); 1073 bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
1021 1074
1022 k = (long)l;
1023 if (bp == bp->page) {
1024 /* Mark the ones we stole for ourselves */
1025 for (i = 0; k > 0; i++) {
1026 bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS));
1027 bp->free--;
1028 bp->total--;
1029 k -= (1 << bits);
1030 }
1031 }
1032 /* MALLOC_LOCK */
1033
1034 pdir_lookup(ptr2index(pp), &pi); 1075 pdir_lookup(ptr2index(pp), &pi);
1035#ifdef MALLOC_EXTRA_SANITY 1076#ifdef MALLOC_EXTRA_SANITY
1036 pidx = PI_IDX(ptr2index(pp)); 1077 pidx = PI_IDX(ptr2index(pp));
@@ -1325,7 +1366,7 @@ irealloc(void *ptr, size_t size)
1325/* 1366/*
1326 * Free a sequence of pages 1367 * Free a sequence of pages
1327 */ 1368 */
1328static __inline__ void 1369static void
1329free_pages(void *ptr, u_long index, struct pginfo * info) 1370free_pages(void *ptr, u_long index, struct pginfo * info)
1330{ 1371{
1331 u_long i, pidx, lidx; 1372 u_long i, pidx, lidx;
@@ -1409,8 +1450,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info)
1409 mprotect(ptr, l, PROT_NONE); 1450 mprotect(ptr, l, PROT_NONE);
1410 1451
1411 /* Add to free-list. */ 1452 /* Add to free-list. */
1412 if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL) 1453 if (px == NULL && (px = alloc_pgfree()) == NULL)
1413 goto not_return; 1454 goto not_return;
1414 px->page = ptr; 1455 px->page = ptr;
1415 px->pdir = spi; 1456 px->pdir = spi;
1416 px->size = l; 1457 px->size = l;
@@ -1578,7 +1619,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info)
1578 /* XXX: We could realloc/shrink the pagedir here I guess. */ 1619 /* XXX: We could realloc/shrink the pagedir here I guess. */
1579 if (pf->size == 0) { /* Remove from free-list as well. */ 1620 if (pf->size == 0) { /* Remove from free-list as well. */
1580 if (px) 1621 if (px)
1581 ifree(px); 1622 put_pgfree(px);
1582 if ((px = pf->prev) != &free_list) { 1623 if ((px = pf->prev) != &free_list) {
1583 if (pi == NULL && last_index == (index - 1)) { 1624 if (pi == NULL && last_index == (index - 1)) {
1584 if (spi == NULL) { 1625 if (spi == NULL) {
@@ -1592,7 +1633,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info)
1592 pdi_mod) - 1; 1633 pdi_mod) - 1;
1593 for (pi = spi, i = index; 1634 for (pi = spi, i = index;
1594 pd[PI_OFF(i)] == MALLOC_NOT_MINE; 1635 pd[PI_OFF(i)] == MALLOC_NOT_MINE;
1595 i--) 1636 i--) {
1596#ifdef MALLOC_EXTRA_SANITY 1637#ifdef MALLOC_EXTRA_SANITY
1597 if (!PI_OFF(i)) { 1638 if (!PI_OFF(i)) {
1598 pi = pi->prev; 1639 pi = pi->prev;
@@ -1601,10 +1642,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info)
1601 pd = pi->base; 1642 pd = pi->base;
1602 i = (PD_IDX(pi->dirnum) + 1) * pdi_mod; 1643 i = (PD_IDX(pi->dirnum) + 1) * pdi_mod;
1603 } 1644 }
1604#else /* !MALLOC_EXTRA_SANITY */
1605 {
1606 }
1607#endif /* MALLOC_EXTRA_SANITY */ 1645#endif /* MALLOC_EXTRA_SANITY */
1646 }
1608 malloc_brk = index2ptr(i + 1); 1647 malloc_brk = index2ptr(i + 1);
1609 } 1648 }
1610 last_index = i; 1649 last_index = i;
@@ -1622,7 +1661,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info)
1622 } 1661 }
1623not_return: 1662not_return:
1624 if (pt != NULL) 1663 if (pt != NULL)
1625 ifree(pt); 1664 put_pgfree(pt);
1626} 1665}
1627 1666
1628/* 1667/*
@@ -1630,16 +1669,41 @@ not_return:
1630 */ 1669 */
1631 1670
1632/* ARGSUSED */ 1671/* ARGSUSED */
1633static __inline__ void 1672static void
1634free_bytes(void *ptr, u_long index, struct pginfo * info) 1673free_bytes(void *ptr)
1635{ 1674{
1636 struct pginfo **mp, **pd; 1675 struct pginfo **mp, **pd, *info;
1637 struct pdinfo *pi; 1676 struct pdinfo *pi;
1638#ifdef MALLOC_EXTRA_SANITY 1677#ifdef MALLOC_EXTRA_SANITY
1639 u_long pidx; 1678 u_long pidx;
1640#endif /* MALLOC_EXTRA_SANITY */ 1679#endif /* MALLOC_EXTRA_SANITY */
1680 u_long index;
1641 void *vp; 1681 void *vp;
1642 long i; 1682 long i;
1683 void *tmpptr;
1684 unsigned int tmpidx;
1685 /* pointers that we will want to free at some future time */
1686 static void *chunk_buffer[16];
1687
1688
1689 /* delay return, returning a random something from before instead */
1690 tmpidx = arc4random() % 16;
1691 tmpptr = chunk_buffer[tmpidx];
1692 chunk_buffer[tmpidx] = ptr;
1693 ptr = tmpptr;
1694 if (!ptr)
1695 return;
1696
1697 index = ptr2index(ptr);
1698
1699 pdir_lookup(index, &pi);
1700 if (pi != last_dir) {
1701 prev_dir = last_dir;
1702 last_dir = pi;
1703 }
1704 pd = pi->base;
1705 info = pd[PI_OFF(index)];
1706
1643 1707
1644 /* Find the chunk number on the page */ 1708 /* Find the chunk number on the page */
1645 i = ((u_long) ptr & malloc_pagemask) >> info->shift; 1709 i = ((u_long) ptr & malloc_pagemask) >> info->shift;
@@ -1711,9 +1775,8 @@ free_bytes(void *ptr, u_long index, struct pginfo * info)
1711 if (info->size == 0) 1775 if (info->size == 0)
1712 mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE); 1776 mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE);
1713 1777
1714 vp = info->page; /* Order is important ! */ 1778 vp = info->page;
1715 if (vp != (void *) info) 1779 put_pginfo(info);
1716 ifree(info);
1717 ifree(vp); 1780 ifree(vp);
1718} 1781}
1719 1782
@@ -1736,7 +1799,7 @@ ifree(void *ptr)
1736 return; 1799 return;
1737 1800
1738 if (malloc_ptrguard && PTR_ALIGNED(ptr)) 1801 if (malloc_ptrguard && PTR_ALIGNED(ptr))
1739 ptr = (char *) ptr - PTR_GAP; 1802 ptr = (char *)ptr - PTR_GAP;
1740 1803
1741 index = ptr2index(ptr); 1804 index = ptr2index(ptr);
1742 1805
@@ -1750,6 +1813,7 @@ ifree(void *ptr)
1750 wrtwarning("ifree: junk pointer, too high to make sense"); 1813 wrtwarning("ifree: junk pointer, too high to make sense");
1751 return; 1814 return;
1752 } 1815 }
1816
1753 pdir_lookup(index, &pi); 1817 pdir_lookup(index, &pi);
1754#ifdef MALLOC_EXTRA_SANITY 1818#ifdef MALLOC_EXTRA_SANITY
1755 pidx = PI_IDX(index); 1819 pidx = PI_IDX(index);
@@ -1769,11 +1833,11 @@ ifree(void *ptr)
1769 if (info < MALLOC_MAGIC) 1833 if (info < MALLOC_MAGIC)
1770 free_pages(ptr, index, info); 1834 free_pages(ptr, index, info);
1771 else 1835 else
1772 free_bytes(ptr, index, info); 1836 free_bytes(ptr);
1773 1837
1774 /* does not matter if malloc_bytes fails */ 1838 /* does not matter if malloc_bytes fails */
1775 if (px == NULL) 1839 if (px == NULL)
1776 px = malloc_bytes(sizeof *px); 1840 px = alloc_pgfree();
1777 1841
1778 return; 1842 return;
1779} 1843}