1 /*
2 Copyright (C) 2001-2014, Parrot Foundation.
3 
4 =head1 NAME
5 
6 src/gc/alloc_memory.c - Memory allocation
7 
8 =head1 DESCRIPTION
9 
10 The memory (mem) API handles memory allocation,
11 
12 Basically just a wrapper C<around malloc/calloc/realloc/free()> with an
13 setup function to initialize the memory pools.
14 
15 =head2 Functions
16 
17 =over 4
18 
19 =cut
20 
21 */
22 
23 #include "parrot/parrot.h"
24 #include "parrot/memory.h"
25 
26 
27 #define PANIC_OUT_OF_MEM(size) panic_failed_allocation(__LINE__, (size))
28 #define PANIC_ZERO_ALLOCATION(func) panic_zero_byte_allocation(__LINE__, (func))
29 
30 #ifndef DETAIL_MEMORY_DEBUG
31 #  define MEMORY_DEBUG_DETAIL_2(s, a1, a2)
32 #else
33 #  define MEMORY_DEBUG_DETAIL_2(s, a1, a2) \
34         fprintf(stderr, (s), (a1), (a2))
35 #endif
36 
37 /* HEADERIZER HFILE: include/parrot/memory.h */
38 /* HEADERIZER BEGIN: static */
39 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
40 
41 PARROT_DOES_NOT_RETURN
42 static void panic_failed_allocation(unsigned int line, unsigned long size);
43 
44 PARROT_DOES_NOT_RETURN
45 static void panic_zero_byte_allocation(
46     unsigned int line,
47     ARGIN(const char *func))
48         __attribute__nonnull__(2);
49 
50 #define ASSERT_ARGS_panic_failed_allocation __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
51 #define ASSERT_ARGS_panic_zero_byte_allocation __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
52        PARROT_ASSERT_ARG(func))
53 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
54 /* HEADERIZER END: static */
55 
56 
57 /*
58 
59 =item C<void * mem_sys_allocate(size_t size)>
60 
61 Uses C<malloc> to allocate system memory. Panics if the system cannot
62 return memory, or if a zero-byte allocation is attempted.
63 
64 =cut
65 
66 */
67 
68 PARROT_EXPORT
69 PARROT_MALLOC
70 PARROT_CANNOT_RETURN_NULL
71 void *
mem_sys_allocate(size_t size)72 mem_sys_allocate(size_t size)
73 {
74     ASSERT_ARGS(mem_sys_allocate)
75     void * const ptr = malloc(size);
76     if (size==0)
77         PANIC_ZERO_ALLOCATION("mem_sys_allocate");
78     MEMORY_DEBUG_DETAIL_2("Allocated %i at %p\n", size, ptr);
79     if (!ptr)
80         PANIC_OUT_OF_MEM(size);
81     return ptr;
82 }
83 
84 /*
85 
86 =item C<void * mem_sys_allocate_zeroed(size_t size)>
87 
88 Uses C<calloc> to allocate system memory.  Guaranteed to succeed, Panics
89 otherwise.
90 
91 =cut
92 
93 */
94 
95 PARROT_EXPORT
96 PARROT_MALLOC
97 PARROT_CANNOT_RETURN_NULL
98 void *
mem_sys_allocate_zeroed(size_t size)99 mem_sys_allocate_zeroed(size_t size)
100 {
101     ASSERT_ARGS(mem_sys_allocate_zeroed)
102     void * const ptr = calloc(1, size);
103 
104     if (size==0)
105         PANIC_ZERO_ALLOCATION("mem_sys_allocate_zeroed");
106     MEMORY_DEBUG_DETAIL_2("Allocated %i at %p\n", size, ptr);
107     if (!ptr)
108         PANIC_OUT_OF_MEM(size);
109     return ptr;
110 }
111 
112 /*
113 
114 =item C<void * mem_sys_realloc(void *from, size_t size)>
115 
116 Resizes a chunk of memory.  Unlike C<realloc>, it can handle a
117 NULL pointer, in which case it calls C<calloc> to create the memory
118 block.
119 
120 =cut
121 
122 */
123 
124 PARROT_EXPORT
125 PARROT_MALLOC
126 PARROT_CANNOT_RETURN_NULL
127 void *
mem_sys_realloc(ARGFREE (void * from),size_t size)128 mem_sys_realloc(ARGFREE(void *from), size_t size)
129 {
130     ASSERT_ARGS(mem_sys_realloc)
131     void *ptr;
132     if (size==0)
133         PANIC_ZERO_ALLOCATION("mem_sys_realloc");
134     MEMORY_DEBUG_DETAIL_2("Freed %p (realloc -- %i bytes)\n", from, size);
135     if (from)
136         ptr = realloc(from, size);
137     else
138         ptr = calloc(1, size);
139     MEMORY_DEBUG_DETAIL_2("Allocated %i at %p\n", size, ptr);
140     if (!ptr)
141         PANIC_OUT_OF_MEM(size);
142     return ptr;
143 }
144 
145 
146 /*
147 
148 =item C<void * mem_sys_realloc_zeroed(void *from, size_t size, size_t old_size)>
149 
150 Resizes a chunk of system memory and fills the newly allocated space
151 with zeroes. If the pointer is C<NULL> a new memory block is
152 allocated and zeroed instead.
153 
154 =cut
155 
156 */
157 
158 PARROT_EXPORT
159 PARROT_MALLOC
160 PARROT_CANNOT_RETURN_NULL
161 void *
mem_sys_realloc_zeroed(ARGFREE (void * from),size_t size,size_t old_size)162 mem_sys_realloc_zeroed(ARGFREE(void *from), size_t size, size_t old_size)
163 {
164     ASSERT_ARGS(mem_sys_realloc_zeroed)
165     void *ptr;
166     if (size==0)
167         PANIC_ZERO_ALLOCATION("mem_sys_realloc_zeroed");
168     MEMORY_DEBUG_DETAIL_2("Freed %p (realloc -- %i bytes)\n", from, size);
169     ptr = from ? realloc(from, size) : malloc(size);
170     MEMORY_DEBUG_DETAIL_2("Allocated %i at %p\n", size, ptr);
171     if (!ptr)
172         PANIC_OUT_OF_MEM(size);
173 
174     if (size > old_size)
175         memset((char*)ptr + old_size, 0, size - old_size);
176 
177     return ptr;
178 }
179 
180 /*
181 
182 =item C<void mem_sys_free(void *from)>
183 
184 Frees a chunk of memory back to the system.
185 
186 =cut
187 
188 */
189 
190 PARROT_EXPORT
191 void
mem_sys_free(ARGFREE (void * from))192 mem_sys_free(ARGFREE(void *from))
193 {
194     ASSERT_ARGS(mem_sys_free)
195     MEMORY_DEBUG_DETAIL_2("Freed %p%s\n", from, "");
196     if (from)
197         free(from);
198 }
199 
200 /*
201 
202 =item C<char * mem_sys_strndup(const char *src, size_t size)>
203 
204 Copy a C string with supplied size to a new block of memory allocated with
205 mem_sys_allocate, that can be later deallocated with mem_sys_free.
206 
207 =cut
208 
209 */
210 
211 PARROT_EXPORT
212 PARROT_MALLOC
213 PARROT_CANNOT_RETURN_NULL
214 char *
mem_sys_strndup(ARGIN (const char * src),size_t size)215 mem_sys_strndup(ARGIN(const char *src), size_t size)
216 {
217     ASSERT_ARGS(mem_sys_strndup)
218 
219     char * const result = (char *)mem_sys_allocate(size + 1);
220     memcpy(result, src, size);
221     result[size] = '\0';
222     return result;
223 }
224 
225 /*
226 
227 =item C<char * mem_sys_strdup(const char *src)>
228 
229 Copy a C string to a new block of memory allocated with mem_sys_allocate,
230 that can be later deallocated with mem_sys_free.
231 
232 =cut
233 
234 */
235 
236 PARROT_EXPORT
237 PARROT_MALLOC
238 PARROT_CANNOT_RETURN_NULL
239 char *
mem_sys_strdup(ARGIN (const char * src))240 mem_sys_strdup(ARGIN(const char *src))
241 {
242     ASSERT_ARGS(mem_sys_strdup)
243 
244     const size_t l = strlen(src);
245     char * const result = (char *)mem_sys_allocate(l + 1);
246     memcpy(result, src, l);
247     result[l] = '\0';
248     return result;
249 }
250 
251 /*
252 
253 =item C<static void panic_failed_allocation(unsigned int line, unsigned long
254 size)>
255 
256 Print an error message and die.
257 
258 =cut
259 
260 */
261 
262 PARROT_DOES_NOT_RETURN
263 static void
panic_failed_allocation(unsigned int line,unsigned long size)264 panic_failed_allocation(unsigned int line, unsigned long size)
265 {
266     ASSERT_ARGS(panic_failed_allocation)
267 
268     fprintf(stderr, "Failed allocation of %lu bytes\n", size);
269     Parrot_x_panic_and_exit(NULL, "Out of mem", __FILE__, line);
270 }
271 
272 /*
273 
274 =item C<static void panic_zero_byte_allocation(unsigned int line, const char
275 *func)>
276 
277 Print an error message and die.
278 
279 =cut
280 
281 */
282 
283 PARROT_DOES_NOT_RETURN
284 static void
panic_zero_byte_allocation(unsigned int line,ARGIN (const char * func))285 panic_zero_byte_allocation(unsigned int line, ARGIN(const char *func))
286 {
287     ASSERT_ARGS(panic_zero_byte_allocation)
288 
289     fprintf(stderr, "Zero-byte allocation not allowed in %s", func);
290     Parrot_x_panic_and_exit(NULL, "Out of mem", __FILE__, line);
291 }
292 
293 /*
294 
295 =back
296 
297 =cut
298 
299 */
300 
301 /*
302  * Local variables:
303  *   c-file-style: "parrot"
304  * End:
305  * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
306  */
307