1 | /* |
2 | * Copyright (c) 2015, Intel Corporation |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions are met: |
6 | * |
7 | * * Redistributions of source code must retain the above copyright notice, |
8 | * this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of Intel Corporation nor the names of its contributors |
13 | * may be used to endorse or promote products derived from this software |
14 | * without specific prior written permission. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | /** \file |
30 | * \brief Aligned memory alloc/free. |
31 | */ |
32 | #include "ue2common.h" |
33 | #include "alloc.h" |
34 | |
35 | #include <cstdlib> |
36 | #include <cstring> |
37 | |
38 | namespace ue2 { |
39 | |
40 | // This is one of the simplest ways to catch failure where we aren't using an |
41 | // aligned_(zmalloc|_free) pair - it will force death if the wrong free is used. |
42 | // We use this whenever assertions are switched on. |
43 | #if !defined(NDEBUG) |
44 | #define HACK_OFFSET 64 |
45 | #else |
46 | #define HACK_OFFSET 0 |
47 | #endif |
48 | |
49 | /* get us a posix_memalign from somewhere */ |
50 | #if !defined(HAVE_POSIX_MEMALIGN) |
51 | # if defined(HAVE_MEMALIGN) |
52 | #define posix_memalign(A, B, C) ((*A = (void *)memalign(B, C)) == nullptr) |
53 | # elif defined(HAVE__ALIGNED_MALLOC) |
54 | /* on Windows */ |
55 | #include <malloc.h> |
56 | #define posix_memalign(A, B, C) ((*A = (void *)_aligned_malloc(C, B)) == nullptr) |
57 | # else |
58 | #error no posix_memalign or memalign aligned malloc |
59 | # endif |
60 | #endif |
61 | |
62 | void *aligned_malloc_internal(size_t size, size_t align) { |
63 | void *mem; |
64 | #if !defined(_WIN32) |
65 | int rv = posix_memalign(&mem, align, size); |
66 | if (rv != 0) { |
67 | DEBUG_PRINTF("posix_memalign returned %d when asked for %zu bytes\n" , |
68 | rv, size); |
69 | return nullptr; |
70 | } |
71 | #else |
72 | if (nullptr == (mem = _aligned_malloc(size, align))) { |
73 | DEBUG_PRINTF("_aligned_malloc failed when asked for %zu bytes\n" , |
74 | size); |
75 | return nullptr; |
76 | } |
77 | #endif |
78 | |
79 | assert(mem); |
80 | return mem; |
81 | } |
82 | |
83 | void aligned_free_internal(void *ptr) { |
84 | if (!ptr) { |
85 | return; |
86 | } |
87 | |
88 | #if defined(_WIN32) |
89 | _aligned_free(ptr); |
90 | #else |
91 | free(ptr); |
92 | #endif |
93 | } |
94 | |
95 | /** \brief 64-byte aligned, zeroed malloc. |
96 | * |
97 | * Pointers should be freed with \ref aligned_free. If we are unable to |
98 | * allocate the requested number of bytes, this function will throw |
99 | * std::bad_alloc. */ |
100 | void *aligned_zmalloc(size_t size) { |
101 | // Really huge allocations are probably an indication that we've |
102 | // done something wrong. |
103 | assert(size < 1024 * 1024 * 1024); // 1GB |
104 | |
105 | const size_t alloc_size = size + HACK_OFFSET; |
106 | |
107 | void *mem = aligned_malloc_internal(alloc_size, 64); |
108 | if (!mem) { |
109 | DEBUG_PRINTF("unable to allocate %zu bytes\n" , alloc_size); |
110 | throw std::bad_alloc(); |
111 | } |
112 | |
113 | DEBUG_PRINTF("alloced %p reporting %p\n" , mem, (char *)mem + HACK_OFFSET); |
114 | assert(ISALIGNED_N(mem, 64)); |
115 | |
116 | memset(mem, 0, alloc_size); |
117 | return (void *)((char *)mem + HACK_OFFSET); |
118 | } |
119 | |
120 | /** \brief Free a pointer allocated with \ref aligned_zmalloc. */ |
121 | void aligned_free(void *ptr) { |
122 | if (!ptr) { |
123 | return; |
124 | } |
125 | |
126 | void *addr = (void *)((char *)ptr - HACK_OFFSET); |
127 | DEBUG_PRINTF("asked to free %p freeing %p\n" , ptr, addr); |
128 | |
129 | assert(ISALIGNED_N(addr, 64)); |
130 | aligned_free_internal(addr); |
131 | } |
132 | |
133 | } // namespace ue2 |
134 | |