paligned_alloc.h (5920B)
1 #ifndef PALIGNED_ALLOC_H 2 3 #ifdef __cplusplus 4 extern "C" { 5 #endif 6 7 /* 8 * NOTE: MSVC in general has no aligned alloc function that is 9 * compatible with free and it is not trivial to implement a version 10 * which is. Therefore, to remain portable, end user code needs to 11 * use `aligned_free` which is not part of C11 but defined in this header. 12 * 13 * glibc only provides aligned_alloc when _ISOC11_SOURCE is defined, but 14 * MingW does not support aligned_alloc despite of this, it uses the 15 * the _aligned_malloc as MSVC. 16 * 17 * The same issue is present on some Unix systems not providing 18 * posix_memalign. 19 * 20 * Note that clang and gcc with -std=c11 or -std=c99 will not define 21 * _POSIX_C_SOURCE and thus posix_memalign cannot be detected but 22 * aligned_alloc is not necessarily available either. We assume 23 * that clang always has posix_memalign although it is not strictly 24 * correct. For gcc, use -std=gnu99 or -std=gnu11 or don't use -std in 25 * order to enable posix_memalign, or live with the fallback until using 26 * a system where glibc has a version that supports aligned_alloc. 27 * 28 * For C11 compliant compilers and compilers with posix_memalign, 29 * it is valid to use free instead of aligned_free with the above 30 * caveats. 31 */ 32 33 #include <stdlib.h> 34 35 /* 36 * Define this to see which version is used so the fallback is not 37 * enganged unnecessarily: 38 * 39 * #define PORTABLE_DEBUG_ALIGNED_ALLOC 40 */ 41 42 #if 0 43 #define PORTABLE_DEBUG_ALIGNED_ALLOC 44 #endif 45 46 #if !defined(PORTABLE_C11_ALIGNED_ALLOC) 47 48 /* 49 * PORTABLE_C11_ALIGNED_ALLOC = 1 50 * indicates that the system has builtin aligned_alloc 51 * If it doesn't, the section after detection provides an implemention. 52 */ 53 #if defined (__MINGW32__) 54 /* MingW does not provide aligned_alloc despite defining _ISOC11_SOURCE */ 55 #define PORTABLE_C11_ALIGNED_ALLOC 0 56 #elif defined (_ISOC11_SOURCE) 57 /* glibc aligned_alloc detection, but MingW is not truthful */ 58 #define PORTABLE_C11_ALIGNED_ALLOC 1 59 #elif defined (__GLIBC__) 60 /* aligned_alloc is not available in glibc just because __STDC_VERSION__ >= 201112L. */ 61 #define PORTABLE_C11_ALIGNED_ALLOC 0 62 #elif defined (__clang__) 63 #define PORTABLE_C11_ALIGNED_ALLOC 0 64 #elif defined (__APPLE__) 65 #define PORTABLE_C11_ALIGNED_ALLOC 0 66 #elif defined(__IBMC__) 67 #define PORTABLE_C11_ALIGNED_ALLOC 0 68 #elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) 69 #define PORTABLE_C11_ALIGNED_ALLOC 1 70 #else 71 #define PORTABLE_C11_ALIGNED_ALLOC 0 72 #endif 73 74 #endif /* PORTABLE_C11_ALIGNED_ALLOC */ 75 76 /* https://linux.die.net/man/3/posix_memalign */ 77 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_GNU_SOURCE) 78 #define PORTABLE_POSIX_MEMALIGN 1 79 #endif 80 81 /* https://forum.kde.org/viewtopic.php?p=66274 */ 82 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_XOPEN_SOURCE) 83 #if _XOPEN_SOURCE >= 600 84 #define PORTABLE_POSIX_MEMALIGN 1 85 #endif 86 #endif 87 88 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(_POSIX_C_SOURCE) 89 #if _POSIX_C_SOURCE >= 200112L 90 #define PORTABLE_POSIX_MEMALIGN 1 91 #endif 92 #endif 93 94 #if !defined(PORTABLE_POSIX_MEMALIGN) && defined(__clang__) 95 #define PORTABLE_POSIX_MEMALIGN 1 96 #endif 97 98 #if !defined(PORTABLE_POSIX_MEMALIGN) 99 #define PORTABLE_POSIX_MEMALIGN 0 100 #endif 101 102 /* https://forum.kde.org/viewtopic.php?p=66274 */ 103 #if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) 104 /* C11 or newer */ 105 #include <stdalign.h> 106 #endif 107 108 /* C11 or newer */ 109 #if !defined(aligned_alloc) && !defined(__aligned_alloc_is_defined) 110 111 #if PORTABLE_C11_ALIGNED_ALLOC 112 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC 113 #error "DEBUG: C11_ALIGNED_ALLOC configured" 114 #endif 115 #elif defined(_MSC_VER) || defined(__MINGW32__) 116 117 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC 118 #error "DEBUG: Windows _aligned_malloc configured" 119 #endif 120 121 /* Aligned _aligned_malloc is not compatible with free. */ 122 #define aligned_alloc(alignment, size) _aligned_malloc(size, alignment) 123 #define aligned_free(p) _aligned_free(p) 124 #define __aligned_alloc_is_defined 1 125 #define __aligned_free_is_defined 1 126 127 #elif PORTABLE_POSIX_MEMALIGN 128 129 #if defined(__GNUC__) 130 #if !defined(__GNUCC__) 131 extern int posix_memalign (void **, size_t, size_t); 132 #elif __GNUCC__ < 5 133 extern int posix_memalign (void **, size_t, size_t); 134 #endif 135 #endif 136 137 static inline void *__portable_aligned_alloc(size_t alignment, size_t size) 138 { 139 int err; 140 void *p = 0; 141 142 if (alignment < sizeof(void *)) { 143 alignment = sizeof(void *); 144 } 145 err = posix_memalign(&p, alignment, size); 146 if (err && p) { 147 free(p); 148 p = 0; 149 } 150 return p; 151 } 152 153 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC 154 #error "DEBUG: POSIX_MEMALIGN configured" 155 #endif 156 157 #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size) 158 #define aligned_free(p) free(p) 159 #define __aligned_alloc_is_defined 1 160 #define __aligned_free_is_defined 1 161 162 #else 163 164 static inline void *__portable_aligned_alloc(size_t alignment, size_t size) 165 { 166 char *raw; 167 void *buf; 168 size_t total_size = (size + alignment - 1 + sizeof(void *)); 169 170 if (alignment < sizeof(void *)) { 171 alignment = sizeof(void *); 172 } 173 raw = (char *)(size_t)malloc(total_size); 174 buf = raw + alignment - 1 + sizeof(void *); 175 buf = (void *)(((size_t)buf) & ~(alignment - 1)); 176 ((void **)buf)[-1] = raw; 177 return buf; 178 } 179 180 static inline void __portable_aligned_free(void *p) 181 { 182 char *raw; 183 184 if (p) { 185 raw = (char*)((void **)p)[-1]; 186 free(raw); 187 } 188 } 189 190 #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size) 191 #define aligned_free(p) __portable_aligned_free(p) 192 #define __aligned_alloc_is_defined 1 193 #define __aligned_free_is_defined 1 194 195 #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC 196 #error "DEBUG: aligned_alloc malloc fallback configured" 197 #endif 198 199 #endif 200 201 #endif /* aligned_alloc */ 202 203 #if !defined(aligned_free) && !defined(__aligned_free_is_defined) 204 #define aligned_free(p) free(p) 205 #define __aligned_free_is_defined 1 206 #endif 207 208 #ifdef __cplusplus 209 } 210 #endif 211 212 #endif /* PALIGNED_ALLOC_H */