summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2012-06-18 17:03:53 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2012-06-18 17:03:53 +0000
commitc68a2702b1752fe6c03e138edb72fee4f93d215a (patch)
treef45a801997441e06da3238e23468a682c862fd5f
parent120e6b0ec214f1b5d3fc4373cfb944692ffff7fa (diff)
Support larger-than-page-alignment requests in posix_memalign() by
overallocating and then releasing unneeded memory pages. ok otto
-rw-r--r--lib/libc/stdlib/malloc.c147
-rw-r--r--lib/libc/stdlib/posix_memalign.36
2 files changed, 130 insertions, 23 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index 6aba00e4a0b..6f646934b22 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.c,v 1.141 2012/02/29 08:44:14 otto Exp $ */
+/* $OpenBSD: malloc.c,v 1.142 2012/06/18 17:03:51 matthew Exp $ */
/*
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
*
@@ -389,7 +389,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
wrterror("internal struct corrupt", NULL);
if (sz != PAGEROUND(sz)) {
wrterror("map round", NULL);
- return NULL;
+ return MAP_FAILED;
}
if (psz > d->free_regions_size) {
p = MMAP(sz);
@@ -1295,8 +1295,10 @@ orealloc(void *p, size_t newsz, void *f)
STATS_SETF(r, f);
STATS_INC(g_pool->cheap_reallocs);
return p;
- } else if (q != MAP_FAILED)
- munmap(q, rnewsz - roldsz);
+ } else if (q != MAP_FAILED) {
+ if (munmap(q, rnewsz - roldsz))
+ wrterror("munmap", q);
+ }
}
} else if (rnewsz < roldsz) {
if (mopts.malloc_guard) {
@@ -1413,29 +1415,136 @@ calloc(size_t nmemb, size_t size)
return r;
}
+static void *
+mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill)
+{
+ void *p, *q;
+
+ if (alignment < MALLOC_PAGESIZE || alignment & (alignment - 1) != 0) {
+ wrterror("mapalign bad alignment", NULL);
+ return MAP_FAILED;
+ }
+ if (sz != PAGEROUND(sz)) {
+ wrterror("mapalign round", NULL);
+ return MAP_FAILED;
+ }
+
+ /* Allocate sz + alignment bytes of memory, which must include a
+ * subrange of size bytes that is properly aligned. Unmap the
+ * other bytes, and then return that subrange.
+ */
+
+ /* We need sz + alignment to fit into a size_t. */
+ if (alignment > SIZE_MAX - sz)
+ return MAP_FAILED;
+
+ p = map(d, sz + alignment, zero_fill);
+ if (p == MAP_FAILED)
+ return MAP_FAILED;
+ q = (void *)(((uintptr_t)p + alignment - 1) & ~(alignment - 1));
+ if (q != p) {
+ if (munmap(p, q - p))
+ wrterror("munmap", p);
+ }
+ if (munmap(q + sz, alignment - (q - p)))
+ wrterror("munmap", q + sz);
+ malloc_used -= alignment;
+
+ return q;
+}
+
+static void *
+omemalign(size_t alignment, size_t sz, int zero_fill, void *f)
+{
+ size_t psz;
+ void *p;
+
+ if (alignment <= MALLOC_PAGESIZE) {
+ /*
+ * max(size, alignment) is enough to assure the requested alignment,
+ * since the allocator always allocates power-of-two blocks.
+ */
+ if (sz < alignment)
+ sz = alignment;
+ return omalloc(sz, zero_fill, f);
+ }
+
+ if (sz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ sz += mopts.malloc_guard;
+ psz = PAGEROUND(sz);
+
+ p = mapalign(g_pool, alignment, psz, zero_fill);
+ if (p == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (insert(g_pool, p, sz, f)) {
+ unmap(g_pool, p, psz);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (mopts.malloc_guard) {
+ if (mprotect((char *)p + psz - mopts.malloc_guard,
+ mopts.malloc_guard, PROT_NONE))
+ wrterror("mprotect", NULL);
+ malloc_guarded += mopts.malloc_guard;
+ }
+
+ if (mopts.malloc_junk) {
+ if (zero_fill)
+ memset((char *)p + sz - mopts.malloc_guard,
+ SOME_JUNK, psz - sz);
+ else
+ memset(p, SOME_JUNK, psz - mopts.malloc_guard);
+ }
+
+ return p;
+}
+
int
posix_memalign(void **memptr, size_t alignment, size_t size)
{
- void *result;
+ int res, saved_errno = errno;
+ void *r;
/* Make sure that alignment is a large enough power of 2. */
- if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *) ||
- alignment > MALLOC_PAGESIZE)
+ if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *))
return EINVAL;
- /*
- * max(size, alignment) is enough to assure the requested alignment,
- * since the allocator always allocates power-of-two blocks.
- */
- if (size < alignment)
- size = alignment;
- result = malloc(size);
-
- if (result == NULL)
- return ENOMEM;
-
- *memptr = result;
+ _MALLOC_LOCK();
+ malloc_func = " in posix_memalign():";
+ if (g_pool == NULL) {
+ if (malloc_init() != 0)
+ goto err;
+ }
+ if (malloc_active++) {
+ malloc_recurse();
+ goto err;
+ }
+ r = omemalign(alignment, size, mopts.malloc_zero, CALLER);
+ malloc_active--;
+ _MALLOC_UNLOCK();
+ if (r == NULL) {
+ if (mopts.malloc_xmalloc) {
+ wrterror("out of memory", NULL);
+ errno = ENOMEM;
+ }
+ goto err;
+ }
+ errno = saved_errno;
+ *memptr = r;
return 0;
+
+err:
+ res = errno;
+ errno = saved_errno;
+ return res;
}
#ifdef MALLOC_STATS
diff --git a/lib/libc/stdlib/posix_memalign.3 b/lib/libc/stdlib/posix_memalign.3
index 46b74af7bef..05ec1b9d148 100644
--- a/lib/libc/stdlib/posix_memalign.3
+++ b/lib/libc/stdlib/posix_memalign.3
@@ -1,4 +1,4 @@
-.\" $OpenBSD: posix_memalign.3,v 1.2 2010/05/19 06:32:43 jmc Exp $
+.\" $OpenBSD: posix_memalign.3,v 1.3 2012/06/18 17:03:52 matthew Exp $
.\" Copyright (C) 2006 Jason Evans <jasone@FreeBSD.org>.
.\" All rights reserved.
.\"
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD: src/lib/libc/stdlib/posix_memalign.3,v 1.3 2007/03/28 04:32:51 jasone Exp $
.\"
-.Dd $Mdocdate: May 19 2010 $
+.Dd $Mdocdate: June 18 2012 $
.Dt POSIX_MEMALIGN 3
.Os
.Sh NAME
@@ -90,5 +90,3 @@ The
.Fn posix_memalign
function first appeared in
.Ox 4.8 .
-.Sh BUGS
-Only alignments up to the page size can be specified.