Browse Source

Support larger-than-page-alignment requests in posix_memalign() by

overallocating and then releasing unneeded memory pages.
ok otto
OPENBSD_5_2
matthew 12 years ago
parent
commit
5294f450b0
2 changed files with 130 additions and 23 deletions
  1. +128
    -19
      src/lib/libc/stdlib/malloc.c
  2. +2
    -4
      src/lib/libc/stdlib/posix_memalign.3

+ 128
- 19
src/lib/libc/stdlib/malloc.c View File

@ -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


+ 2
- 4
src/lib/libc/stdlib/posix_memalign.3 View File

@ -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.

Loading…
Cancel
Save