Implement aligned_alloc().

Implement aligned_alloc(), which was added in the C11 standard.  The
function is weakly specified to the point that a minimally compliant
implementation would be painful to use (size must be an integral
multiple of alignment!), which in practice makes posix_memalign() a
safer choice.
This commit is contained in:
Jason Evans 2012-03-13 12:55:21 -07:00
parent 4c2faa8a7c
commit 0a0bbf63e5
8 changed files with 218 additions and 14 deletions

View File

@ -63,9 +63,9 @@ DOCS_XML := @objroot@doc/jemalloc@install_suffix@.xml
DOCS_HTML := $(DOCS_XML:@objroot@%.xml=@srcroot@%.html) DOCS_HTML := $(DOCS_XML:@objroot@%.xml=@srcroot@%.html)
DOCS_MAN3 := $(DOCS_XML:@objroot@%.xml=@srcroot@%.3) DOCS_MAN3 := $(DOCS_XML:@objroot@%.xml=@srcroot@%.3)
DOCS := $(DOCS_HTML) $(DOCS_MAN3) DOCS := $(DOCS_HTML) $(DOCS_MAN3)
CTESTS := @srcroot@test/allocated.c @srcroot@test/bitmap.c \ CTESTS := @srcroot@test/aligned_alloc.c @srcroot@test/allocated.c \
@srcroot@test/mremap.c @srcroot@test/posix_memalign.c \ @srcroot@test/bitmap.c @srcroot@test/mremap.c \
@srcroot@test/thread_arena.c @srcroot@test/posix_memalign.c @srcroot@test/thread_arena.c
ifeq (@enable_experimental@, 1) ifeq (@enable_experimental@, 1)
CTESTS += @srcroot@test/allocm.c @srcroot@test/rallocm.c CTESTS += @srcroot@test/allocm.c @srcroot@test/rallocm.c
endif endif

View File

@ -316,7 +316,7 @@ AC_PATH_PROG([AR], [ar], , [$PATH])
AC_PATH_PROG([LD], [ld], , [$PATH]) AC_PATH_PROG([LD], [ld], , [$PATH])
AC_PATH_PROG([AUTOCONF], [autoconf], , [$PATH]) AC_PATH_PROG([AUTOCONF], [autoconf], , [$PATH])
public_syms="malloc_conf malloc_message malloc calloc posix_memalign realloc free malloc_usable_size malloc_stats_print mallctl mallctlnametomib mallctlbymib" public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free malloc_usable_size malloc_stats_print mallctl mallctlnametomib mallctlbymib"
dnl Check for allocator-related functions that should be wrapped. dnl Check for allocator-related functions that should be wrapped.
AC_CHECK_FUNC([memalign], AC_CHECK_FUNC([memalign],

View File

@ -30,6 +30,7 @@
<refname>malloc</refname> <refname>malloc</refname>
<refname>calloc</refname> <refname>calloc</refname>
<refname>posix_memalign</refname> <refname>posix_memalign</refname>
<refname>aligned_alloc</refname>
<refname>realloc</refname> <refname>realloc</refname>
<refname>free</refname> <refname>free</refname>
<refname>malloc_usable_size</refname> <refname>malloc_usable_size</refname>
@ -73,6 +74,11 @@
<paramdef>size_t <parameter>alignment</parameter></paramdef> <paramdef>size_t <parameter>alignment</parameter></paramdef>
<paramdef>size_t <parameter>size</parameter></paramdef> <paramdef>size_t <parameter>size</parameter></paramdef>
</funcprototype> </funcprototype>
<funcprototype>
<funcdef>void *<function>aligned_alloc</function></funcdef>
<paramdef>size_t <parameter>alignment</parameter></paramdef>
<paramdef>size_t <parameter>size</parameter></paramdef>
</funcprototype>
<funcprototype> <funcprototype>
<funcdef>void *<function>realloc</function></funcdef> <funcdef>void *<function>realloc</function></funcdef>
<paramdef>void *<parameter>ptr</parameter></paramdef> <paramdef>void *<parameter>ptr</parameter></paramdef>
@ -190,6 +196,14 @@
<parameter>alignment</parameter> must be a power of 2 at least as large <parameter>alignment</parameter> must be a power of 2 at least as large
as <code language="C">sizeof(<type>void *</type>)</code>.</para> as <code language="C">sizeof(<type>void *</type>)</code>.</para>
<para>The <function>aligned_alloc<parameter/></function> function
allocates <parameter>size</parameter> bytes of memory such that the
allocation's base address is an even multiple of
<parameter>alignment</parameter>. The requested
<parameter>alignment</parameter> must be a power of 2. Behavior is
undefined if <parameter>size</parameter> is not an integral multiple of
<parameter>alignment</parameter>.</para>
<para>The <function>realloc<parameter/></function> function changes the <para>The <function>realloc<parameter/></function> function changes the
size of the previously allocated memory referenced by size of the previously allocated memory referenced by
<parameter>ptr</parameter> to <parameter>size</parameter> bytes. The <parameter>ptr</parameter> to <parameter>size</parameter> bytes. The
@ -1789,6 +1803,27 @@ malloc_conf = "xmalloc:true";]]></programlisting>
</variablelist> </variablelist>
</para> </para>
<para>The <function>aligned_alloc<parameter/></function> function returns
a pointer to the allocated memory if successful; otherwise a
<constant>NULL</constant> pointer is returned and
<varname>errno</varname> is set. The
<function>aligned_alloc<parameter/></function> function will fail if:
<variablelist>
<varlistentry>
<term><errorname>EINVAL</errorname></term>
<listitem><para>The <parameter>alignment</parameter> parameter is
not a power of 2.
</para></listitem>
</varlistentry>
<varlistentry>
<term><errorname>ENOMEM</errorname></term>
<listitem><para>Memory allocation error.</para></listitem>
</varlistentry>
</variablelist>
</para>
<para>The <function>realloc<parameter/></function> function returns a <para>The <function>realloc<parameter/></function> function returns a
pointer, possibly identical to <parameter>ptr</parameter>, to the pointer, possibly identical to <parameter>ptr</parameter>, to the
allocated memory if successful; otherwise a <constant>NULL</constant> allocated memory if successful; otherwise a <constant>NULL</constant>

View File

@ -43,6 +43,7 @@ void *je_malloc(size_t size) JEMALLOC_ATTR(malloc);
void *je_calloc(size_t num, size_t size) JEMALLOC_ATTR(malloc); void *je_calloc(size_t num, size_t size) JEMALLOC_ATTR(malloc);
int je_posix_memalign(void **memptr, size_t alignment, size_t size) int je_posix_memalign(void **memptr, size_t alignment, size_t size)
JEMALLOC_ATTR(nonnull(1)); JEMALLOC_ATTR(nonnull(1));
void *je_aligned_alloc(size_t alignment, size_t size) JEMALLOC_ATTR(malloc);
void *je_realloc(void *ptr, size_t size); void *je_realloc(void *ptr, size_t size);
void je_free(void *ptr); void je_free(void *ptr);
@ -82,6 +83,7 @@ int je_nallocm(size_t *rsize, size_t size, int flags);
#define malloc je_malloc #define malloc je_malloc
#define calloc je_calloc #define calloc je_calloc
#define posix_memalign je_posix_memalign #define posix_memalign je_posix_memalign
#define aligned_alloc je_aligned_alloc
#define realloc je_realloc #define realloc je_realloc
#define free je_free #define free je_free
#define malloc_usable_size je_malloc_usable_size #define malloc_usable_size je_malloc_usable_size
@ -113,6 +115,7 @@ int je_nallocm(size_t *rsize, size_t size, int flags);
#undef je_malloc #undef je_malloc
#undef je_calloc #undef je_calloc
#undef je_posix_memalign #undef je_posix_memalign
#undef je_aligned_alloc
#undef je_realloc #undef je_realloc
#undef je_free #undef je_free
#undef je_malloc_usable_size #undef je_malloc_usable_size

