summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatthew <>2012-06-18 17:03:52 +0000
committermatthew <>2012-06-18 17:03:52 +0000
commit71b2db593f575c8e8ada85098d2b61ee7f67408b (patch)
treef92bf32b94fe50878ccc250509462e743ce99ce6
parent0e75ebe6fc3d4043e79e7c89766f56e43c180169 (diff)
downloadopenbsd-71b2db593f575c8e8ada85098d2b61ee7f67408b.tar.gz
openbsd-71b2db593f575c8e8ada85098d2b61ee7f67408b.tar.bz2
openbsd-71b2db593f575c8e8ada85098d2b61ee7f67408b.zip
Support larger-than-page-alignment requests in posix_memalign() by
overallocating and then releasing unneeded memory pages. ok otto
-rw-r--r--src/lib/libc/stdlib/malloc.c147
-rw-r--r--src/lib/libc/stdlib/posix_memalign.36
2 files changed, 130 insertions, 23 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index 6aba00e4a0..6f646934b2 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.141 2012/02/29 08:44:14 otto Exp $ */ 1/* $OpenBSD: malloc.c,v 1.142 2012/06/18 17:03:51 matthew Exp $ */
2/* 2/*
3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
4 * 4 *
@@ -389,7 +389,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
389 wrterror("internal struct corrupt", NULL); 389 wrterror("internal struct corrupt", NULL);
390 if (sz != PAGEROUND(sz)) { 390 if (sz != PAGEROUND(sz)) {
391 wrterror("map round", NULL); 391 wrterror("map round", NULL);
392 return NULL; 392 return MAP_FAILED;
393 } 393 }
394 if (psz > d->free_regions_size) { 394 if (psz > d->free_regions_size) {
395 p = MMAP(sz); 395 p = MMAP(sz);
@@ -1295,8 +1295,10 @@ orealloc(void *p, size_t newsz, void *f)
1295 STATS_SETF(r, f); 1295 STATS_SETF(r, f);
1296 STATS_INC(g_pool->cheap_reallocs); 1296 STATS_INC(g_pool->cheap_reallocs);
1297 return p; 1297 return p;
1298 } else if (q != MAP_FAILED) 1298 } else if (q != MAP_FAILED) {
1299 munmap(q, rnewsz - roldsz); 1299 if (munmap(q, rnewsz - roldsz))
1300 wrterror("munmap", q);
1301 }
1300 } 1302 }
1301 } else if (rnewsz < roldsz) { 1303 } else if (rnewsz < roldsz) {
1302 if (mopts.malloc_guard) { 1304 if (mopts.malloc_guard) {
@@ -1413,29 +1415,136 @@ calloc(size_t nmemb, size_t size)
1413 return r; 1415 return r;
1414} 1416}
1415 1417
1418static void *
1419mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill)
1420{
1421 void *p, *q;
1422
1423 if (alignment < MALLOC_PAGESIZE || alignment & (alignment - 1) != 0) {
1424 wrterror("mapalign bad alignment", NULL);
1425 return MAP_FAILED;
1426 }
1427 if (sz != PAGEROUND(sz)) {
1428 wrterror("mapalign round", NULL);
1429 return MAP_FAILED;
1430 }
1431
1432 /* Allocate sz + alignment bytes of memory, which must include a
1433 * subrange of size bytes that is properly aligned. Unmap the
1434 * other bytes, and then return that subrange.
1435 */
1436
1437 /* We need sz + alignment to fit into a size_t. */
1438 if (alignment > SIZE_MAX - sz)
1439 return MAP_FAILED;
1440
1441 p = map(d, sz + alignment, zero_fill);
1442 if (p == MAP_FAILED)
1443 return MAP_FAILED;
1444 q = (void *)(((uintptr_t)p + alignment - 1) & ~(alignment - 1));
1445 if (q != p) {
1446 if (munmap(p, q - p))
1447 wrterror("munmap", p);
1448 }
1449 if (munmap(q + sz, alignment - (q - p)))
1450 wrterror("munmap", q + sz);
1451 malloc_used -= alignment;
1452
1453 return q;
1454}
1455
1456static void *
1457omemalign(size_t alignment, size_t sz, int zero_fill, void *f)
1458{
1459 size_t psz;
1460 void *p;
1461
1462 if (alignment <= MALLOC_PAGESIZE) {
1463 /*
1464 * max(size, alignment) is enough to assure the requested alignment,
1465 * since the allocator always allocates power-of-two blocks.
1466 */
1467 if (sz < alignment)
1468 sz = alignment;
1469 return omalloc(sz, zero_fill, f);
1470 }
1471
1472 if (sz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
1473 errno = ENOMEM;
1474 return NULL;
1475 }
1476
1477 sz += mopts.malloc_guard;
1478 psz = PAGEROUND(sz);
1479
1480 p = mapalign(g_pool, alignment, psz, zero_fill);
1481 if (p == NULL) {
1482 errno = ENOMEM;
1483 return NULL;
1484 }
1485
1486 if (insert(g_pool, p, sz, f)) {
1487 unmap(g_pool, p, psz);
1488 errno = ENOMEM;
1489 return NULL;
1490 }
1491
1492 if (mopts.malloc_guard) {
1493 if (mprotect((char *)p + psz - mopts.malloc_guard,
1494 mopts.malloc_guard, PROT_NONE))
1495 wrterror("mprotect", NULL);
1496 malloc_guarded += mopts.malloc_guard;
1497 }
1498
1499 if (mopts.malloc_junk) {
1500 if (zero_fill)
1501 memset((char *)p + sz - mopts.malloc_guard,
1502 SOME_JUNK, psz - sz);
1503 else
1504 memset(p, SOME_JUNK, psz - mopts.malloc_guard);
1505 }
1506
1507 return p;
1508}
1509
1416int 1510int
1417posix_memalign(void **memptr, size_t alignment, size_t size) 1511posix_memalign(void **memptr, size_t alignment, size_t size)
1418{ 1512{
1419 void *result; 1513 int res, saved_errno = errno;
1514 void *r;
1420 1515
1421 /* Make sure that alignment is a large enough power of 2. */ 1516 /* Make sure that alignment is a large enough power of 2. */
1422 if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *) || 1517 if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *))
1423 alignment > MALLOC_PAGESIZE)
1424 return EINVAL; 1518 return EINVAL;
1425 1519
1426 /* 1520 _MALLOC_LOCK();
1427 * max(size, alignment) is enough to assure the requested alignment, 1521 malloc_func = " in posix_memalign():";
1428 * since the allocator always allocates power-of-two blocks. 1522 if (g_pool == NULL) {
1429 */ 1523 if (malloc_init() != 0)
1430 if (size < alignment) 1524 goto err;
1431 size = alignment; 1525 }
1432 result = malloc(size); 1526 if (malloc_active++) {
1433 1527 malloc_recurse();
1434 if (result == NULL) 1528 goto err;
1435 return ENOMEM; 1529 }
1436 1530 r = omemalign(alignment, size, mopts.malloc_zero, CALLER);
1437 *memptr = result; 1531 malloc_active--;
1532 _MALLOC_UNLOCK();
1533 if (r == NULL) {
1534 if (mopts.malloc_xmalloc) {
1535 wrterror("out of memory", NULL);
1536 errno = ENOMEM;
1537 }
1538 goto err;
1539 }
1540 errno = saved_errno;
1541 *memptr = r;
1438 return 0; 1542 return 0;
1543
1544err:
1545 res = errno;
1546 errno = saved_errno;
1547 return res;
1439} 1548}
1440 1549
1441#ifdef MALLOC_STATS 1550#ifdef MALLOC_STATS
diff --git a/src/lib/libc/stdlib/posix_memalign.3 b/src/lib/libc/stdlib/posix_memalign.3
index 46b74af7be..05ec1b9d14 100644
--- a/src/lib/libc/stdlib/posix_memalign.3
+++ b/src/lib/libc/stdlib/posix_memalign.3
@@ -1,4 +1,4 @@
1.\" $OpenBSD: posix_memalign.3,v 1.2 2010/05/19 06:32:43 jmc Exp $ 1.\" $OpenBSD: posix_memalign.3,v 1.3 2012/06/18 17:03:52 matthew Exp $
2.\" Copyright (C) 2006 Jason Evans <jasone@FreeBSD.org>. 2.\" Copyright (C) 2006 Jason Evans <jasone@FreeBSD.org>.
3.\" All rights reserved. 3.\" All rights reserved.
4.\" 4.\"
@@ -28,7 +28,7 @@
28.\" 28.\"
29.\" $FreeBSD: src/lib/libc/stdlib/posix_memalign.3,v 1.3 2007/03/28 04:32:51 jasone Exp $ 29.\" $FreeBSD: src/lib/libc/stdlib/posix_memalign.3,v 1.3 2007/03/28 04:32:51 jasone Exp $
30.\" 30.\"
31.Dd $Mdocdate: May 19 2010 $ 31.Dd $Mdocdate: June 18 2012 $
32.Dt POSIX_MEMALIGN 3 32.Dt POSIX_MEMALIGN 3
33.Os 33.Os
34.Sh NAME 34.Sh NAME
@@ -90,5 +90,3 @@ The
90.Fn posix_memalign 90.Fn posix_memalign
91function first appeared in 91function first appeared in
92.Ox 4.8 . 92.Ox 4.8 .
93.Sh BUGS
94Only alignments up to the page size can be specified.