]> Savannah Git Hosting - gnulib.git/commitdiff
aligned-malloc: New module.
authorBruno Haible <bruno@clisp.org>
Tue, 21 Jul 2020 08:03:42 +0000 (10:03 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 21 Jul 2020 08:37:17 +0000 (10:37 +0200)
* lib/aligned-malloc.h: New file.
* m4/malloc-align.m4: New file.
* modules/aligned-malloc: New file.
* doc/posix-functions/posix_memalign.texi: Mention the new module.
* doc/glibc-functions/memalign.texi: Likewise.

ChangeLog
doc/glibc-functions/memalign.texi
doc/posix-functions/posix_memalign.texi
lib/aligned-malloc.h [new file with mode: 0644]
m4/malloc-align.m4 [new file with mode: 0644]
modules/aligned-malloc [new file with mode: 0644]

index 654ad7c1ff5af19040c1b8a929fbf5b9e3b045ff..768b209b652dee92e3c35db6a9a324870ef80b95 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2020-07-21  Bruno Haible  <bruno@clisp.org>
+
+       aligned-malloc: New module.
+       * lib/aligned-malloc.h: New file.
+       * m4/malloc-align.m4: New file.
+       * modules/aligned-malloc: New file.
+       * doc/posix-functions/posix_memalign.texi: Mention the new module.
+       * doc/glibc-functions/memalign.texi: Likewise.
+
 2020-07-21  Bruno Haible  <bruno@clisp.org>
 
        inttypes: Fix PRI*PTR and SCN*PTR on 64-bit native Windows.
index a7e9715736aab65d191de6e87453d1532136dd06..0740f7373b67f8a1064c00e6d8a37bf23cc0c544 100644 (file)
@@ -27,3 +27,6 @@ Portability problems not fixed by Gnulib:
 This function is missing on some platforms:
 Mac OS X 10.5, FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11.00, mingw, MSVC 14.
 @end itemize
+
+The Gnulib module @code{aligned-malloc} provides functions for
+allocating and freeing blocks of suitably aligned memory.
index 53abc86291b2eebba0b68aedf1922eae8ab9e805..084841bd9af584cc35c8b699287a2398ac8567a5 100644 (file)
@@ -17,5 +17,8 @@ This function is missing on some platforms:
 Mac OS X 10.5, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 10, Cygwin 1.5.x, mingw, MSVC 14, Android 4.1.
 @end itemize
 
-The Gnulib module @code{pagealign_alloc} provides a similar API
-that returns memory aligned on a system page boundary.
+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
new file mode 100644 (file)
index 0000000..86382fd
--- /dev/null
@@ -0,0 +1,140 @@
+/* Allocate memory with indefinite extent and specified alignment.
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+/* Before including this file, you need to define the following macro:
+
+   ALIGNMENT      A constant expression that evaluates to the desired alignment
+                  (a power of 2).
+
+   And you also need to #include <stdint.h> and <stdlib.h>.  */
+
+/* aligned_malloc allocates a block of memory of SIZE bytes, aligned on a
+   boundary of ALIGNMENT bytes.
+   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():
+   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().  */
+
+#if ((ALIGNMENT) <= MALLOC_ALIGNMENT) || HAVE_POSIX_MEMALIGN || HAVE_MEMALIGN
+
+# if (ALIGNMENT) <= MALLOC_ALIGNMENT
+/* Simply use malloc.  */
+
+#  ifdef aligned_malloc
+   /* The caller wants an inline function, not a macro.  */
+static inline void *
+aligned_malloc (size_t size)
+{
+  return malloc (size);
+}
+#  else
+#   define aligned_malloc malloc
+#  endif
+
+# elif HAVE_POSIX_MEMALIGN
+/* Use posix_memalign.
+   This is OK since ALIGNMENT > MALLOC_ALIGNMENT >= sizeof (void *).  */
+
+static inline void *
+aligned_malloc (size_t size)
+{
+  void *p;
+  int ret = posix_memalign (&p, (ALIGNMENT), size);
+  if (ret == 0)
+    return p;
+  else
+    return NULL;
+}
+
+# elif HAVE_MEMALIGN                    /* HP-UX, IRIX, Solaris <= 10 */
+/* Use memalign.  */
+
+static inline void *
+aligned_malloc (size_t size)
+{
+  return memalign ((ALIGNMENT), size);
+}
+
+# endif
+
+# ifdef aligned_free
+   /* The caller wants an inline function, not a macro.  */
+static inline void
+aligned_free (void *q)
+{
+  free (q);
+}
+# else
+#  define aligned_free free
+# endif
+
+#else
+/* Use malloc and waste a bit of memory.  */
+
+static inline void *
+aligned_malloc (size_t size)
+{
+  size += (ALIGNMENT);
+  if (size >= (ALIGNMENT)) /* no overflow? */
+    {
+      void *p = malloc (size);
+      if (p != NULL)
+        {
+          /* Go to the next multiple of ALIGNMENT.  */
+          void *q =
+            (void *) (((uintptr_t) p + (ALIGNMENT)) & -(intptr_t)(ALIGNMENT));
+          /* Now q - p <= ALIGNMENT and
+             q - p >= MALLOC_ALIGNMENT >= sizeof (void *).
+             This is enough to store a back pointer to p.  */
+          ((void **) q)[-1] = p;
+          return q;
+        }
+    }
+  return NULL;
+}
+
+static inline void
+aligned_free (void *q)
+{
+  if (q != NULL)
+    {
+      if ((uintptr_t) q & ((ALIGNMENT) - 1))
+        /* Argument not aligned as expected.  */
+        abort ();
+      else
+        {
+          void *p = ((void **) q)[-1];
+          if (!((uintptr_t) p <= (uintptr_t) q
+                && (uintptr_t) q - (uintptr_t) p >= MALLOC_ALIGNMENT
+                && (uintptr_t) q - (uintptr_t) p <= (ALIGNMENT)))
+            abort ();
+          free (p);
+        }
+    }
+}
+
+#endif
diff --git a/m4/malloc-align.m4 b/m4/malloc-align.m4
new file mode 100644 (file)
index 0000000..7ee8343
--- /dev/null
@@ -0,0 +1,140 @@
+# malloc-align.m4 serial 1
+dnl Copyright (C) 2020 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Defines a C macro MALLOC_ALIGNMENT, whose value is a numeric constant,
+dnl a power of 2, with the property that
+dnl   (uintptr_t) malloc (N)
+dnl is always guaranteed to be a multiple of MALLOC_ALIGNMENT.
+
+AC_DEFUN([gl_MALLOC_ALIGNMENT],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CACHE_CHECK([for the malloc() alignment],
+    [gl_cv_malloc_alignment],
+    [gl_cv_malloc_alignment=
+     AC_RUN_IFELSE(
+       [AC_LANG_PROGRAM(
+          [[#include <stdio.h>
+            #include <stdlib.h>
+            #if defined _WIN32 && !defined __CYGWIN__
+            # include <inttypes.h>
+            /* uintptr_t is equivalent to 'unsigned long long' if _WIN64,
+               or to 'unsigned long' otherwise.  */
+            #else
+            # undef uintptr_t
+            # define uintptr_t unsigned long
+            #endif
+          ]],
+          [[FILE *fp = fopen ("conftest.out", "w");
+            if (fp == NULL)
+              return 1;
+            {
+              uintptr_t bits = 0;
+              bits |= (uintptr_t) malloc (1);
+              bits |= (uintptr_t) malloc (1);
+              bits |= (uintptr_t) malloc (1);
+              bits |= (uintptr_t) malloc (2);
+              bits |= (uintptr_t) malloc (2);
+              bits |= (uintptr_t) malloc (2);
+              bits |= (uintptr_t) malloc (3);
+              bits |= (uintptr_t) malloc (3);
+              bits |= (uintptr_t) malloc (3);
+              bits |= (uintptr_t) malloc (5);
+              bits |= (uintptr_t) malloc (8);
+              bits |= (uintptr_t) malloc (8);
+              bits |= (uintptr_t) malloc (13);
+              bits |= (uintptr_t) malloc (13);
+              bits |= (uintptr_t) malloc (19);
+              bits |= (uintptr_t) malloc (19);
+              bits |= (uintptr_t) malloc (28);
+              bits |= (uintptr_t) malloc (28);
+              bits |= (uintptr_t) malloc (37);
+              bits |= (uintptr_t) malloc (37);
+              bits |= (uintptr_t) malloc (73);
+              bits |= (uintptr_t) malloc (73);
+              bits |= (uintptr_t) malloc (117);
+              bits |= (uintptr_t) malloc (117);
+              bits |= (uintptr_t) malloc (351);
+              bits |= (uintptr_t) malloc (351);
+              bits |= (uintptr_t) malloc (914);
+              bits |= (uintptr_t) malloc (914);
+              bits |= (uintptr_t) malloc (1712);
+              bits |= (uintptr_t) malloc (1712);
+              bits |= (uintptr_t) malloc (4021);
+              bits |= (uintptr_t) malloc (4021);
+              bits |= (uintptr_t) malloc (7641);
+              bits |= (uintptr_t) malloc (7641);
+              bits |= (uintptr_t) malloc (17027);
+              bits |= (uintptr_t) malloc (17027);
+              bits |= (uintptr_t) malloc (81231);
+              bits |= (uintptr_t) malloc (81231);
+              fprintf (fp, "%u\n", (unsigned int) (((bits ^ (bits - 1)) + 1) >> 1));
+            }
+            if (fclose (fp) != 0)
+              return 2;
+            return 0;
+          ]])
+       ],
+       [gl_cv_malloc_alignment=`cat conftest.out`],
+       [gl_cv_malloc_alignment="unknown"],
+       [dnl When cross-compiling, guess a value. Note that it's OK to return
+        dnl a smaller value (e.g. 4 instead of 8 or 16).
+        gl_cv_malloc_alignment="unknown"
+        case "$host_os" in
+          linux* | mingw*)
+            dnl On Linux:
+            dnl - It's 8 on most 32-bit platforms, except 16 on x86_64-x32 and
+            dnl   (with newer versions of glibc) on i386 and powerpc.  8 is a
+            dnl   safe guess.
+            dnl - It's 16 on all 64-bit platforms.
+            dnl On Windows: It's 8 on 32-bit Windows, 16 on 64-bit Windows.
+            for nn in 4 8 16 32; do
+              AC_COMPILE_IFELSE(
+                [AC_LANG_PROGRAM([[
+                   #define MALLOC_ALIGN (2 * sizeof (void *))
+                   int test [MALLOC_ALIGN <= $nn ? 1 : -1];
+                   ]])
+                ],
+                [gl_cv_malloc_alignment="guessing $nn"
+                 break
+                ],
+                [:])
+            done
+            ;;
+          *)
+            dnl If we don't know, assume the worst.
+            dnl This minimum is e.g. reached on NetBSD/i386 and NetBSD/sparc.
+            for nn in 4 8 16; do
+              AC_COMPILE_IFELSE(
+                [AC_LANG_PROGRAM([[
+                   #define MALLOC_ALIGN (sizeof (void *))
+                   int test [MALLOC_ALIGN <= $nn ? 1 : -1];
+                   ]])
+                ],
+                [gl_cv_malloc_alignment="guessing $nn"
+                 break
+                ],
+                [:])
+            done
+            ;;
+        esac
+       ])
+    ])
+  case "$gl_cv_malloc_alignment" in
+    "unknown")
+      dnl Assume the worst.
+      value=4
+    ;;
+    "guessing "*)
+      value=`echo "$gl_cv_malloc_alignment" | sed -e 's/guessing //'`
+      ;;
+    *)
+      value="$gl_cv_malloc_alignment"
+      ;;
+  esac
+  AC_DEFINE_UNQUOTED([MALLOC_ALIGNMENT], [$value],
+    [Define to the guaranteed alignment of malloc() return values.])
+])
diff --git a/modules/aligned-malloc b/modules/aligned-malloc
new file mode 100644 (file)
index 0000000..29483d8
--- /dev/null
@@ -0,0 +1,25 @@
+Description:
+Allocate memory with indefinite extent and specified alignment.
+
+Files:
+lib/aligned-malloc.h
+m4/malloc-align.m4
+
+Depends-on:
+stdint
+
+configure.ac:
+gl_MALLOC_ALIGNMENT
+AC_REQUIRE([AC_C_INLINE])
+AC_CHECK_FUNCS([posix_memalign memalign])
+
+Makefile.am:
+
+Include:
+"aligned-malloc.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all