View File

@ -16,6 +16,7 @@
#undef je_malloc #undef je_malloc
#undef je_calloc #undef je_calloc
#undef je_posix_memalign #undef je_posix_memalign
#undef je_aligned_alloc
#undef je_realloc #undef je_realloc
#undef je_free #undef je_free
#undef je_malloc_usable_size #undef je_malloc_usable_size

View File

@ -68,7 +68,7 @@ static void malloc_conf_error(const char *msg, const char *k, size_t klen,
static void malloc_conf_init(void); static void malloc_conf_init(void);
static bool malloc_init_hard(void); static bool malloc_init_hard(void);
static int imemalign(void **memptr, size_t alignment, size_t size, static int imemalign(void **memptr, size_t alignment, size_t size,
bool enforce_min_alignment); size_t min_alignment);
/******************************************************************************/ /******************************************************************************/
/* /*
@ -851,7 +851,7 @@ JEMALLOC_ATTR(noinline)
#endif #endif
static int static int
imemalign(void **memptr, size_t alignment, size_t size, imemalign(void **memptr, size_t alignment, size_t size,
bool enforce_min_alignment) size_t min_alignment)
{ {
int ret; int ret;
size_t usize; size_t usize;
@ -862,6 +862,8 @@ imemalign(void **memptr, size_t alignment, size_t size,
#endif #endif
; ;
assert(min_alignment != 0);
if (malloc_init()) if (malloc_init())
result = NULL; result = NULL;
else { else {
@ -870,10 +872,10 @@ imemalign(void **memptr, size_t alignment, size_t size,
/* Make sure that alignment is a large enough power of 2. */ /* Make sure that alignment is a large enough power of 2. */
if (((alignment - 1) & alignment) != 0 if (((alignment - 1) & alignment) != 0
|| (enforce_min_alignment && alignment < sizeof(void *))) { || (alignment < min_alignment)) {
if (config_xmalloc && opt_xmalloc) { if (config_xmalloc && opt_xmalloc) {
malloc_write("<jemalloc>: Error in " malloc_write("<jemalloc>: Error allocating "
"posix_memalign(): invalid alignment\n"); "aligned memory: invalid alignment\n");
abort(); abort();
} }
result = NULL; result = NULL;
@ -915,8 +917,8 @@ imemalign(void **memptr, size_t alignment, size_t size,
if (result == NULL) { if (result == NULL) {
if (config_xmalloc && opt_xmalloc) { if (config_xmalloc && opt_xmalloc) {
malloc_write("<jemalloc>: Error in posix_memalign(): " malloc_write("<jemalloc>: Error allocating aligned "
"out of memory\n"); "memory: out of memory\n");
abort(); abort();
} }
ret = ENOMEM; ret = ENOMEM;
@ -942,7 +944,22 @@ int
je_posix_memalign(void **memptr, size_t alignment, size_t size) je_posix_memalign(void **memptr, size_t alignment, size_t size)
{ {
return imemalign(memptr, alignment, size, true); return imemalign(memptr, alignment, size, sizeof(void *));
}
JEMALLOC_ATTR(malloc)
JEMALLOC_ATTR(visibility("default"))
void *
je_aligned_alloc(size_t alignment, size_t size)
{
void *ret;
int err;
if ((err = imemalign(&ret, alignment, size, 1)) != 0) {
ret = NULL;
errno = err;
}
return (ret);
} }
JEMALLOC_ATTR(malloc) JEMALLOC_ATTR(malloc)
@ -1196,7 +1213,7 @@ je_memalign(size_t alignment, size_t size)
= NULL = NULL
#endif #endif
; ;
imemalign(&ret, alignment, size, false); imemalign(&ret, alignment, size, 1);
return (ret); return (ret);
} }
#endif #endif
@ -1212,7 +1229,7 @@ je_valloc(size_t size)
= NULL = NULL
#endif #endif
; ;
imemalign(&ret, PAGE_SIZE, size, false); imemalign(&ret, PAGE_SIZE, size, 1);
return (ret); return (ret);
} }
#endif #endif

123
test/aligned_alloc.c Normal file
View File

@ -0,0 +1,123 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define JEMALLOC_MANGLE
#include "jemalloc_test.h"
#define CHUNK 0x400000
/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */
#define MAXALIGN ((size_t)0x2000000LU)
#define NITER 4
int
main(void)
{
size_t alignment, size, total;
unsigned i;
void *p, *ps[NITER];
fprintf(stderr, "Test begin\n");
/* Test error conditions. */
alignment = 0;
errno = 0;
p = aligned_alloc(alignment, 1);
if (p != NULL || errno != EINVAL) {
fprintf(stderr,
"Expected error for invalid alignment %zu\n", alignment);
}
for (alignment = sizeof(size_t); alignment < MAXALIGN;
alignment <<= 1) {
errno = 0;
p = aligned_alloc(alignment + 1, 1);
if (p != NULL || errno != EINVAL) {
fprintf(stderr,
"Expected error for invalid alignment %zu\n",
alignment + 1);
}
}
#if LG_SIZEOF_PTR == 3
alignment = UINT64_C(0x8000000000000000);
size = UINT64_C(0x8000000000000000);
#else
alignment = 0x80000000LU;
size = 0x80000000LU;
#endif
errno = 0;
p = aligned_alloc(alignment, size);
if (p != NULL || errno != ENOMEM) {
fprintf(stderr,
"Expected error for aligned_alloc(%zu, %zu)\n",
alignment, size);
}
#if LG_SIZEOF_PTR == 3
alignment = UINT64_C(0x4000000000000000);
size = UINT64_C(0x8400000000000001);
#else
alignment = 0x40000000LU;
size = 0x84000001LU;
#endif
errno = 0;
p = aligned_alloc(alignment, size);
if (p != NULL || errno != ENOMEM) {
fprintf(stderr,
"Expected error for aligned_alloc(%zu, %zu)\n",
alignment, size);
}
alignment = 0x10LU;
#if LG_SIZEOF_PTR == 3
size = UINT64_C(0xfffffffffffffff0);
#else
size = 0xfffffff0LU;
#endif
errno = 0;
p = aligned_alloc(alignment, size);
if (p != NULL || errno != ENOMEM) {
fprintf(stderr,
"Expected error for aligned_alloc(&p, %zu, %zu)\n",
alignment, size);
}
for (i = 0; i < NITER; i++)
ps[i] = NULL;
for (alignment = 8;
alignment <= MAXALIGN;
alignment <<= 1) {
total = 0;
fprintf(stderr, "Alignment: %zu\n", alignment);
for (size = 1;
size < 3 * alignment && size < (1U << 31);
size += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
for (i = 0; i < NITER; i++) {
ps[i] = aligned_alloc(alignment, size);
if (ps[i] == NULL) {
fprintf(stderr,
"Error for size %zu (%#zx): %s\n",
size, size, strerror(errno));
exit(1);
}
total += malloc_usable_size(ps[i]);
if (total >= (MAXALIGN << 1))
break;
}
for (i = 0; i < NITER; i++) {
if (ps[i] != NULL) {
free(ps[i]);
ps[i] = NULL;
}
}
}
}
fprintf(stderr, "Test end\n");
return (0);
}

25
test/aligned_alloc.exp Normal file
View File

@ -0,0 +1,25 @@
Test begin
Alignment: 8
Alignment: 16
Alignment: 32
Alignment: 64
Alignment: 128
Alignment: 256
Alignment: 512
Alignment: 1024
Alignment: 2048
Alignment: 4096
Alignment: 8192
Alignment: 16384
Alignment: 32768
Alignment: 65536
Alignment: 131072
Alignment: 262144
Alignment: 524288
Alignment: 1048576
Alignment: 2097152
Alignment: 4194304
Alignment: 8388608
Alignment: 16777216
Alignment: 33554432
Test end