1 /* Jitter: allocated heap memory blocks.
2
3 Copyright (C) 2020 Luca Saiu
4 Written by Luca Saiu
5
6 This file is part of Jitter.
7
8 Jitter is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Jitter is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
20
21
22 #include <jitter/jitter-aligned-block.h>
23 #include <jitter/jitter-bitwise.h>
24 #include <jitter/jitter-fatal.h>
25
26 /* Include the right header, according to the selected implementation. */
27 #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP)
28 # include <unistd.h> /* For sysconf . */
29 # include <sys/mman.h> /* For mmap and munmap . */
30 #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC)
31 # include <stdlib.h>
32 #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN)
33 # include <stdlib.h>
34 #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK)
35 # include <jitter/jitter-malloc.h>
36 #else
37 # error "no aligned block implementation defined. This should never happen."
38 #endif
39
40
41
42
43 /* Aligned block allocation and destruction.
44 * ************************************************************************** */
45
46 void *
jitter_aligned_block_make(jitter_aligned_block_id * id,size_t alignment_in_bytes,size_t size_in_bytes)47 jitter_aligned_block_make (jitter_aligned_block_id *id,
48 size_t alignment_in_bytes, size_t size_in_bytes)
49 {
50 void *res;
51
52 /* The mmap and malloc implementations share the strategy of allocating a
53 larger block guaranteed to contain an aligned block inside. */
54 #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP) \
55 || defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK)
56 /* Allocate a larger buffer which is guaranteed to contain an aligned buffer
57 of the required size as a sub-buffer. Keep a pointer to the initial
58 buffer, in order to be able to free it later, in the block id. */
59 size_t allocated_size_in_bytes;
60 if (size_in_bytes < alignment_in_bytes)
61 allocated_size_in_bytes = alignment_in_bytes * 2;
62 else
63 allocated_size_in_bytes = size_in_bytes * 2;
64 void *initial_pointer;
65 #endif
66
67 #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP)
68 /* Allocate a larger block. */
69 initial_pointer = mmap (NULL,
70 allocated_size_in_bytes,
71 PROT_READ | PROT_WRITE,
72 MAP_PRIVATE | MAP_ANONYMOUS,
73 -1,
74 0);
75 if (initial_pointer == NULL)
76 jitter_fatal ("mmap failed");
77 /* Find the aligned part of the mapping, which is the only part we are
78 interested in. */
79 res = ((void *)
80 JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO ((jitter_uint) initial_pointer,
81 alignment_in_bytes));
82 id->initial_map = res;
83 id->mapping_length_in_bytes = size_in_bytes;
84 /* Unmap the misaligned part (which means: aligned to a double memory page,
85 but not to the required alignment) at the beginning and the end. This also
86 checks that the block alignment is a multiple of double the page size, as
87 munmap fails otherwise. */
88 void *misaligned_before = initial_pointer;
89 size_t misaligned_before_length
90 = (char *) res - (char *) initial_pointer;
91 void *misaligned_after = (char *) res + size_in_bytes;
92 size_t misaligned_after_length
93 = (((char *) initial_pointer + allocated_size_in_bytes)
94 - (char *) misaligned_after);
95 if (misaligned_before_length > 0)
96 if (munmap (misaligned_before, misaligned_before_length) != 0)
97 jitter_fatal ("munmap failed (%li B not an even multiple of the page "
98 "size?)", (long) alignment_in_bytes);
99 if (misaligned_after_length > 0)
100 if (munmap (misaligned_after, misaligned_after_length) != 0)
101 jitter_fatal ("munmap failed (%li B not an even multiple of the page "
102 "size?)", (long) alignment_in_bytes);
103 #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC)
104 /* According to the specification aligned_alloc requires that the size be a
105 multiple of the alignment -- thanks to Bruno Haible for letting me notice.
106 This solution is therefore, in theory (in practice alignment_in_bytes will
107 usually be the same as size_in_bytes), wasteful. */
108 size_in_bytes = JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO (size_in_bytes,
109 alignment_in_bytes);
110 res = aligned_alloc (alignment_in_bytes, size_in_bytes);
111 if (res == NULL)
112 jitter_fatal ("aligned_alloc failed");
113 id->aligned_alloced_buffer = res;
114 #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN)
115 if (posix_memalign (& res, alignment_in_bytes, size_in_bytes) != 0)
116 jitter_fatal ("posix_memalign failed");
117 id->posix_memaligned_buffer = res;
118 #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK)
119 initial_pointer = jitter_xmalloc (allocated_size_in_bytes);
120 res = ((void *)
121 JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO ((jitter_uint) initial_pointer,
122 alignment_in_bytes));
123 id->initial_pointer = initial_pointer;
124 #else
125 # error "no aligned block implementation defined. This should never happen."
126 #endif
127 return res;
128 }
129
130 void
jitter_aligned_block_destroy(jitter_aligned_block_id id)131 jitter_aligned_block_destroy (jitter_aligned_block_id id)
132 {
133 #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP)
134 munmap (id.initial_map, id.mapping_length_in_bytes);
135 #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC)
136 free (id.aligned_alloced_buffer);
137 #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN)
138 free (id.posix_memaligned_buffer);
139 #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK)
140 free (id.initial_pointer);
141 #else
142 # error "no aligned block implementation defined. This should never happen."
143 #endif
144 }
145