1 /*
2 memalloc.c:
3
4 Copyright (C) 1991 Barry Vercoe, John ffitch, Richard Dobson,
5 (C) 2005 Istvan Varga
6
7 This file is part of Csound.
8
9 The Csound Library is free software; you can redistribute it
10 and/or modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 Csound is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with Csound; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 02110-1301 USA
23 */
24
25 #include "csoundCore.h" /* MEMALLOC.C */
26
27 /* This code wraps malloc etc with maintaining a list of allocated memory
28 so it can be freed on a reset. It would not be necessary with a zoned
29 allocator.
30 */
31 #if defined(BETA) && !defined(MEMDEBUG)
32 #define MEMDEBUG 1
33 #endif
34
35 #define MEMALLOC_MAGIC 0x6D426C6B
36 /* The memory list must be controlled by mutex */
37 #define CSOUND_MEM_SPINLOCK csoundSpinLock(&csound->memlock);
38 #define CSOUND_MEM_SPINUNLOCK csoundSpinUnLock(&csound->memlock);
39
40 typedef struct memAllocBlock_s {
41 #ifdef MEMDEBUG
42 int magic; /* 0x6D426C6B ("mBlk") */
43 void *ptr; /* pointer to allocated area */
44 #endif
45 struct memAllocBlock_s *prv; /* previous structure in chain */
46 struct memAllocBlock_s *nxt; /* next structure in chain */
47 } memAllocBlock_t;
48
49 #define HDR_SIZE (((int) sizeof(memAllocBlock_t) + 7) & (~7))
50 #define ALLOC_BYTES(n) ((size_t) HDR_SIZE + (size_t) (n))
51 #define DATA_PTR(p) ((void*) ((unsigned char*) (p) + (int) HDR_SIZE))
52 #define HDR_PTR(p) ((memAllocBlock_t*) ((unsigned char*) (p) - (int) HDR_SIZE))
53
54 #define MEMALLOC_DB (csound->memalloc_db)
55
memdie(CSOUND * csound,size_t nbytes)56 static void memdie(CSOUND *csound, size_t nbytes)
57 {
58 csound->ErrorMsg(csound, Str("memory allocate failure for %zd"),
59 nbytes);
60 csound->LongJmp(csound, CSOUND_MEMORY);
61 }
62
mmalloc(CSOUND * csound,size_t size)63 void *mmalloc(CSOUND *csound, size_t size)
64 {
65 void *p;
66
67 #ifdef MEMDEBUG
68 if (UNLIKELY(size == (size_t) 0)) {
69 csound->DebugMsg(csound,
70 " *** internal error: mmalloc() called with zero nbytes\n");
71 return NULL;
72 }
73 #endif
74 /* allocate memory */
75 if (UNLIKELY((p = malloc(ALLOC_BYTES(size))) == NULL)) {
76 memdie(csound, size); /* does a long jump */
77 }
78 /* link into chain */
79 #ifdef MEMDEBUG
80 ((memAllocBlock_t*) p)->magic = MEMALLOC_MAGIC;
81 ((memAllocBlock_t*) p)->ptr = DATA_PTR(p);
82 #endif
83 CSOUND_MEM_SPINLOCK
84 ((memAllocBlock_t*) p)->prv = (memAllocBlock_t*) NULL;
85 ((memAllocBlock_t*) p)->nxt = (memAllocBlock_t*) MEMALLOC_DB;
86 if (MEMALLOC_DB != NULL)
87 ((memAllocBlock_t*) MEMALLOC_DB)->prv = (memAllocBlock_t*) p;
88 MEMALLOC_DB = (void*) p;
89 CSOUND_MEM_SPINUNLOCK
90 /* return with data pointer */
91 return DATA_PTR(p);
92 }
93
mmallocDebug(CSOUND * csound,size_t size,char * file,int line)94 void *mmallocDebug(CSOUND *csound, size_t size, char *file, int line)
95 {
96 void *ans = mmalloc(csound,size);
97 printf("Alloc %p (%zu) %s:%d\n", ans, size, file, line);
98 return ans;
99 }
100
mcalloc(CSOUND * csound,size_t size)101 void *mcalloc(CSOUND *csound, size_t size)
102 {
103 void *p;
104
105 #ifdef MEMDEBUG
106 if (UNLIKELY(size == (size_t) 0)) {
107 csound->DebugMsg(csound,
108 " *** internal error: csound->Calloc() called with zero nbytes\n");
109 return NULL;
110 }
111 #endif
112 /* allocate memory */
113 if (UNLIKELY((p = calloc(ALLOC_BYTES(size), (size_t) 1)) == NULL)) {
114 memdie(csound, size); /* does longjump */
115 }
116 /* link into chain */
117 #ifdef MEMDEBUG
118 ((memAllocBlock_t*) p)->magic = MEMALLOC_MAGIC;
119 ((memAllocBlock_t*) p)->ptr = DATA_PTR(p);
120 #endif
121 CSOUND_MEM_SPINLOCK
122 ((memAllocBlock_t*) p)->prv = (memAllocBlock_t*) NULL;
123 ((memAllocBlock_t*) p)->nxt = (memAllocBlock_t*) MEMALLOC_DB;
124 if (MEMALLOC_DB != NULL)
125 ((memAllocBlock_t*) MEMALLOC_DB)->prv = (memAllocBlock_t*) p;
126 MEMALLOC_DB = (void*) p;
127 CSOUND_MEM_SPINUNLOCK
128 /* return with data pointer */
129 return DATA_PTR(p);
130 }
131
mcallocDebug(CSOUND * csound,size_t size,char * file,int line)132 void *mcallocDebug(CSOUND *csound, size_t size, char *file, int line)
133 {
134 void *ans = mcalloc(csound,size);
135 printf("Alloc %p (%zu) %s:%d\n", ans, size, file, line);
136 return ans;
137 }
138
139
mfree(CSOUND * csound,void * p)140 void mfree(CSOUND *csound, void *p)
141 {
142 memAllocBlock_t *pp;
143
144 if (UNLIKELY(p == NULL))
145 return;
146 pp = HDR_PTR(p);
147 #ifdef MEMDEBUG
148 if (UNLIKELY(pp->magic != MEMALLOC_MAGIC || pp->ptr != p)) {
149 csound->Warning(csound, "csound->Free() called with invalid "
150 "pointer (%p) %x %p %x",
151 p, pp->magic, pp->ptr, MEMALLOC_MAGIC);
152 /* exit() is ugly, but this is a fatal error that can only occur */
153 /* as a result of a bug */
154 /* exit(-1); */
155 /*VL 28-12-12 - returning from here instead of exit() */
156 return;
157 }
158 pp->magic = 0;
159 #endif
160 CSOUND_MEM_SPINLOCK
161 /* unlink from chain */
162 {
163 memAllocBlock_t *prv = pp->prv, *nxt = pp->nxt;
164 if (nxt != NULL)
165 nxt->prv = prv;
166 if (prv != NULL)
167 prv->nxt = nxt;
168 else
169 MEMALLOC_DB = (void*)nxt;
170 }
171 //csound->Message(csound, "free\n");
172 /* free memory */
173 free((void*) pp);
174 CSOUND_MEM_SPINUNLOCK
175 }
176
mfreeDebug(CSOUND * csound,void * ans,char * file,int line)177 void mfreeDebug(CSOUND *csound, void *ans, char *file, int line)
178 {
179 printf("Free %p %s:%d\n", ans, file, line);
180 mfree(csound,ans);
181 }
182
mrealloc(CSOUND * csound,void * oldp,size_t size)183 void *mrealloc(CSOUND *csound, void *oldp, size_t size)
184 {
185 memAllocBlock_t *pp;
186 void *p;
187
188 if (UNLIKELY(oldp == NULL))
189 return mmalloc(csound, size);
190 if (UNLIKELY(size == (size_t) 0)) {
191 mfree(csound, oldp);
192 return NULL;
193 }
194 pp = HDR_PTR(oldp);
195 #ifdef MEMDEBUG
196 if (UNLIKELY(pp->magic != MEMALLOC_MAGIC || pp->ptr != oldp)) {
197 csound->DebugMsg(csound, " *** internal error: mrealloc() called with invalid "
198 "pointer (%p)\n", oldp);
199 /* exit() is ugly, but this is a fatal error that can only occur */
200 /* as a result of a bug */
201 exit(-1);
202 }
203 /* mark old header as invalid */
204 pp->magic = 0;
205 pp->ptr = NULL;
206 #endif
207 /* allocate memory */
208 p = realloc((void*) pp, ALLOC_BYTES(size));
209 if (UNLIKELY(p == NULL)) {
210 #ifdef MEMDEBUG
211 CSOUND_MEM_SPINLOCK
212 /* alloc failed, restore original header */
213 pp->magic = MEMALLOC_MAGIC;
214 pp->ptr = oldp;
215 CSOUND_MEM_SPINUNLOCK
216 #endif
217 memdie(csound, size);
218 return NULL;
219 }
220 CSOUND_MEM_SPINLOCK
221 /* create new header and update chain pointers */
222 pp = (memAllocBlock_t*) p;
223 #ifdef MEMDEBUG
224 pp->magic = MEMALLOC_MAGIC;
225 pp->ptr = DATA_PTR(pp);
226 #endif
227 {
228 memAllocBlock_t *prv = pp->prv, *nxt = pp->nxt;
229 if (nxt != NULL)
230 nxt->prv = pp;
231 if (prv != NULL)
232 prv->nxt = pp;
233 else
234 MEMALLOC_DB = (void*) pp;
235 }
236 CSOUND_MEM_SPINUNLOCK
237 /* return with data pointer */
238 return DATA_PTR(pp);
239 }
240
mreallocDebug(CSOUND * csound,void * oldp,size_t size,char * file,int line)241 void *mreallocDebug(CSOUND *csound, void *oldp, size_t size, char *file, int line)
242 {
243 void *p = mrealloc(csound, oldp, size);
244 printf("Realloc %p->%p (%zu) %s:%d\n", oldp, p, size, file, line);
245 return p;
246 }
247
memRESET(CSOUND * csound)248 void memRESET(CSOUND *csound)
249 {
250 memAllocBlock_t *pp, *nxtp;
251
252 pp = (memAllocBlock_t*) MEMALLOC_DB;
253 MEMALLOC_DB = NULL;
254 while (pp != NULL) {
255 nxtp = pp->nxt;
256 #ifdef MEMDEBUG
257 pp->magic = 0;
258 #endif
259 free((void*) pp);
260 pp = nxtp;
261 }
262 }
263