root/maint/gnulib/lib/aligned-malloc.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. aligned_free
  2. aligned_malloc
  3. aligned_malloc
  4. aligned_malloc
  5. aligned_malloc
  6. aligned_free
  7. aligned_malloc

   1 /* Allocate memory with indefinite extent and specified alignment.
   2 
   3    Copyright (C) 2020-2021 Free Software Foundation, Inc.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 2.1 of the
   8    License, or (at your option) any later version.
   9 
  10    This file is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 /* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
  19 
  20 /* Before including this file, you need to define the following macro:
  21 
  22    ALIGNMENT      A constant expression that evaluates to the desired alignment
  23                   (a power of 2).
  24 
  25    And you also need to #include <stdint.h> and <stdlib.h>.  */
  26 
  27 /* aligned_malloc allocates a block of memory of SIZE bytes, aligned on a
  28    boundary of ALIGNMENT bytes.
  29    The block can be freed through aligned_free(), NOT through free().
  30    Upon failure, it returns NULL.  */
  31 
  32 /* This module exists instead of a posix_memalign(), aligned_alloc(), or
  33    memalign() emulation, because we can't reasonably emulate posix_memalign(),
  34    aligned_alloc(), or memalign():
  35    If malloc() returned p, only free (p) is allowed, not free (p + 1),
  36    free (p + 2), free (p + 4), free (p + 8), or similar.
  37 
  38    We can use posix_memalign(), a POSIX function.
  39 
  40    We can also use aligned_alloc(), an ISO C11 and POSIX function.  But it's
  41    a bit more awkward to use.
  42 
  43    On older systems, we can alternatively use memalign() instead.  In the
  44    Solaris documentation of memalign() it is not specified how a memory block
  45    returned by memalign() can be freed, but it actually can be freed with
  46    free().  */
  47 
  48 #if !defined ALIGNMENT
  49 # error "ALIGNMENT is not defined"
  50 #endif
  51 #if !((ALIGNMENT) > 0 && ((ALIGNMENT) & ((ALIGNMENT) - 1)) == 0)
  52 # error "ALIGNMENT is not a power of 2"
  53 #endif
  54 #if ((ALIGNMENT) <= MALLOC_ALIGNMENT) || HAVE_POSIX_MEMALIGN || HAVE_ALIGNED_ALLOC || HAVE_MEMALIGN
  55 
  56 # if defined aligned_free || __GNUC__ >= 11
  57    /* The caller wants an inline function, not a macro,
  58       or we can use GCC's -Wmismatched-dealloc warning.  */
  59 static inline void
  60 aligned_free (void *q)
     /* [previous][next][first][last][top][bottom][index][help] */
  61 {
  62   free (q);
  63 }
  64 # else
  65 #  define aligned_free free
  66 # endif
  67 
  68 # if (ALIGNMENT) <= MALLOC_ALIGNMENT
  69 /* Simply use malloc.  */
  70 
  71 #  if defined aligned_malloc || __GNUC__ >= 11
  72    /* The caller wants an inline function, not a macro,
  73       or GCC's -Wmismatched-dealloc warning might be in effect.  */
  74 static inline
  75 /*_GL_ATTRIBUTE_DEALLOC (aligned_free, 1)*/
  76 void *
  77 aligned_malloc (size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79   return malloc (size);
  80 }
  81 #  else
  82 #   define aligned_malloc malloc
  83 #  endif
  84 
  85 # elif HAVE_POSIX_MEMALIGN
  86 /* Use posix_memalign.
  87    This is OK since ALIGNMENT > MALLOC_ALIGNMENT >= sizeof (void *).  */
  88 
  89 static inline
  90 /*_GL_ATTRIBUTE_DEALLOC (aligned_free, 1)*/
  91 void *
  92 aligned_malloc (size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94   void *p;
  95   int ret = posix_memalign (&p, (ALIGNMENT), size);
  96   if (ret == 0)
  97     return p;
  98   else
  99     return NULL;
 100 }
 101 
 102 # elif HAVE_ALIGNED_ALLOC
 103 /* Use aligned_alloc.  */
 104 
 105 static inline
 106 /*_GL_ATTRIBUTE_DEALLOC (aligned_free, 1)*/
 107 void *
 108 aligned_malloc (size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110   /* Round up SIZE to the next multiple of ALIGNMENT,
 111      namely (SIZE + ALIGNMENT - 1) & ~(ALIGNMENT - 1).  */
 112   size += (ALIGNMENT) - 1;
 113   if (size >= (ALIGNMENT) - 1) /* no overflow? */
 114     {
 115       size &= ~(size_t)((ALIGNMENT) - 1);
 116       return aligned_alloc ((ALIGNMENT), size);
 117     }
 118   return NULL;
 119 }
 120 
 121 # elif HAVE_MEMALIGN                    /* HP-UX, IRIX, Solaris <= 10 */
 122 /* Use memalign.  */
 123 
 124 static inline
 125 /*_GL_ATTRIBUTE_DEALLOC (aligned_free, 1)*/
 126 void *
 127 aligned_malloc (size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129   return memalign ((ALIGNMENT), size);
 130 }
 131 
 132 # endif
 133 
 134 #else
 135 /* Use malloc and waste a bit of memory.  */
 136 
 137 static inline void
 138 aligned_free (void *q)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140   if (q != NULL)
 141     {
 142       if ((uintptr_t) q & ((ALIGNMENT) - 1))
 143         /* Argument not aligned as expected.  */
 144         abort ();
 145       else
 146         {
 147           void *p = ((void **) q)[-1];
 148           if (!((uintptr_t) p <= (uintptr_t) q
 149                 && (uintptr_t) q - (uintptr_t) p >= MALLOC_ALIGNMENT
 150                 && (uintptr_t) q - (uintptr_t) p <= (ALIGNMENT)))
 151             abort ();
 152           free (p);
 153         }
 154     }
 155 }
 156 
 157 static inline
 158 /*_GL_ATTRIBUTE_DEALLOC (aligned_free, 1)*/
 159 void *
 160 aligned_malloc (size_t size)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162   size += (ALIGNMENT);
 163   if (size >= (ALIGNMENT)) /* no overflow? */
 164     {
 165       void *p = malloc (size);
 166       if (p != NULL)
 167         {
 168           /* Go to the next multiple of ALIGNMENT.  */
 169           void *q =
 170             (void *) (((uintptr_t) p + (ALIGNMENT)) & -(intptr_t)(ALIGNMENT));
 171           /* Now q - p <= ALIGNMENT and
 172              q - p >= MALLOC_ALIGNMENT >= sizeof (void *).
 173              This is enough to store a back pointer to p.  */
 174           ((void **) q)[-1] = p;
 175           return q;
 176         }
 177     }
 178   return NULL;
 179 }
 180 
 181 #endif

/* [previous][next][first][last][top][bottom][index][help] */