1 /*****************************************************************************/
5 /* Allocate an aligned memory block */
9 /* (C) 2004-2005 Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided "as-is," without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated, but is not required. */
27 /* 2. Alterred source versions must be marked plainly as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or alterred from any source */
32 /*****************************************************************************/
36 #include <stddef.h> /* define NULL */
37 #include <stdlib.h> /* declare function's prototype */
41 #define EOK 0 /* No errors (non-standard name) */
45 /* This is a very simple version of an aligned memory allocator. We will
46 ** allocate a greater block, so that we can place the aligned block (that is
47 ** returned) within it. We use our knowledge about the internal heap
48 ** structures to free the unused parts of the bigger block (the two chunks
49 ** below and above the aligned block).
54 int __fastcall__ posix_memalign (void** memptr, size_t alignment, size_t size)
55 /* Allocate a block of memory with the given "size", which is aligned to a
56 ** memory address that is a multiple of "alignment". "alignment" MUST NOT be
57 ** zero, and MUST be a power of two; otherwise, this function will return
58 ** EINVAL. The function returns ENOMEM if not enough memory is available
59 ** to satisfy the request. "memptr" must point to a variable; that variable
60 ** will return the address of the allocated memory. Use free() to release that
67 register struct usedblock* b; /* points to raw Block */
68 register struct usedblock* u; /* points to User block */
69 register struct usedblock* p; /* Points to upper block */
71 /* Handle requests for zero-sized blocks */
77 /* Test alignment: is it a power of two? There must be only one bit set. */
78 if (alignment == 0 || (alignment & --alignment) != 0) {
83 /* Augment the block size up to the alignment, and allocate memory.
84 ** We don't need to account for the additional admin. data that's needed to
85 ** manage the used block, because the block returned by malloc() has that
86 ** overhead added one time; and, the worst thing that might happen is that
87 ** we cannot free the upper and lower blocks.
89 b = malloc (size + alignment);
91 /* Handle out-of-memory */
97 /* Create (and return) a new pointer that points to the user-visible
100 u = *memptr = (struct usedblock*) (((unsigned)b + alignment) & ~alignment);
102 /* Get a pointer to the (raw) upper block */
103 p = (struct usedblock*) ((char*)u + size);
105 /* Get the raw-block pointer, which is located just below the visible
106 ** unaligned block. The first word of this raw block is the total size
107 ** of the block, including the admin. space.
112 /* Check if we can free the space above the user block. That is the case
113 ** if the size of the block is at least sizeof (struct freeblock) bytes,
114 ** and the size of the remaining block is at least that size, too.
115 ** If the upper block is smaller, then we just will pass it to the caller,
116 ** together with the requested aligned block.
118 uppersize = rawsize - (lowersize = (char*)p - (char*)b);
119 if (uppersize >= sizeof (struct freeblock) &&
120 lowersize >= sizeof (struct freeblock)) {
122 /* Setup the usedblock structure */
126 /* Generate a pointer to the (upper) user space, and free that block */
129 /* Decrease the raw-block size by the amount of space just freed */
133 /* Check if we can free the space below the user block. That is the case
134 ** if the size of the block is at least sizeof (struct freeblock) bytes,
135 ** and the size of the remaining block is at least that size, too. If the
136 ** lower block is smaller, we just will pass it to the caller, together
137 ** with the requested aligned block.
138 ** Beware: We need an additional struct usedblock, in the lower block,
139 ** which is part of the block that is passed back to the caller.
141 lowersize = ((char*)u - (char*)b) - sizeof (struct usedblock);
142 if ( lowersize >= sizeof (struct freeblock) &&
143 (rawsize - lowersize) >= sizeof (struct freeblock)) {
145 /* b already points to the raw lower-block.
146 ** Set up the usedblock structure.
151 /* Generate a pointer to the (lower) user space, and free that block */
154 /* Decrease the raw-block size by the amount of space just freed */
155 rawsize -= lowersize;
157 /* Set b to the raw user-block (that will be returned) */
161 /* u points to the user-visible block, while b points to the raw block,
162 ** and rawsize contains the length of the raw block. Set up the usedblock
163 ** structure, but beware: If we didn't free the lower block, then it is
164 ** split; which means that we must use b to write the size,
165 ** and u to write the start field.