1 /*
2 * Copyright (c) 2012, 2013 ARM Ltd
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the company may not be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "nano-malloc.h"
30
31 /*
32 * Allocate memory block aligned at specific boundary.
33 * align: required alignment. Must be power of 2. Return NULL
34 * if not power of 2. Undefined behavior is bigger than
35 * pointer value range.
36 * s: required size.
37 * Return: allocated memory pointer aligned to align
38 * Algorithm: Malloc a big enough block, padding pointer to aligned
39 * address, then truncate and free the tail if too big.
40 * Record the offset of align pointer and original pointer
41 * in the padding area.
42 */
43
44 void *
memalign(size_t align,size_t s)45 memalign(size_t align, size_t s)
46 {
47 chunk_t *chunk_p;
48 size_t offset, size_with_padding;
49 char * allocated, * aligned_p;
50
51 /* Return NULL if align isn't power of 2 */
52 if ((align & (align-1)) != 0)
53 {
54 errno = EINVAL;
55 return NULL;
56 }
57
58 align = MAX(align, MALLOC_MINSIZE);
59
60 if (s > MALLOC_MAXSIZE - align)
61 {
62 errno = ENOMEM;
63 return NULL;
64 }
65
66 s = __align_up(MAX(s,1), MALLOC_CHUNK_ALIGN);
67
68 /* Make sure there's space to align the allocation and split
69 * off chunk_t from the front
70 */
71 size_with_padding = s + align + MALLOC_MINSIZE;
72
73 allocated = __malloc_malloc(size_with_padding);
74 if (allocated == NULL) return NULL;
75
76 chunk_p = ptr_to_chunk(allocated);
77
78 aligned_p = __align_up(allocated, align);
79
80 offset = (size_t) (aligned_p - allocated);
81
82 /* Split off the front piece if necessary */
83 if (offset)
84 {
85 if (offset < MALLOC_MINSIZE) {
86 aligned_p += align;
87 offset += align;
88 }
89
90 chunk_t *new_chunk_p = ptr_to_chunk(aligned_p);
91 _set_size(new_chunk_p, _size(chunk_p) - offset);
92
93 make_free_chunk(chunk_p, offset);
94
95 chunk_p = new_chunk_p;
96 }
97
98 offset = _size(chunk_p) - chunk_size(s);
99
100 /* Split off the back piece if large enough */
101 if (offset >= MALLOC_MINSIZE)
102 {
103 *_size_ref(chunk_p) -= offset;
104
105 make_free_chunk(chunk_after(chunk_p), offset);
106 }
107 return aligned_p;
108 }
109
110 #ifdef _HAVE_ALIAS_ATTRIBUTE
111 __strong_reference(memalign, aligned_alloc);
112 #endif
113