Branch data Line data Source code
1 : : #ifndef PALIGNED_ALLOC_H
2 : :
3 : : #ifndef __cplusplus
4 : :
5 : : /*
6 : : * NOTE: MSVC in general has no aligned alloc function that is
7 : : * compatible with free and it is not trivial to implement a version
8 : : * there is. Therefore, to remain portable, end user code needs to
9 : : * use `aligned_free` which is not part of C11 but defined in this header.
10 : : *
11 : : * The same issue may be present on some Unix systems not providing
12 : : * posix_memalign, but we do not currently support this.
13 : : *
14 : : * For C11 compliant compilers and compilers with posix_memalign,
15 : : * it is valid to use free instead of aligned_free with the above
16 : : * caveats.
17 : : */
18 : :
19 : : #include <stdlib.h>
20 : :
21 : :
22 : : /*
23 : : * Define this to see which version is used so the fallback is not
24 : : * enganged unnecessarily:
25 : : *
26 : : * #define PORTABLE_DEBUG_ALIGNED_ALLOC
27 : : */
28 : :
29 : : #if !defined(PORTABLE_C11_ALIGNED_ALLOC)
30 : :
31 : : #if defined (__GLIBC__)
32 : : #define PORTABLE_C11_ALIGNED_ALLOC 0
33 : : #elif defined (__clang__)
34 : : #define PORTABLE_C11_ALIGNED_ALLOC 0
35 : : #elif defined(__IBMC__)
36 : : #define PORTABLE_C11_ALIGNED_ALLOC 0
37 : : #elif (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
38 : : #define PORTABLE_C11_ALIGNED_ALLOC 1
39 : : #else
40 : : #define PORTABLE_C11_ALIGNED_ALLOC 0
41 : : #endif
42 : :
43 : : #endif /* PORTABLE_C11_ALIGNED_ALLOC */
44 : :
45 : : /* https://linux.die.net/man/3/posix_memalign */
46 : : #if !defined(PORTABLE_POSIX_MEMALIGN)
47 : : /* https://forum.kde.org/viewtopic.php?p=66274 */
48 : : #if (defined _GNU_SOURCE) || ((_XOPEN_SOURCE + 0) >= 600) || (_POSIX_C_SOURCE + 0) >= 200112L
49 : : #define PORTABLE_POSIX_MEMALIGN 1
50 : : #elif (__clang__)
51 : : #define PORTABLE_POSIX_MEMALIGN 1
52 : : #else
53 : : #define PORTABLE_POSIX_MEMALIGN 0
54 : : #endif
55 : : #endif /* PORTABLE_POSIX_MEMALIGN */
56 : :
57 : : /* https://forum.kde.org/viewtopic.php?p=66274 */
58 : : #if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L)
59 : : /* C11 or newer */
60 : : #include <stdalign.h>
61 : : #endif
62 : :
63 : : /* C11 or newer */
64 : : #if !defined(aligned_alloc) && !defined(__aligned_alloc_is_defined)
65 : :
66 : : #if PORTABLE_C11_ALIGNED_ALLOC
67 : : #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
68 : : #error "DEBUG: C11_ALIGNED_ALLOC configured"
69 : : #endif
70 : : #elif defined(_MSC_VER)
71 : :
72 : : /* Aligned _aligned_malloc is not compatible with free. */
73 : : #define aligned_alloc(alignment, size) _aligned_malloc(size, alignment)
74 : : #define aligned_free(p) _aligned_free(p)
75 : : #define __aligned_alloc_is_defined 1
76 : : #define __aligned_free_is_defined 1
77 : :
78 : : #elif PORTABLE_POSIX_MEMALIGN
79 : :
80 : : #ifdef __GNUC__
81 : : #include "mm_malloc.h"
82 : : #endif
83 : :
84 : : static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
85 : : {
86 : : int err;
87 : : void *p = 0;
88 : :
89 : : if (alignment < sizeof(void *)) {
90 : : alignment = sizeof(void *);
91 : : }
92 : : err = posix_memalign(&p, alignment, size);
93 : : if (err && p) {
94 : : free(p);
95 : : p = 0;
96 : : }
97 : : return p;
98 : : }
99 : :
100 : : #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
101 : : #error "DEBUG: POSIX_MEMALIGN configured"
102 : : #endif
103 : :
104 : : #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
105 : : #define aligned_free(p) free(p)
106 : : #define __aligned_alloc_is_defined 1
107 : : #define __aligned_free_is_defined 1
108 : :
109 : : #else
110 : :
111 : 8 : static inline void *__portable_aligned_alloc(size_t alignment, size_t size)
112 : : {
113 : : char *raw;
114 : : void *buf;
115 : 8 : size_t total_size = (size + alignment - 1 + sizeof(void *));
116 : :
117 [ + + ]: 8 : if (alignment < sizeof(void *)) {
118 : : alignment = sizeof(void *);
119 : : }
120 : 8 : raw = (char *)(size_t)malloc(total_size);
121 : 8 : buf = raw + alignment - 1 + sizeof(void *);
122 : 8 : buf = (void *)(((size_t)buf) & ~(alignment - 1));
123 : 8 : ((void **)buf)[-1] = raw;
124 : 8 : return buf;
125 : : }
126 : :
127 : : static inline void __portable_aligned_free(void *p)
128 : : {
129 : 0 : char *raw = ((void **)p)[-1];
130 : :
131 : 0 : free(raw);
132 : : }
133 : :
134 : : #define aligned_alloc(alignment, size) __portable_aligned_alloc(alignment, size)
135 : : #define aligned_free(p) __portable_aligned_free(p)
136 : : #define __aligned_alloc_is_defined 1
137 : : #define __aligned_free_is_defined 1
138 : :
139 : : #ifdef PORTABLE_DEBUG_ALIGNED_ALLOC
140 : : #error "DEBUG: aligned_alloc malloc fallback configured"
141 : : #endif
142 : :
143 : : #endif
144 : :
145 : : #endif /* aligned_alloc */
146 : :
147 : : #if !defined(aligned_free) && !defined(__aligned_free_is_defined)
148 : : #define aligned_free(p) free(p)
149 : : #define __aligned_free_is_defined 1
150 : : #endif
151 : :
152 : : #endif /* __cplusplus */
153 : : #endif /* PALIGNED_ALLOC_H */
|