From 0a0bbf63e5d9bc60d6854c6d46b437fbeebd1470 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 13 Mar 2012 12:55:21 -0700 Subject: [PATCH] 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. --- Makefile.in | 6 +- configure.ac | 2 +- doc/jemalloc.xml.in | 35 ++++++++ include/jemalloc/jemalloc.h.in | 3 + include/jemalloc/jemalloc_defs.h.in | 1 + src/jemalloc.c | 37 ++++++--- test/aligned_alloc.c | 123 ++++++++++++++++++++++++++++ test/aligned_alloc.exp | 25 ++++++ 8 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 test/aligned_alloc.c create mode 100644 test/aligned_alloc.exp diff --git a/Makefile.in b/Makefile.in index 62864556..01ed083c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -63,9 +63,9 @@ DOCS_XML := @objroot@doc/jemalloc@install_suffix@.xml DOCS_HTML := $(DOCS_XML:@objroot@%.xml=@srcroot@%.html) DOCS_MAN3 := $(DOCS_XML:@objroot@%.xml=@srcroot@%.3) DOCS := $(DOCS_HTML) $(DOCS_MAN3) -CTESTS := @srcroot@test/allocated.c @srcroot@test/bitmap.c \ - @srcroot@test/mremap.c @srcroot@test/posix_memalign.c \ - @srcroot@test/thread_arena.c +CTESTS := @srcroot@test/aligned_alloc.c @srcroot@test/allocated.c \ + @srcroot@test/bitmap.c @srcroot@test/mremap.c \ + @srcroot@test/posix_memalign.c @srcroot@test/thread_arena.c ifeq (@enable_experimental@, 1) CTESTS += @srcroot@test/allocm.c @srcroot@test/rallocm.c endif diff --git a/configure.ac b/configure.ac index a5ca859b..295e646d 100644 --- a/configure.ac +++ b/configure.ac @@ -316,7 +316,7 @@ AC_PATH_PROG([AR], [ar], , [$PATH]) AC_PATH_PROG([LD], [ld], , [$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. AC_CHECK_FUNC([memalign], diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 74da409f..926deafe 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -30,6 +30,7 @@ malloc calloc posix_memalign + aligned_alloc realloc free malloc_usable_size @@ -73,6 +74,11 @@ size_t alignment size_t size + + void *aligned_alloc + size_t alignment + size_t size + void *realloc void *ptr @@ -190,6 +196,14 @@ alignment must be a power of 2 at least as large as sizeof(void *). + The aligned_alloc function + allocates size bytes of memory such that the + allocation's base address is an even multiple of + alignment. The requested + alignment must be a power of 2. Behavior is + undefined if size is not an integral multiple of + alignment. + The realloc function changes the size of the previously allocated memory referenced by ptr to size bytes. The @@ -1789,6 +1803,27 @@ malloc_conf = "xmalloc:true";]]> + The aligned_alloc function returns + a pointer to the allocated memory if successful; otherwise a + NULL pointer is returned and + errno is set. The + aligned_alloc function will fail if: + + + EINVAL + + The alignment parameter is + not a power of 2. + + + + ENOMEM + + Memory allocation error. + + + + The realloc function returns a pointer, possibly identical to ptr, to the allocated memory if successful; otherwise a NULL diff --git a/include/jemalloc/jemalloc.h.in b/include/jemalloc/jemalloc.h.in index 742daddd..f0581dbd 100644 --- a/include/jemalloc/jemalloc.h.in +++ b/include/jemalloc/jemalloc.h.in @@ -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); int je_posix_memalign(void **memptr, size_t alignment, size_t size) 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_free(void *ptr); @@ -82,6 +83,7 @@ int je_nallocm(size_t *rsize, size_t size, int flags); #define malloc je_malloc #define calloc je_calloc #define posix_memalign je_posix_memalign +#define aligned_alloc je_aligned_alloc #define realloc je_realloc #define free je_free #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_calloc #undef je_posix_memalign +#undef je_aligned_alloc #undef je_realloc #undef je_free #undef je_malloc_usable_size diff --git a/include/jemalloc/jemalloc_defs.h.in b/include/jemalloc/jemalloc_defs.h.in index 6b2b0d01..f8f80e62 100644 --- a/include/jemalloc/jemalloc_defs.h.in +++ b/include/jemalloc/jemalloc_defs.h.in @@ -16,6 +16,7 @@ #undef je_malloc #undef je_calloc #undef je_posix_memalign +#undef je_aligned_alloc #undef je_realloc #undef je_free #undef je_malloc_usable_size diff --git a/src/jemalloc.c b/src/jemalloc.c index f564b65e..2f3f3722 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -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 bool malloc_init_hard(void); 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 static int imemalign(void **memptr, size_t alignment, size_t size, - bool enforce_min_alignment) + size_t min_alignment) { int ret; size_t usize; @@ -862,6 +862,8 @@ imemalign(void **memptr, size_t alignment, size_t size, #endif ; + assert(min_alignment != 0); + if (malloc_init()) result = NULL; 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. */ if (((alignment - 1) & alignment) != 0 - || (enforce_min_alignment && alignment < sizeof(void *))) { + || (alignment < min_alignment)) { if (config_xmalloc && opt_xmalloc) { - malloc_write(": Error in " - "posix_memalign(): invalid alignment\n"); + malloc_write(": Error allocating " + "aligned memory: invalid alignment\n"); abort(); } result = NULL; @@ -915,8 +917,8 @@ imemalign(void **memptr, size_t alignment, size_t size, if (result == NULL) { if (config_xmalloc && opt_xmalloc) { - malloc_write(": Error in posix_memalign(): " - "out of memory\n"); + malloc_write(": Error allocating aligned " + "memory: out of memory\n"); abort(); } ret = ENOMEM; @@ -942,7 +944,22 @@ int 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) @@ -1196,7 +1213,7 @@ je_memalign(size_t alignment, size_t size) = NULL #endif ; - imemalign(&ret, alignment, size, false); + imemalign(&ret, alignment, size, 1); return (ret); } #endif @@ -1212,7 +1229,7 @@ je_valloc(size_t size) = NULL #endif ; - imemalign(&ret, PAGE_SIZE, size, false); + imemalign(&ret, PAGE_SIZE, size, 1); return (ret); } #endif diff --git a/test/aligned_alloc.c b/test/aligned_alloc.c new file mode 100644 index 00000000..2a95604f --- /dev/null +++ b/test/aligned_alloc.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/test/aligned_alloc.exp b/test/aligned_alloc.exp new file mode 100644 index 00000000..b5061c72 --- /dev/null +++ b/test/aligned_alloc.exp @@ -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