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