1 /* File: memsubs.c
2 * Author: Richard Durbin (rd@sanger.ac.uk)
3 * Copyright (C) J Thierry-Mieg and R Durbin, 1998
4 *-------------------------------------------------------------------
5 * This file is part of the ACEDB genome database package, written by
6 * Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and
7 * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
8 *
9 * Description:
10 * Exported functions:
11 * HISTORY:
12 * Last edited: Dec 4 11:24 1998 (fw)
13 * Created: Thu Aug 20 16:54:55 1998 (rd)
14 *-------------------------------------------------------------------
15 */
16
17 /* define MALLOC_CHECK here to check mallocs - also in regular.h */
18
19 #include "regular.h"
20
21 #if defined(NEXT) || defined(HP) || defined(MACINTOSH)
22 extern void* malloc(mysize_t size) ;
23 #elif !defined(WIN32) && !defined(DARWIN)
24 #include <stdlib.h> /* normal machines */
25 #endif
26
27 /********** primary type definition **************/
28
29 typedef struct _STORE_HANDLE_STRUCT {
30 STORE_HANDLE next ; /* for chaining together on Handles */
31 STORE_HANDLE back ; /* to unchain */
32 void (*final)(void*) ; /* finalisation routine */
33 int size ; /* of user memory to follow */
34 #ifdef MALLOC_CHECK
35 int check1 ; /* set to known value */
36 #endif
37 } STORE_HANDLE_STRUCT ;
38
39 /*********************************************************************/
40 /********** memory allocation - messalloc() and handles *************/
41
42 static int numMessAlloc = 0 ;
43 static int totMessAlloc = 0 ;
44
45
46 /* Calculate to size of an STORE_HANDLE_STRUCT rounded to the nearest upward
47 multiple of sizeof(double). This avoids alignment problems when
48 we put an STORE_HANDLE_STRUCT at the start of a memory block */
49
50 #define STORE_OFFSET ((((sizeof(STORE_HANDLE_STRUCT)-1)/MALLOC_ALIGNMENT)+1)\
51 * MALLOC_ALIGNMENT)
52
53
54 /* macros to convert between a void* and the corresponding STORE_HANDLE */
55
56 #define toAllocUnit(x) (STORE_HANDLE) ((char*)(x) - STORE_OFFSET)
57 #define toMemPtr(unit)((void*)((char*)(unit) + STORE_OFFSET))
58
59 #ifdef MALLOC_CHECK
60 BOOL handlesInitialised = FALSE;
61 static Array handles = 0 ;
62
63 /* macro to give the terminal check int for an STORE_HANDLE_STRUCT */
64 /* unit->size must be a multiple of sizeof(int) */
65 #define check2(unit) *(int*)(((char*)toMemPtr(unit)) + (unit)->size)
66
67 static void checkUnit (STORE_HANDLE unit) ;
handleOrder(void * a,void * b)68 static int handleOrder (void *a, void *b)
69 { return (*((STORE_HANDLE *)a) == *((STORE_HANDLE *)b)) ? 0 :
70 (*((STORE_HANDLE *)a) > *((STORE_HANDLE *)b)) ? 1 : -1 ;
71 }
72 #endif
73 #if defined(MALLOC_CHECK) || defined(MEM_DEBUG)
74 STORE_HANDLE_STRUCT handle0 ;
75 #endif
76
77 /************** halloc(): key function - messalloc() calls this ****************/
78
79 #ifdef MEM_DEBUG
halloc_dbg(int size,STORE_HANDLE handle,const char * hfname,int hlineno)80 void *halloc_dbg(int size, STORE_HANDLE handle,const char *hfname, int hlineno)
81 #else
82 void *halloc(int size, STORE_HANDLE handle)
83 #endif
84 {
85 STORE_HANDLE unit ;
86
87 #ifdef MALLOC_CHECK
88 if (!handlesInitialised) /* initialise */
89 { handlesInitialised = TRUE;
90 /* BEWARE, arrayCreate calls handleAlloc, line above must precede
91 following line to avoid infinite recursion */
92 handles = arrayCreate (16, STORE_HANDLE) ;
93 array (handles, 0, STORE_HANDLE) = &handle0 ;
94 handle0.next = 0 ;
95 }
96
97 while (size % INT_ALIGNMENT) size++ ; /* so check2 alignment is OK */
98 unit = (STORE_HANDLE) malloc(STORE_OFFSET + size + sizeof(int)) ;
99 if (unit) memset (unit, 0, STORE_OFFSET + size + sizeof(int)) ;
100 #else
101 unit = (STORE_HANDLE) malloc(STORE_OFFSET + size) ;
102 if (unit) memset (unit, 0, STORE_OFFSET + size) ;
103 #endif
104
105 if (!unit) /* out of memory -> messcrash */
106 {
107 messcrash (
108 "Memory allocation failure when requesting %d bytes, %d already allocated",
109 size, totMessAlloc) ;
110 }
111 #if defined(MALLOC_CHECK) || defined(MEM_DEBUG)
112 if (!handle)
113 handle = &handle0 ;
114 #endif
115 if (handle)
116 { unit->next = handle->next ;
117 unit->back = handle ;
118 if (handle->next) (handle->next)->back = unit ;
119 handle->next = unit ;
120 }
121
122 unit->size = size ;
123 #ifdef MALLOC_CHECK
124 unit->check1 = 0x12345678 ;
125 check2(unit) = 0x12345678 ;
126 #endif
127
128 ++numMessAlloc ;
129 totMessAlloc += size ;
130
131 return toMemPtr(unit) ;
132 }
133
blockSetFinalise(void * block,void (* final)(void *))134 void blockSetFinalise(void *block, void (*final)(void *))
135 { STORE_HANDLE unit = toAllocUnit(block);
136 unit->final = final ;
137 }
138
139 /***** handleAlloc() - does halloc() + blockSetFinalise() - archaic *****/
140
141 #ifdef MEM_DEBUG
handleAlloc_dbg(void (* final)(void *),STORE_HANDLE handle,int size,const char * hfname,int hlineno)142 void *handleAlloc_dbg (void (*final)(void*), STORE_HANDLE handle, int size,
143 const char *hfname, int hlineno)
144 {
145 void *result = halloc_dbg(size, handle, hfname, hlineno) ;
146 #else
147 void *handleAlloc (void (*final)(void*), STORE_HANDLE handle, int size)
148 {
149 void *result = halloc(size, handle);
150 #endif
151 if (final)
152 blockSetFinalise(result, final);
153
154 return result;
155 }
156
157 /****************** useful utility ************/
158
159 #ifdef MEM_DEBUG
160 char *strnew_dbg(char *old, STORE_HANDLE handle, const char *hfname, int hlineno)
161 { char *result = 0 ;
162 if (old)
163 { result = (char *)halloc_dbg(1+strlen(old), handle, hfname, hlineno) ;
164 #else
165 char *strnew(char *old, STORE_HANDLE handle)
166 { char *result = 0 ;
167 if (old)
168 { result = (char *)halloc(1+strlen(old), handle);
169 #endif
170 strcpy(result, old);
171 }
172 return result;
173 }
174
175 /****************** messfree ***************/
176
177 void umessfree (void *cp)
178 {
179 STORE_HANDLE unit = toAllocUnit(cp) ;
180
181 #ifdef MALLOC_CHECK
182 checkUnit (unit) ;
183 unit->check1 = 0x87654321; /* test for double free */
184 #endif
185
186 if (unit->final)
187 (*unit->final)(cp) ;
188
189 if (unit->back)
190 { (unit->back)->next = unit->next;
191 if (unit->next) (unit->next)->back = unit->back;
192 }
193
194 --numMessAlloc ;
195 totMessAlloc -= unit->size ;
196 free (unit) ;
197 }
198
199 /************** create and destroy handles **************/
200
201 /* NOTE: handleDestroy is #defined in regular.h to be messfree */
202 /* The actual work is done by handleFinalise, which is the finalisation */
203 /* routine attached to all STORE_HANDLEs. This allows multiple levels */
204 /* of free-ing by allocating new STORE_HANDLES on old ones, using */
205 /* handleHandleCreate. handleCreate is simply defined as handleHandleCreate(0) */
206
207 static void handleFinalise (void *p)
208 {
209 STORE_HANDLE handle = (STORE_HANDLE)p;
210 STORE_HANDLE next, unit = handle->next ;
211
212 /* do handle finalisation first */
213 if (handle->final)
214 (*handle->final)((void *)handle->back);
215
216 while (unit)
217 {
218 #ifdef MALLOC_CHECK
219 checkUnit (unit) ;
220 unit->check1 = 0x87654321; /* test for double free */
221 #endif
222 if (unit->final)
223 (*unit->final)(toMemPtr(unit)) ;
224 next = unit->next ;
225 --numMessAlloc ;
226 totMessAlloc -= unit->size ;
227 free (unit) ;
228 unit = next ;
229 }
230
231 #ifdef MALLOC_CHECK
232 arrayRemove (handles, &p, handleOrder) ;
233 #endif
234
235 /* This is a finalisation routine, the actual store is freed in messfree,
236 or another invokation of itself. */
237 }
238
239 void handleSetFinalise(STORE_HANDLE handle, void (*final)(void *), void *arg)
240 { handle->final = final;
241 handle->back = (STORE_HANDLE)arg;
242 }
243
244 STORE_HANDLE handleHandleCreate(STORE_HANDLE handle)
245 {
246 STORE_HANDLE res = (STORE_HANDLE) handleAlloc(handleFinalise,
247 handle,
248 sizeof(STORE_HANDLE_STRUCT));
249 #ifdef MALLOC_CHECK
250 /* NB call to handleAlloc above ensures that handles is initialised here */
251 arrayInsert (handles, &res, handleOrder) ;
252 #endif
253 res->next = res->back = 0 ; /* No blocks on this handle yet. */
254 res->final = 0 ; /* No handle finalisation */
255 return res ;
256 }
257
258 BOOL finalCleanup = FALSE ;
259 #ifdef MEM_DEBUG
260 void handleCleanUp (void)
261 { finalCleanup = TRUE ;
262 handleFinalise ((void *)&handle0) ;
263 }
264 #endif
265
266 /************** checking functions, require MALLOC_CHECK *****/
267
268 #ifdef MALLOC_CHECK
269 static void checkUnit (STORE_HANDLE unit)
270 {
271 if (unit->check1 == 0x87654321)
272 messerror ("Block at %x freed twice - bad things will happen.",
273 toMemPtr(unit));
274 else
275 if (unit->check1 != 0x12345678)
276 messerror ("Malloc error at %x length %d: "
277 "start overwritten with %x",
278 toMemPtr(unit), unit->size, unit->check1) ;
279
280 if (check2(unit) != 0x12345678)
281 messerror ("Malloc error at %x length %d: "
282 "end overwritten with %x",
283 toMemPtr(unit), unit->size, check2(unit)) ;
284 }
285
286 void messalloccheck (void)
287 {
288 int i ;
289 STORE_HANDLE unit ;
290
291 if (!handles) return ;
292
293 for (i = 0 ; i < arrayMax(handles) ; ++i)
294 for (unit = arr(handles,i,STORE_HANDLE)->next ; unit ; unit=unit->next)
295 checkUnit (unit) ;
296 }
297 #else
298 void messalloccheck (void) {}
299 #endif
300
301 /******************* status monitoring functions ******************/
302
303 void handleInfo (STORE_HANDLE handle, int *number, int *size)
304 {
305 STORE_HANDLE unit = handle->next;
306
307 *number = 0;
308 *size = 0;
309
310 while (unit)
311 { ++*number ;
312 *size += unit->size ;
313 unit = unit->next ;
314 }
315 }
316
317 int messAllocStatus (int *mem)
318 {
319 *mem = totMessAlloc ;
320 return numMessAlloc ;
321 }
322
323 /*************************** end of file ************************/
324 /****************************************************************/
325