chiark / gitweb /
Synchronize with trunk
[disorder] / lib / mem.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004, 2005, 2006, 2007, 2009 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/mem.c
19  * @brief Memory management
20  */
21
22 #include "common.h"
23
24 #if GC
25 #include <gc.h>
26 #endif
27 #include <errno.h>
28
29 #include "mem.h"
30 #include "log.h"
31 #include "printf.h"
32
33 #include "disorder.h"
34
35 /** @brief Allocate and zero out
36  * @param n Number of bytes to allocate
37  * @return Pointer to allocated memory,  or 0
38  */
39 static void *malloc_and_zero(size_t n) {
40   void *ptr = malloc(n);
41
42   if(ptr) memset(ptr, 0, n);
43   return ptr;
44 }
45
46 #if GC
47 static void *(*do_malloc)(size_t) = GC_malloc;
48 static void *(*do_realloc)(void *, size_t) = GC_realloc;
49 static void *(*do_malloc_atomic)(size_t) = GC_malloc_atomic;
50 static void (*do_free)(void *) = GC_free;
51 #else
52 static void *(*do_malloc)(size_t) = malloc_and_zero;
53 static void *(*do_realloc)(void *, size_t) = realloc;
54 static void *(*do_malloc_atomic)(size_t) = malloc;
55 static void (*do_free)(void *) = free;
56 #endif
57
58 /** @brief Initialize memory management
59  *
60  * Must be called by all programs that use garbage collection.  Define
61  * @c ${DISORDER_GC} to @c no to suppress use of the collector
62  * (e.g. for debugging purposes).
63  */
64 void mem_init(void) {
65 #if GC
66   const char *e;
67   
68   if(((e = getenv("DISORDER_GC")) && !strcmp(e, "no"))) {
69     do_malloc = malloc_and_zero;
70     do_malloc_atomic = malloc;
71     do_realloc = realloc;
72     do_free = free;
73   } else {
74     GC_init();
75     assert(GC_all_interior_pointers);
76   }
77 #endif
78 }
79
80 /** @brief Allocate memory
81  * @param n Bytes to allocate
82  * @return Pointer to allocated memory
83  *
84  * Terminates the process on error.  The allocated memory is always
85  * 0-filled.
86  */
87 void *xmalloc(size_t n) {
88   void *ptr;
89
90   if(!(ptr = do_malloc(n)) && n)
91     disorder_fatal(errno, "error allocating memory");
92   return ptr;
93 }
94
95 /** @brief Reallocate memory
96  * @param ptr Block to reallocated
97  * @param n Bytes to allocate
98  * @return Pointer to allocated memory
99  *
100  * Terminates the process on error.  It is NOT guaranteed that any
101  * additional memory allocated is 0-filled.
102  */
103 void *xrealloc(void *ptr, size_t n) {
104   if(!(ptr = do_realloc(ptr, n)) && n)
105     disorder_fatal(errno, "error allocating memory");
106   return ptr;
107 }
108
109 /** @brief Allocate memory
110  * @param count Number of objects to allocate
111  * @param size Size of one object
112  * @return Pointer to allocated memory
113  *
114  * Terminates the process on error.  The allocated memory is always
115  * 0-filled.
116  */
117 void *xcalloc(size_t count, size_t size) {
118   if(count > SIZE_MAX / size)
119     disorder_fatal(0, "excessively large calloc");
120   return xmalloc(count * size);
121 }
122
123 /** @brief Allocate memory
124  * @param n Bytes to allocate
125  * @return Pointer to allocated memory
126  *
127  * Terminates the process on error.  The allocated memory is not
128  * guaranteed to be 0-filled and is not suitable for storing pointers
129  * in.
130  */
131 void *xmalloc_noptr(size_t n) {
132   void *ptr;
133
134   if(!(ptr = do_malloc_atomic(n)) && n)
135     disorder_fatal(errno, "error allocating memory");
136   return ptr;
137 }
138
139 /** @brief Allocate memory
140  * @param count Number of objects to allocate
141  * @param size Size of one object
142  * @return Pointer to allocated memory
143  *
144  * Terminates the process on error.  IMPORTANT: the allocated memory is NOT
145  * 0-filled (unlike @c calloc()).
146  */
147 void *xcalloc_noptr(size_t count, size_t size) {
148   if(count > SIZE_MAX / size)
149     disorder_fatal(0, "excessively large calloc");
150   return xmalloc_noptr(count * size);
151 }
152
153 /** @brief Reallocate memory
154  * @param ptr Block to reallocated
155  * @param n Bytes to allocate
156  * @return Pointer to allocated memory
157  *
158  * Terminates the processf on error.  It is NOT guaranteed that any
159  * additional memory allocated is 0-filled.  The block must have been
160  * allocated with xmalloc_noptr() (or xrealloc_noptr()) initially.
161  */
162 void *xrealloc_noptr(void *ptr, size_t n) {
163   if(ptr == 0)
164     return xmalloc_noptr(n);
165   if(!(ptr = do_realloc(ptr, n)) && n)
166     disorder_fatal(errno, "error allocating memory");
167   return ptr;
168 }
169
170 /** @brief Duplicate a string
171  * @param s String to copy
172  * @return New copy of string
173  *
174  * This uses the equivalent of xmalloc_noptr() to allocate the new string.
175  */
176 char *xstrdup(const char *s) {
177   char *t;
178
179   if(!(t = do_malloc_atomic(strlen(s) + 1)))
180     disorder_fatal(errno, "error allocating memory");
181   return strcpy(t, s);
182 }
183
184 /** @brief Duplicate a prefix of a string
185  * @param s String to copy
186  * @param n Prefix of string to copy
187  * @return New copy of string
188  *
189  * This uses the equivalent of xmalloc_noptr() to allocate the new string.
190  * @p n must not exceed the length of the string.
191  */
192 char *xstrndup(const char *s, size_t n) {
193   char *t;
194
195   if(!(t = do_malloc_atomic(n + 1)))
196     disorder_fatal(errno, "error allocating memory");
197   memcpy(t, s, n);
198   t[n] = 0;
199   return t;
200 }
201
202 /** @brief Free memory
203  * @param ptr Block to free or 0
204  */
205 void xfree(void *ptr) {
206   do_free(ptr);
207 }
208
209 /*
210 Local Variables:
211 c-basic-offset:2
212 comment-column:40
213 fill-column:79
214 indent-tabs-mode:nil
215 End:
216 */