From: Bruno Haible <bruno@clisp.org>
Date: Tue, 21 Jul 2020 16:09:35 +0000 (+0200)
Subject: aligned-malloc: Optionally use aligned_alloc.
X-Git-Tag: v1.0~3874
X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=ac34618e85013bfec4650f02e8e79c5de6d80fb3;p=gnulib.git

aligned-malloc: Optionally use aligned_alloc.

* lib/aligned-malloc.h: Verify the alignment.
(aligned_malloc): Use aligned_alloc as an alternative.
* modules/aligned-malloc (configure.ac): Test for aligned_alloc.
* doc/posix-functions/aligned_alloc.texi: Mention the modules
'aligned-malloc' and 'pagealign_alloc'.
---

diff --git a/ChangeLog b/ChangeLog
index 8da483c857..8cac948ad2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2020-07-21  Bruno Haible  <bruno@clisp.org>
+
+	aligned-malloc: Optionally use aligned_alloc.
+	* lib/aligned-malloc.h: Verify the alignment.
+	(aligned_malloc): Use aligned_alloc as an alternative.
+	* modules/aligned-malloc (configure.ac): Test for aligned_alloc.
+	* doc/posix-functions/aligned_alloc.texi: Mention the modules
+	'aligned-malloc' and 'pagealign_alloc'.
+
 2020-07-21  Bruno Haible  <bruno@clisp.org>
 
 	aligned-malloc: Add tests.
diff --git a/doc/posix-functions/aligned_alloc.texi b/doc/posix-functions/aligned_alloc.texi
index c938f30d71..a4897b9167 100644
--- a/doc/posix-functions/aligned_alloc.texi
+++ b/doc/posix-functions/aligned_alloc.texi
@@ -16,3 +16,9 @@ Portability problems not fixed by Gnulib:
 This function is missing on all non-glibc platforms:
 glibc 2.15, Mac OS X 10.5, FreeBSD 6.4, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 7.1, HP-UX 11.31, IRIX 6.5, Solaris 11.3, Cygwin, mingw, MSVC 14, Android 8.1.
 @end itemize
+
+The Gnulib module @code{aligned-malloc} provides functions for
+allocating and freeing blocks of suitably aligned memory.
+
+The Gnulib module @code{pagealign_alloc} provides a similar API for
+allocating and freeing blocks of memory aligned on a system page boundary.
diff --git a/lib/aligned-malloc.h b/lib/aligned-malloc.h
index 86382fd25b..9baaab4cfe 100644
--- a/lib/aligned-malloc.h
+++ b/lib/aligned-malloc.h
@@ -29,17 +29,29 @@
    The block can be freed through aligned_free(), NOT through free().
    Upon failure, it returns NULL.  */
 
-/* This module exists instead of a posix_memalign() or memalign() emulation,
-   because we can't reasonably emulate posix_memalign() or memalign():
+/* This module exists instead of a posix_memalign(), aligned_alloc(), or
+   memalign() emulation, because we can't reasonably emulate posix_memalign(),
+   aligned_alloc(), or memalign():
    If malloc() returned p, only free (p) is allowed, not free (p + 1),
    free (p + 2), free (p + 4), free (p + 8), or similar.
 
-   We can use posix_memalign().  On older systems, we can alternatively use
-   memalign() instead.  In the Solaris documentation of memalign() it is not
-   specified how a memory block returned by memalign() can be freed, but
-   it actually can be freed with free().  */
+   We can use posix_memalign(), a POSIX function.
 
-#if ((ALIGNMENT) <= MALLOC_ALIGNMENT) || HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN
+   We can also use aligned_alloc(), an ISO C11 and POSIX function.  But it's
+   a bit more awkward to use.
+
+   On older systems, we can alternatively use memalign() instead.  In the
+   Solaris documentation of memalign() it is not specified how a memory block
+   returned by memalign() can be freed, but it actually can be freed with
+   free().  */
+
+#if !defined ALIGNMENT
+# error "ALIGNMENT is not defined"
+#endif
+#if !((ALIGNMENT) > 0 && ((ALIGNMENT) & ((ALIGNMENT) - 1)) == 0)
+# error "ALIGNMENT is not a power of 2"
+#endif
+#if ((ALIGNMENT) <= MALLOC_ALIGNMENT) || HAVE_POSIX_MEMALIGN || HAVE_ALIGNED_ALLOC || HAVE_MEMALIGN
 
 # if (ALIGNMENT) <= MALLOC_ALIGNMENT
 /* Simply use malloc.  */
@@ -70,6 +82,23 @@ aligned_malloc (size_t size)
     return NULL;
 }
 
+# elif HAVE_ALIGNED_ALLOC
+/* Use aligned_alloc.  */
+
+static inline void *
+aligned_malloc (size_t size)
+{
+  /* Round up SIZE to the next multiple of ALIGNMENT,
+     namely (SIZE + ALIGNMENT - 1) & ~(ALIGNMENT - 1).  */
+  size += (ALIGNMENT) - 1;
+  if (size >= (ALIGNMENT) - 1) /* no overflow? */
+    {
+      size &= ~(size_t)((ALIGNMENT) - 1);
+      return aligned_alloc ((ALIGNMENT), size);
+    }
+  return NULL;
+}
+
 # elif HAVE_MEMALIGN                    /* HP-UX, IRIX, Solaris <= 10 */
 /* Use memalign.  */
 
diff --git a/modules/aligned-malloc b/modules/aligned-malloc
index 29483d83d7..d562e3d6b9 100644
--- a/modules/aligned-malloc
+++ b/modules/aligned-malloc
@@ -11,7 +11,7 @@ stdint
 configure.ac:
 gl_MALLOC_ALIGNMENT
 AC_REQUIRE([AC_C_INLINE])
-AC_CHECK_FUNCS([posix_memalign memalign])
+AC_CHECK_FUNCS([posix_memalign aligned_alloc memalign])
 
 Makefile.am: