diff options
author | matthew <> | 2012-06-18 17:03:52 +0000 |
---|---|---|
committer | matthew <> | 2012-06-18 17:03:52 +0000 |
commit | 71b2db593f575c8e8ada85098d2b61ee7f67408b (patch) | |
tree | f92bf32b94fe50878ccc250509462e743ce99ce6 | |
parent | 0e75ebe6fc3d4043e79e7c89766f56e43c180169 (diff) | |
download | openbsd-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.c | 147 | ||||
-rw-r--r-- | src/lib/libc/stdlib/posix_memalign.3 | 6 |
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 | ||
1418 | static void * | ||
1419 | mapalign(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 | |||
1456 | static void * | ||
1457 | omemalign(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 | |||
1416 | int | 1510 | int |
1417 | posix_memalign(void **memptr, size_t alignment, size_t size) | 1511 | posix_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 | |||
1544 | err: | ||
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 |
91 | function first appeared in | 91 | function first appeared in |
92 | .Ox 4.8 . | 92 | .Ox 4.8 . |
93 | .Sh BUGS | ||
94 | Only alignments up to the page size can be specified. | ||