fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / regina / memory.c
blob2d8759691a367a53c2351a84448f4a2f77d0997c
1 #if 0
2 #define REGINA_DEBUG_MEMORY
3 #define REGINA_DEBUG_MEMORY1
4 #define REGINA_DEBUG_MEMORY2
5 #define REGINA_DEBUG_MEMORY3
6 #endif
7 /*
8 * The Regina Rexx Interpreter
9 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public
22 * License along with this library; if not, write to the Free
23 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * The routines in this file try to minimize the the number of calls
28 * to malloc() and free(). Since it would generally not be possible to
29 * release memory, unless it actually is last in the virtual memory
30 * that the process holds, just don't release it, and let the
31 * interpreter grow. Memory are allocated in only certain sizes, and
32 * are "freed" to a freelist, which is within the interpreter.
34 * The important routines are get_a_chunk() and give_a_chunk(), which
35 * might be called a large number of times. All the other routines are
36 * either called once to initiate, or it is used in tracing and
37 * debugging, where speed and space is not important anyway.
39 * The algorithm works something like this: memory can only be allocated
40 * in predetermined sizes (8, 12, 16, 24, 32, ...) and allocation of a
41 * size other than that will have to allocate something slightly bigger.
42 * For each size, there is a linked list of free pieces of memory of
43 * that size, the first entry of each of these lists can be accessed
44 * through 'flists', which is an array of pointers to these lists.
46 * Every time someone needs a piece of memory, the first piece of the
47 * freelist containing memory of suitable size (as big or slightly
48 * bigger) is returned. If the list is empty, a large piece of
49 * memory is allocated by malloc(), chopped up and put on the freelist
50 * that was empty.
52 * When memory is released, the prime problem is to decide which
53 * freelist to put it on. To manage that, each time memory is
54 * allocated by malloc(), the upper and lower address of the memory
55 * is put in hashtable; given a particular address, the hashtable
56 * can be sought using the address as hashvalue, and the result will
57 * be the size of the memory chunks at that address.
59 * When dealloacting strings, we know the max-size of the string, and
60 * then we can calculate which freelist the string should be put on,
61 * without having to search the hashtable structure. Note that there
62 * is no need to deallocate strings using the give_a_string() function,
63 * the normal give_a_chunk() will work just as well, but is somewhat
64 * slower.
66 * If you don't #define FLISTS, then malloc() and free() should be
67 * used instead. That might be very slow on some machines, since rexx
68 * tend to use lots of small size memory. If you #define TRACEMEM,
69 * memory is traced, which also tend to be slow, since there is a lot
70 * of overhead in allocation and deallocation. Also note that in the
71 * current implementation you can use malloc()/free() in parallel with
72 * the routines defined here.
74 * Note that using this metod, the last piece of memory freed will be
75 * the first to be used when more memory is needed.
77 * The number of calls to malloc() seems to be negligable when using
78 * this method (typical less than 100 for medium sized programs). But
79 * this is of course dependent on how the program uses memory.
81 * The tracing part of this file, (#ifdef TRACEMEM) is an optional
82 * extention for debugging purposes. Whenever memory is allocated,
83 * mymalloc() allocates 16 bytes more than needed. These bytes are
84 * used like this:
86 * 0 4 8 12 16 bytes
87 * | count |f|m|seq| prev | next | start of allocated memory
89 * The 'count' is the number of bytes allocated, 'f' (flag) is used in
90 * garbage collection, and 'prev' and 'next' are pointers used in a
91 * double linked list. seqv is a sequence number which is iterated
92 * for each memoryallocation.
94 * count is int, prev and next are char*, f is char and seqv is a
95 * 16 bit integer. The 'm' is a magic number. Actually it is just
96 * there to fill the space, and can be used for more useful purposed
97 * if needed.
99 * An additional option to TRACEMEM is filling allocated and deallocated
100 * memory with bitpatterns. If the PATTERN_MEMORY cpp-variable is set,
101 * all allocated memory is initated to NOT_USED, and deallocated memory
102 * is set BEEN_USED before deallocation.
104 * Garbage-collection is not implemented, but listleaked will list out
105 * every chunk of allocated memory that are not currently in use. The
106 * array markptrs contains a list of functions for marking memory.
107 * There is a potential problem with garbage collection, since the
108 * interpreter might 'loose' some memory everytime it hits a syntax
109 * error, like "say random(.5)". To fix that, memory should either
110 * be traced and then garbage collected, or it should have a sort
111 * of transaction oriented memory management (yuk!).
113 * NOTE that #define'ing TRACEMEM requires that your machine follows
114 * this: sizeof(int) = sizeof(char*) = 32 bits. It might work
115 * for other machines to (having larger word size), but I don't
116 * guarantee it.
120 #include "rexx.h"
121 #include <stdlib.h>
122 #include <stdio.h>
123 #include <assert.h>
124 #include <string.h>
126 #ifdef TRACEMEM
128 * If we are tracing memory, each piece of allocated memory gets the
129 * following header prepended, which are used to keep track of that
130 * piece of memory.
132 typedef struct memhead
134 int count ; /* Size of this piece of memeory */
135 struct memhead *prev, *next ; /* Ptrs in double linked list */
136 unsigned short seqv ; /* Sequential counter */
137 unsigned char flag ; /* What is this memory used for */
138 unsigned char magic ; /* Not really used */
139 void *addr;
140 } memheader;
142 # ifdef PATTERN_MEMORY
144 * The two byte values NOT_USED and BEEN_USED are patterns which newly
145 * allocated dynamic memory will be set to, and memory to be freed
146 * will be set to, respectively. This is done to provoke problems if
147 * memory is used but not initialized, or if it used after is has
148 * been released.
151 # define NOT_USED (0x42) /* letter 'B' */
152 # define BEEN_USED (0x69) /* letter 'i' */
155 * The magic cookie is just a placeholder, it is checked for consistency
156 * but could easily be used for something else, if the space is needed.
158 # define MAGIC_COOKIE (0xd4)
160 # endif /* PATTERN_MEMORY */
161 #endif /* TRACEMEM */
164 #ifdef FLISTS
166 * CHUNK_SIZE it the size in which memory is allocated using malloc(),
167 * and that memory is then divided into pieces of the wanted size.
168 * If you increase it, things will work slightly faster, but more
169 * memory is wasted, and vice versa. The 'right' size is dependent on
170 * your machine, rexx scripts and your personal taste.
172 #define CHUNK_SIZE (8192*4) /* JO - was 8192 */
175 * MAX_INTERNAL_SIZE is the max size of individual pieces of memory
176 * that this system will handle itself. If bigger pieces are requested
177 * it will just forward the request to malloc()/free(). Note that
178 * this value should be less than or equal to CHUNK_SIZE.
180 #define MAX_INTERNAL_SIZE (8192*3) /* JO - was 4096 */
183 * MEMINFO_HASHSIZE is the size of the 'hashtable' used to find the size
184 * of a chunk of memory, given an address of a byte within that chunk.
185 * Actually, this isn't much of a real hashtable, but still. Allocating
186 * large value will not make much harm other than wasting memory. Using
187 * too small value can seriously degrade execution. The optimal size
188 * is such that MEMINFO_HASHSIZE * CHUNK_SIZE is only slight bigger
189 * than the actual use of memory in your rexx script (including the
190 * memory that will be wasted)
192 #define MEMINFO_HASHSIZE (499)
195 * FLIST_ARRAY_SIZE is the element count of an array which holds meminfo's
196 * (see below) while allocating space. Have a look at add_entry() below.
198 #define FLIST_ARRAY_SIZE 128
201 * GET_SIZE() is a 'function' that returns a index into the 'hash'
202 * variable, given a specific number. The index returned will be the
203 * index of the ptr to the list of free memory entries that is identical
204 * or slightly bigger than the parameter in size.
206 #define GET_SIZE(mt,a) (mt->hash[((a)+3)>>2])
209 * This is the hashfunction for use with 'hashtable'. It will effectively
210 * just shift away some of the lower bits and fold the result around
211 * the 'hashtable'. Note that '13' is corresponent to CHUNK_SIZE, since
212 * 8192 == 1<<13, which is the optimal size. If you change one of them
213 * be sure to change the other.
215 * Maybe we could eliminate a division by letting MEMINFO_HASHSIZE have
216 * a number equal to a binary 'round' number (e.g. 512). There is no
217 * need to keep the size a prime number, since the elements in the
218 * table *will* be well distributed.
219 * 8192*4 == 1<<15
220 * JO was 13
222 #define mem_hash_func(a) (((a)>>15)%MEMINFO_HASHSIZE)
225 * Here are the list of the 'approved' sizes. Memory is only allocatable
226 * in these sizes. If you need anything else, use the lowest number that
227 * is higher than what you need.
229 * Why exactly these numbers? Why not? Note that these are a subset
230 * of the series {8,16,32,64,128...} and {12,24,48,96} mingled together.
231 * Note that you can not allocate memory in smaller sizes than is
232 * possible to fit a pointer (to char and/or void) into. Also take
233 * into consideration that all these sizes should be aligned according
234 * to the size of ints and pointers, so don't make them too small.
236 #define NUMBER_SIZES 25 /* JO - was 19 */
237 static const int sizes[NUMBER_SIZES] =
238 { 8, 12, 16, 24, 32, 48, 64, 96,
239 128, 192 , 256, 384, 512, 768, 1024, 1536,
240 2048, 3072, 4096,
241 4096+2048, 8192,
242 8192+4096, 16384,
243 16384+8192,32768 };
245 * The type meminfo holds the info about the connection between the
246 * address of allocated memory and the size of that memory. When new
247 * memory is allocated by malloc(), in size CHUNK_SIZE, a new box of
248 * meminfo is created, which holds the address returned from malloc()
249 * and the size in which the chunk was divided {8,12,16,24,32...}.
251 typedef struct meminfo_type
253 char *start ; /* start of memory's address */
254 char *last ; /* end of memory's address */
255 struct meminfo_type *next ; /* next ptr in linked list */
256 int size ; /* size of chunks at that address */
257 } meminfo ;
258 #endif /* FLISTS */
260 typedef struct { /* mem_tsd: static variables of this module (thread-safe) */
261 #ifdef FLISTS
263 * The array of pointers to the freelists having memory of the sizes
264 * specified in 'sizes'. I.e. flists[0] is a pointer to a linked list
265 * of free memory chunks of size 8, flist[1] to memory of size 12 etc.
266 * The size of this array is the same as the size of 'sizes'.
268 char *flists[NUMBER_SIZES];
271 * The 'hashtable'. Used for quick access to the size of a chunk of
272 * memory, given its address.
274 meminfo *hashtable[ MEMINFO_HASHSIZE ];
277 * These variables track the allocation of memory allocated by
278 * MallocTSD() and used by the internal memory allocation
279 * mechanism.
281 meminfo *first_entry;
282 meminfo *curr_entry;
284 * Array used for rounding a number to an 'approved' size, i.e. a size
285 * in which the interpreter will allocate memory. Remember that the
286 * approved sizes are {8,12,16,24,32 ...}? This function will return
287 * 8 for 1 through 8; 12 for 9 through 12; 16 for 13 through 16 etc.
288 * It is not initially set, but will be set by init_memory().
290 * Note: the 'step' in this table (4 as it is defined below) must not
291 * be bigger then the smallest gap in between two 'approved' sizes of
292 * memory. E.g the smallest gap as defined above is 12-8 = 4.
294 * Actually, the name is somewhat misleading, since this is not really
295 * a hashtable, it is just a leftover from the time when it actually
296 * was a hashtable.
298 * Due to how the hash array is initialized, we have to allocate one
299 * more item than is going to be used. This is really a klugde, and we
300 * really ought to fix it a more clean way.
302 short hash[ CHUNK_SIZE/4 + 1 ] ;
304 /* See add_entry() for the following two variables */
305 meminfo *mem_ctl ;
306 int mem_ctl_idx ;
307 #endif
309 #ifdef TRACEMEM
311 * Counter for dynamically memory allocated, in bytes, and ditto for
312 * the deallocated memory, dynamic memory currently in use is the
313 * difference between these. This is only used for gathering
314 * statistics.
316 int allocated ;
317 int deallocated ;
320 * Sequence number for newly allocated memory, incremented for each
321 * new allocation of dynamic memory. Actually, it is stored as a
322 * unsigned short in the memhead of each memory allocation. That might
323 * be slightly too small, since the number of memory allocation can
324 * easily reach 100000, even for relatively small programs.
326 * Therefore, the sequence number might be stored as a 24 bit number,
327 * (on 32 bit machines). But anyway, who cares, it is only used for
328 * debugging purposes.
330 int sequence ;
333 * Pointer to last (most newly) allocated memorychunk in double linked
334 * list of all allocated dynamic memory.
336 struct memhead *header0 ;
338 #define MAX_MARKERS 100
339 void (*(markers[MAX_MARKERS]))(const tsd_t *TSD) ;
340 int max_markers_regd ;
341 #endif
342 int FillerForThisStructure;
343 } mem_tsd_t; /* thread-specific but only needed by this module. see
344 * init_memory
347 #ifdef FLISTS
348 static void init_hash_table( mem_tsd_t *mt ) ;
349 # ifdef REGINA_DEBUG_MEMORY
350 static int show_a_free_list(mem_tsd_t *mt, int bin, char *str );
351 # endif
352 #endif
355 * This function initiates the 'mem_tsd'. This might have been
356 * done initially, since the values in this will never change. But
357 * since the size is rather big. it is more efficient to spend some
358 * CPU on initiating it. The startup time might be decreased by swapping
359 * this routine for a pre-defined variable. Perhaps it should be
360 * rewritten to use two arrays, one for large pieces of memory and
361 * one for small pieces. That would save space in 'hash'
363 * The values put into the array has been described above.
364 * The function returns 1 on success, 0 if memory is short.
366 int init_memory( tsd_t *TSD )
368 mem_tsd_t *mt;
370 if (TSD->mem_tsd != NULL)
371 return(1);
373 if ( ( TSD->mem_tsd = TSD->MTMalloc( TSD, sizeof(mem_tsd_t) ) ) == NULL )
374 return(0);
375 mt = (mem_tsd_t *)TSD->mem_tsd;
376 memset( mt, 0, sizeof(mem_tsd_t) );
378 * Don't register this chunk of memory! It contains the list of all
379 * other blocks of memory to be freed!
381 #ifdef FLISTS
382 init_hash_table( mt ) ;
383 #endif
384 return(1);
387 #ifdef FLISTS
389 * This function initiates the variable 'hash'. This might have been
390 * done initially, since the values in this will never change. But
391 * since the size is rather big. it is more efficient to spend some
392 * CPU on initiating it. The startup time might be decreased by swapping
393 * this routine for a pre-defined variable. Perhaps it should be
394 * rewritten to use two arrays, one for large pieces of memory and
395 * one for small pieces. That would save space in 'hash'
397 * The values put into the array has been described above.
399 static void init_hash_table( mem_tsd_t *mt )
401 int indeks ; /* index into current element to be initiated */
402 int j ;
403 int size ;
404 int num ;
406 /* Force allocation of the first mem_ctl: */
407 mt->mem_ctl_idx = FLIST_ARRAY_SIZE ;
410 * Set the few lowest values manually, since the algoritm breaks
411 * down for sufficient small values.
413 indeks = 0 ;
414 mt->hash[indeks++] = 0 ; /* when size equals 0, well ... 8 :-) */
415 mt->hash[indeks++] = 0 ; /* for 1 <= size < 4 */
416 mt->hash[indeks++] = 0 ; /* for 4 <= size < 8 */
419 * The main loop. How does this algorithm work, well, look at the
420 * following table, in which all numbers should be multiplied with
421 * 4 to get the correct numbers.
423 * bin sizes
424 * 0 (8) : 2
425 * 1 (12) : 3
426 * 2 (16) : 4 5
427 * 3 (24) : 6 7
428 * 4 (32) : 8 9 10 11
429 * 5 (48) : 12 13 14 15
430 * 6 (64) : 16 17 18 19 20 21 22 23
431 * 7 (96) : 24 25 26 27 28 29 30 31
432 * 8 (128) : 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
433 * 9 (192) : 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
434 * etc
436 * The number to the left of the colon is the index into the
437 * 'sizes' array, and the number in parenthesis is the size which
438 * 'sizes' would return for that index. The numbers to the right of
439 * the colon are all the elements in 'hash' that contains that
440 * particular index into 'sizes'. Notice that pairs of lines have
441 * equal number of numbers, and that the number of numbers doubles
442 * for every second line.
444 * Therefore, let size be the number of elements to initialize in
445 * each iteration, and double it at the end of the loop. 'size'
446 * will then loop through 8, 16, 32, 64, 128 ... For each iteration
447 * of that loop, initialize 'size'/2 numbers to 'num' and then the
448 * next 'size'/2 numbers to 'num'+1. Increment 'num' by two for
449 * each iteration. The 'indeks' is the current number in hash to
450 * initialize.
452 size = 1 ;
453 num = 1 ;
454 for (; indeks<(CHUNK_SIZE/4); )
457 * Initalize first in each pair of bins of same length.
458 * I.e 8, 16, 32, 64 ... etc
460 for (j=0; j<size; j++ )
461 mt->hash[indeks++] = (short) num ;
462 num++ ;
465 * Initialize the second in each pair: 12, 24, 48, 96 ... etc
467 for (j=0; j<size; j++ )
468 mt->hash[indeks++] = (short) num ;
469 num++ ;
470 size = size << 1 ;
474 * Do I need this? I don't think so. It is a kludge to make something
475 * work on 64 bit machines, but I don't think it is needed anymore.
476 * Just let is be commented out, and the delete it if things seem
477 * to work.
480 /* We need to know if "int" or "int*" ar larger than 4 bytes. Since the
481 * sizeof operator is evaluated at compile time and we don't want to
482 * get a message "expression is constant" we use a more complex
483 * expression. We assume that there is no machine with an "int"-size
484 * of 2 and a pointer size of 8 or something else.
486 size = sizeof(int) ;
487 size += sizeof(int*) ;
488 if (size > 8)
489 mt->hash[3] = 2 ;
490 memset( mt->flists, 0, NUMBER_SIZES * sizeof(char *) );
493 * This function stores in a singly linked list all chunks of memory
494 * that are allocated with malloc(). This is so that they can all be
495 * free()ed by the_free_flists().
497 static int register_mem( const tsd_t *TSD, void *chunk )
499 meminfo *mem=NULL;
500 mem_tsd_t *mt=(mem_tsd_t *)TSD->mem_tsd;
502 if ( ( mem = (meminfo *)TSD->MTMalloc( TSD, sizeof(meminfo) ) ) == NULL )
503 return(1);
504 mem->start = (char *)chunk;
505 mem->next = NULL;
506 if (mt->curr_entry)
508 mt->curr_entry->next = mem;
510 mt->curr_entry = mem;
511 if (mt->first_entry == NULL)
512 mt->first_entry = mt->curr_entry;
514 #ifdef REGINA_DEBUG_MEMORY3
515 fprintf(stderr,"--register_mem(): added %x to malloced memory\n",chunk);
516 #endif
517 return(0);
523 * Adds information about a chunk of memory to the hashtable memory
524 * addresses and the chunksize at that address. Note that two addresses
525 * are sent as parameters, the start of the memory to be registerd, and
526 * the address under which the information is to be registered. Why?
527 * Look at the following figure:
529 * 0 8K 16K 24K
530 * +---------------+-----------------+------------------+-------------+
531 * | AAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBB
532 * +----+----------------+---+----------------+-------------------------+
533 * 3K 11K 13K 21K
535 * Two chunks are allocated: A and B. The chunks are allocated in 8K
536 * blocks, but they will in general not follow the 8K boundaries of
537 * the machine. The 'hashtable' array have entries that _do_ follow
538 * the 8K boundaries of the machine. Therefore, chunk A must be
539 * registered under the in the 'hashtable' entries for both the 0-8K
540 * segment, and the 8-16K segment. And vice versa, the 8-16K segment
541 * may contain parts of chunk A and B.
543 * This could be avoided, if the chunks were aligned with the boundaries
544 * of the computer. If you change any of the constants in this part of
545 * the program, be sure to tune them to match eachother!
547 * Of course, this routines need memory to be able to register other
548 * memory, so to avoid a deadlock, it calls malloc directly. It will
549 * never release memory, since we can really not be sure that all
550 * memory has been released.
552 static void add_entry( const tsd_t *TSD, char *start, const char *addr, int bin_no )
554 mem_tsd_t *mt = (mem_tsd_t *)TSD->mem_tsd;
555 meminfo *ptr ; /* work ptr */
556 int tmp ; /* tmp storage for mem_hash_func() */
559 * If we have used all free meminfo-boxes, allocate more. This is
560 * forces upon us at the first invocation. Allocate space for 128
561 * at a time.
563 if (mt->mem_ctl_idx>=FLIST_ARRAY_SIZE)
565 /* Stupid SunOS acc gives incorrect warning for the next line */
566 if ( ( mt->mem_ctl = (meminfo *)TSD->MTMalloc( TSD, sizeof( meminfo) * FLIST_ARRAY_SIZE ) ) == NULL )
567 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
568 mt->mem_ctl_idx = 0 ;
569 if ( register_mem( TSD, mt->mem_ctl ) )
570 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
574 * Fill in the fields of the box, and put it in the front of the
575 * requested bin in hashtable
577 ptr = &mt->mem_ctl[ mt->mem_ctl_idx++ ] ;
578 ptr->next = mt->hashtable[tmp=mem_hash_func((unsigned long)addr)] ;
579 ptr->size = bin_no ;
580 ptr->start = start ;
581 mt->hashtable[tmp] = ptr ;
586 * Allocate a piece of memory. The size is given as the 'size' parameter.
587 * If size is more than MAX_INTERNAL_SIZE, it will call malloc()
588 * directly, else, it will return a piece of memory from the freelist,
589 * after possibly filling the freelist with more memory if is was
590 * empty in the first place.
592 void *get_a_chunk( int size )
594 return get_a_chunkTSD(__regina_get_tsd(), size) ;
597 void *get_a_chunkTSD( const tsd_t *TSD, int size )
599 int bin ; /* bin no in array of freelists */
600 char *vptr ; /* holds the result */
601 void *result ;
602 mem_tsd_t *mt;
603 char *ptr ; /* work ptr, to loop through the memory */
604 char *topaddr ; /* points to last item in memory */
605 #ifdef REGINA_DEBUG_MEMORY
606 int before, after;
607 #endif
609 #ifdef REGINA_DEBUG_MEMORY1
610 fprintf(stderr,"get_a_chunkTSD(): want %d bytes...",size);
611 #endif
613 mt = (mem_tsd_t *)TSD->mem_tsd;
616 * If memory is too big, let malloc() handle the problem.
618 if (size>MAX_INTERNAL_SIZE)
620 if ((result=TSD->MTMalloc( TSD, size )) != NULL)
622 #ifdef REGINA_DEBUG_MEMORY1
623 fprintf(stderr,"got %d at %x (after allocating with malloc)\n",size,result);
624 #endif
626 * removing this fixes memory leak in 908114 - MHES 08-March-2004
627 if ( register_mem( TSD, result ) )
628 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
630 return result ;
632 else
633 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
637 * Get the first item from the appropriate freelist, and let 'vptr'
638 * point to it. Simultaneously set bin to the bin no in 'flists'
639 * to avoid recalculating the number. If the freelist is empty
640 * (i.e vptr==NULL) then allocate more memory.
642 if ((vptr=mt->flists[bin=GET_SIZE(mt,size)])==NULL)
645 * Allocate the memory, and set both vptr and initiate the
646 * right element in 'flists'. Note that the value in 'flists' is
647 * 'incremented' later, so it must be set to the value which now
648 * is to be allocated.
650 vptr = (char *)TSD->MTMalloc( TSD, CHUNK_SIZE ) ;
651 if (!vptr)
652 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
654 #ifdef REGINA_DEBUG_MEMORY1
655 fprintf(stderr,"got %d at %x in bin %d (after allocating %d bytes)\n",sizes[bin],vptr,bin,CHUNK_SIZE);
656 #endif
657 if ( register_mem( TSD, vptr ) )
658 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
659 mt->flists[bin] = vptr ;
660 #ifdef REGINA_DEBUG_MEMORY3
661 memset( vptr, 0xC0+bin, CHUNK_SIZE );
662 #endif
665 * Calculate the top address of the memory allocated, and put
666 * the memory into 'topaddr'. Then register the chunk of memory
667 * in both the possible CHUNK_SIZE segments of the machine. In
668 * some rare cases the last registration might not be needed,
669 * but do it anyway, to avoid having to determine it.
671 topaddr = vptr + CHUNK_SIZE - sizes[bin] ;
672 add_entry( TSD, vptr, vptr, bin ) ;
673 add_entry( TSD, vptr, vptr + CHUNK_SIZE, bin ) ;
676 * Then loop through the individual pieced of memory within the
677 * newly allocated chunk, and make it a linked list, where the
678 * last ptr in the list is NULL.
680 for (ptr=vptr; ptr<topaddr; ptr=ptr+sizes[bin] )
681 *(char**)ptr = ptr + sizes[bin] ;
683 *((char**)(ptr-sizes[bin])) = NULL ;
685 #ifdef REGINA_DEBUG_MEMORY
686 show_a_free_list( mt, bin, "get_a_chunkTSD(): empty freelist for ");
687 #endif
689 #ifdef REGINA_DEBUG_MEMORY1
690 else
692 fprintf(stderr,"got %d at %x in bin %d\n",sizes[bin],vptr,bin);
694 #endif
697 * Update the pointer in 'flist' to point to the next entry in the
698 * freelist instead of the one we just allocated, and return to
699 * caller.
701 #ifdef REGINA_DEBUG_MEMORY2
702 before = show_a_free_list( mt, bin, NULL);
703 #endif
704 mt->flists[bin] = (*((char**)(vptr))) ;
705 #ifdef REGINA_DEBUG_MEMORY2
706 after = show_a_free_list( mt, bin, NULL );
707 if ( before - 1 != after )
708 fprintf(stderr,"****** get_a_chunkTSD() for bin [%d] failed. Before %d After %d\n",bin,before,after);
709 #endif
710 return (vptr) ;
714 streng *get_a_streng( int size )
716 return get_a_strengTSD(__regina_get_tsd(), size) ;
719 streng *get_a_strengTSD( const tsd_t *TSD, int size )
721 register int bin ; /* bin no in array of freelists */
722 register char *vptr ; /* holds the result */
723 register streng *result ;
724 mem_tsd_t *mt;
725 char *ptr ; /* work ptr, to loop through the memory */
726 char *topaddr ; /* points to last item in memory */
727 #ifdef REGINA_DEBUG_MEMORY
728 int before, after;
729 #endif
731 size = size + STRHEAD;
734 * If memory is too big, let malloc() handle the problem.
736 #ifdef REGINA_DEBUG_MEMORY1
737 fprintf(stderr,"get_a_strengTSD(): want %d bytes...",size-STRHEAD);
738 #endif
739 if (size>MAX_INTERNAL_SIZE)
741 if ( ( result = (streng *)TSD->MTMalloc( TSD, size ) ) != NULL )
743 result->len = 0 ;
744 result->max = size-STRHEAD ;
746 * removing this fixes memory leak in 908114 - MHES 08-Mark-2004
747 if ( register_mem( TSD, result ) )
748 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
750 return result ;
752 else
753 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
756 mt = (mem_tsd_t *)TSD->mem_tsd;
759 * Get the first item from the appropriate freelist, and let 'vptr'
760 * point to it. Simultaneously set bin to the bin no in 'flists'
761 * to avoid recalculating the number. If the freelist is empty
762 * (i.e vptr==NULL) then allocate more memory.
764 if ((vptr=mt->flists[bin=GET_SIZE(mt,size)])==NULL)
767 * Allocate the memory, and set both vptr and initiate the
768 * right element in 'flists'. Note that the value in 'flists' is
769 * 'incremented' later, so it must be set to the value which now
770 * is to be allocated.
772 vptr = (char *)TSD->MTMalloc( TSD, CHUNK_SIZE ) ;
773 if (!vptr)
774 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
775 if ( register_mem( TSD, vptr ) )
776 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
777 mt->flists[bin] = vptr ;
778 #ifdef REGINA_DEBUG_MEMORY3
779 memset( vptr, 0xA0+bin, CHUNK_SIZE );
780 #endif
783 * Calculate the top address of the memory allocated, and put
784 * the memory into 'topaddr'. Then register the chunk of memory
785 * in both the possible CHUNK_SIZE segments of the machine. In
786 * some rare cases the last registration might not be needed,
787 * but do it anyway, to avoid having to determine it.
789 topaddr = vptr + CHUNK_SIZE - sizes[bin] ;
790 add_entry( TSD, vptr, vptr, bin ) ;
791 add_entry( TSD, vptr, vptr + CHUNK_SIZE, bin ) ;
794 * Then loop through the individual pieced of memory within the
795 * newly allocated chunk, and make it a linked list, where the
796 * last ptr in the list is NULL.
798 for (ptr=vptr; ptr<topaddr; ptr=ptr+sizes[bin] )
799 *(char**)ptr = ptr + sizes[bin] ;
801 *((char**)(ptr-sizes[bin])) = NULL ;
802 #ifdef REGINA_DEBUG_MEMORY1
803 fprintf(stderr,"got %d at %x (after allocating %d bytes)\n",sizes[bin],vptr,CHUNK_SIZE);
804 #endif
806 #ifdef REGINA_DEBUG_MEMORY
807 show_a_free_list( mt, bin, "get_a_strengTSD(): empty freelist for ");
808 #endif
810 #ifdef REGINA_DEBUG_MEMORY1
811 else
813 fprintf(stderr,"got %d at %x\n",sizes[bin],vptr);
815 #endif
818 * Update the pointer in 'flist' to point to the next entry in the
819 * freelist instead of the one we just allocated, and return to
820 * caller.
822 #ifdef REGINA_DEBUG_MEMORY2
823 before = show_a_free_list( mt, bin, NULL );
824 #endif
825 mt->flists[bin] = (*((char**)(vptr))) ;
826 ((streng *)vptr)->len = 0 ;
827 ((streng *)vptr)->max = size-STRHEAD ;
828 #ifdef REGINA_DEBUG_MEMORY2
829 after = show_a_free_list( mt, bin, NULL );
830 if ( before - 1 != after )
831 fprintf(stderr,"****** get_a_strengTSD() for bin [%d] failed. Before %d After %d\n",bin,before,after);
832 #endif
834 return ((streng *)vptr) ;
838 * Shortcut to deallocate a streng. Since we know the max size of a
839 * streng, we don't really need to calculate the size using of the
840 * hashtable structure. That saves some time, since a lot of the
841 * memorychunks in rexx are strengs.
843 * Note that strengs can just as well be deallocated using the
844 * 'normal' method, but this interface saves some time. Just a thought:
845 * if all allocated string were sure to have a max size that did not
846 * waste any memory, we didn't have to expand the GET_SIZE macro,
847 * and thereby saving even a few more cycles
849 void give_a_streng( streng *ptr )
851 give_a_strengTSD(__regina_get_tsd(), ptr) ;
854 void give_a_strengTSD( const tsd_t *TSD, streng *ptr )
856 char **tptr ; /* tmp variable, points to element in flists */
857 mem_tsd_t *mt;
858 register int bin;
859 #ifdef REGINA_DEBUG_MEMORY
860 int before, after;
861 #endif
863 #ifdef REGINA_DEBUG_MEMORY1
864 fprintf(stderr,"give_a_strengTSD() going to free %x...", ptr );
865 #endif
866 assert( ptr->len <= ptr->max ) ;
867 if ((ptr->max+STRHEAD) > MAX_INTERNAL_SIZE) /* off-by-one error ? */
869 TSD->MTFree(TSD, ptr ) ;
870 #ifdef REGINA_DEBUG_MEMORY1
871 fprintf(stderr,"freed by MTFree()\n" );
872 #endif
873 return ;
876 mt = (mem_tsd_t *)TSD->mem_tsd;
879 * First find the right element in flists, then link this piece
880 * of memory into the start of the list, clean and simple. 'tptr'
881 * is the old first element in the freelist, and 'ptr' is the
882 * memory to free.
884 bin = GET_SIZE(mt,ptr->max + STRHEAD);
885 #ifdef REGINA_DEBUG_MEMORY1
886 fprintf(stderr,"freed from bin%d\n",bin );
887 #endif
888 #ifdef REGINA_DEBUG_MEMORY2
889 before = show_a_free_list( mt, bin, NULL );
890 #endif
891 tptr = &mt->flists[bin] ;
892 *((char**)ptr) = *tptr ;
893 *tptr = (char*)ptr ;
894 #ifdef REGINA_DEBUG_MEMORY2
895 after = show_a_free_list( mt, bin, NULL );
896 if ( before + 1 != after )
897 fprintf(stderr,"****** give_a_strengTSD() for bin [%d] failed. Before %d After %d\n",bin,before,after);
898 #endif
902 * The standard interface to freeing memory. The parameter 'ptr' is
903 * a pointer to the memory to be freed, is put first in the freelist
904 * pointed to by the appropriate element in 'flists'.
906 * I am not really sure what cptr do in this, but I think it has
907 * something to do with *void != *char on Crays ... The main consumer
908 * of CPU in this routine is the for(;;) loop, it should be rewritten.
910 void give_a_chunk( void *ptr )
912 give_a_chunkTSD(__regina_get_tsd(), ptr) ;
915 void give_a_chunkTSD( const tsd_t *TSD, void *ptr )
917 char *cptr ; /* pseudonym for 'ptr' */
918 meminfo *mptr ; /* caches the right element in hashtable */
919 mem_tsd_t *mt;
920 #ifdef REGINA_DEBUG_MEMORY
921 int before, after;
922 #endif
924 mt = (mem_tsd_t *)TSD->mem_tsd;
926 * initialize a few values, 'cptr' is easy, while 'mptr' is the
927 * list of values for this piece of memory, that is in the
928 * hashtable that returns memory size given a specific address
930 cptr = (char*)ptr ;
931 mptr = mt->hashtable[ mem_hash_func( ((unsigned long)cptr) ) ] ;
932 #ifdef REGINA_DEBUG_MEMORY1
933 fprintf(stderr,"give_a_chunkTSD() going to free %x hashtable %d...", ptr, mem_hash_func( ((unsigned int)cptr) ) );
934 #endif
937 * For each element in the list attached to the specific hashvalue,
938 * loop through the list, and stop at the entry which has a start
939 * address _less_ than 'cptr' and a stop address _higher_ than
940 * 'cptr' (i.e. cptr is within the chunk.)
942 for ( ; (mptr) && ((mptr->start+CHUNK_SIZE<=cptr) || (mptr->start>cptr)); mptr = mptr->next) ;
945 * Now, there are two possibilities, either is mptr==NULL, in which
946 * case this piece of memory is never registered in the system, or
947 * then we have more information. In the former case, just give
948 * the address to free(), hoping it knows more. In the latter, put
949 * the memory on the appropriate freelist.
951 if (mptr)
953 #ifdef REGINA_DEBUG_MEMORY1
954 fprintf(stderr,"freed from bin %d\n", mptr->size );
955 #endif
957 * Link it into the first place of the freelist.
959 #ifdef REGINA_DEBUG_MEMORY2
960 before = show_a_free_list( mt, mptr->size, NULL );
961 #endif
962 *((char**)cptr) = mt->flists[mptr->size] ;
963 mt->flists[mptr->size] = cptr ;
964 #ifdef REGINA_DEBUG_MEMORY2
965 after = show_a_free_list( mt, mptr->size, NULL );
966 if ( before + 1 != after )
967 fprintf(stderr,"****** give_a_chunkTSD() for bin [%d] failed. Before %d After %d\n",mptr->size,before,after);
968 #endif
970 else
972 #ifdef REGINA_DEBUG_MEMORY1
973 fprintf(stderr,"freed from MTFree()\n" );
974 #endif
975 TSD->MTFree(TSD, ptr ) ;
980 * This function frees up all memory allocated by the flists internal
981 * meomory management routines
983 void purge_flists( const tsd_t *TSD )
985 meminfo *ptr;
986 meminfo *next;
987 mem_tsd_t *mt;
989 mt = (mem_tsd_t *)TSD->mem_tsd;
990 ptr = mt->first_entry;
992 while( ptr )
994 next = ptr->next;
995 TSD->MTFree(TSD, ptr ) ;
996 ptr = next;
998 mt->first_entry = mt->curr_entry = NULL;
999 return;
1002 # ifdef REGINA_DEBUG_MEMORY
1003 static int show_a_free_list(mem_tsd_t *mt, int bin, char *str)
1005 char *ptr;
1006 int j=0;
1008 if ( mt->flists[bin] == NULL )
1010 if (str)
1011 fprintf(stderr,"%sbin[%d] Free List unallocated Maximum %d Size: %d\n",str,bin,(CHUNK_SIZE / sizes[bin]),sizes[bin]);
1013 else
1015 for (j=1,ptr=mt->flists[bin]; *(char**)ptr!=NULL && j<5000; ptr=*(char **)ptr,j++ )
1019 if (str)
1020 fprintf(stderr,"%sbin[%d] Number in Free List %d Maximum %d Size: %d\n",str,bin,j,(CHUNK_SIZE / sizes[bin]), sizes[bin]);
1022 return j;
1025 int show_free_lists(const tsd_t *TSD)
1027 int num_bins = sizeof(sizes)/sizeof(sizes[0]);
1028 int i;
1029 mem_tsd_t *mt;
1031 mt = (mem_tsd_t *)TSD->mem_tsd;
1032 for ( i = 0; i < num_bins; i++ )
1034 show_a_free_list( mt, i, "" );
1036 return 0;
1038 # endif /* REGINA_DEBUG_MEMORY */
1040 #endif /* FLISTS */
1042 #ifdef TRACEMEM
1044 * Strings used to mark chunks of memory when listing dynamically
1045 * allocated memory in listleaked(). Length is max 8 chars.
1047 * NOTE: There is a close correspondace between these and the cpp
1048 * variables TRC_* in defs.h. If you change one of them, please
1049 * change the other too.
1051 static const char *allocs[] = {
1052 "leaked", /* status unknown, probably leaked */
1053 "hashtab", /* holds hashtable in variable subsystem */
1054 "procbox", /* the info local to a single routine */
1055 "source", /* a line of source code */
1056 "srcbox", /* box in list of source lines */
1057 "treenode", /* node in the parse three */
1058 "var_val", /* value of a variable */
1059 "var_nam", /* name of a variable */
1060 "var_box", /* other structure in the variable subsystem */
1061 "stc_box", /* box in linked list of the stack lines */
1062 "stc_line", /* stack line */
1063 "sys_info", /* the common info for a whole program */
1064 "file_ptr", /* holds the filetable */
1065 "proc_arg", /* holds arguments for internal or builtin functions */
1066 "label", /* holds info about labels */
1067 "static", /* names of special variables */
1068 "argcache", /* the proc argument cache */
1069 "math", /* dynamic workarrays in the math funcstion */
1070 "envirbx", /* box holding environment definition */
1071 "envirnm", /* name in a box holding environment definition */
1072 "spcvarbx", /* special variable box */
1073 "spcvarnm", /* special variable name */
1074 "spcnumbx", /* special number box */
1075 "spcnumnm", /* special number contents */
1076 NULL /* terminator */
1081 * This routine obtains memory, either through get_a_chunk, or through
1082 * malloc() if we are not running with freelists. The memory requested
1083 * will be increased with the size of a memhead structure (32 bytes on
1084 * 'normal' 32 bit machines).
1086 * The function also updates the statistics, linkes it into the list
1087 * of currently allocated memory, and might pattern the memory.
1089 void *mymalloc( int bytes )
1091 return mymallocTSD(__regina_get_tsd(), bytes) ;
1094 void *mymallocTSD( const tsd_t *TSD, int bytes )
1096 struct memhead *memptr ; /* holds the result */
1097 mem_tsd_t *mt;
1099 mt = (mem_tsd_t *)TSD->mem_tsd;
1102 * Increase the size of the memory wanted, so we can put the
1103 * header into it first. You'd better not have played with the
1104 * parameters above in such a way that the result is non-aligned.
1106 mt->allocated += (bytes += sizeof(struct memhead) ) ;
1109 * Do the actual allocation of memory, either call get_a_chunk()
1110 * or be boring and call plain old malloc(). In either case,
1111 * chicken out if there are not any more memory left. Hmmm, this
1112 * situation should be handled better. Memory management should
1113 * be transaction oriented
1115 #ifdef FLISTS
1116 if ((memptr=get_a_chunkTSD(TSD,bytes)) == NULL)
1117 #else
1118 if ((memptr = (struct memhead *) TSD->MTMalloc(TSD,bytes)) == NULL)
1119 #endif
1120 exiterror( ERR_STORAGE_EXHAUSTED, 0 ) ;
1122 #ifdef PATTERN_MEMORY
1124 * If the options for memory patterning is set, perform it. This is
1125 * only useful during debugging, to provoke error due to the use of
1126 * uninitialized variables. Other than that, it is just a pure waste
1127 * of CPU.
1129 memset( memptr, NOT_USED, bytes ) ;
1130 #endif /* PATTERN_MEMORY */
1133 * Fill in the fields of the header: the size, the sequence number,
1134 * the magic number, initialize the flag, and then link it into the
1135 * linked list of allocated memory, at the start of the list.
1137 memptr->count = bytes ;
1138 memptr->flag = 0 ;
1139 memptr->magic = MAGIC_COOKIE ;
1140 memptr->seqv = (unsigned short) ++mt->sequence ;
1141 memptr->prev = NULL ;
1142 #ifdef HAVE_BUILTIN_RETURN_ADDRESS
1144 void *p;
1146 p = __builtin_return_address(0);
1148 if ( ( (unsigned long) p >= (unsigned long) __regina_Str_first ) &&
1149 ( (unsigned long) p <= (unsigned long) __regina_Str_last ) )
1151 p = __builtin_return_address(1);
1153 if ( ( (unsigned long) p >= (unsigned long) __regina_Str_first ) &&
1154 ( (unsigned long) p <= (unsigned long) __regina_Str_last ) )
1156 p = __builtin_return_address(2);
1158 if ( ( (unsigned long) p >= (unsigned long) __regina_Str_first ) &&
1159 ( (unsigned long) p <= (unsigned long) __regina_Str_last ) )
1161 p = __builtin_return_address(3);
1166 memptr->addr = p;
1168 #else
1169 memptr->addr = NULL;
1170 #endif
1171 memptr->next = mt->header0 ;
1172 if (mt->header0)
1173 mt->header0->prev = memptr ;
1176 * Increment the pointer to the start of the memory that the user
1177 * is allowed to use, i.e past the header. The return.
1179 mt->header0 = memptr++ ;
1180 return memptr ;
1186 * myfree takes a pointer to memory to be deallocated, it is a wrapper
1187 * for free(3), and does some housekeeping tasks
1189 void myfree( void *cptr )
1191 myfreeTSD(__regina_get_tsd(), cptr) ;
1194 void myfreeTSD( const tsd_t *TSD, void *cptr )
1196 struct memhead *memptr ; /* ptr to memory to be freed */
1197 mem_tsd_t *mt;
1199 mt = (mem_tsd_t *)TSD->mem_tsd;
1201 * The header part of the memory is prepended to the part of the
1202 * memory that the user saw, so move the pointer backwards to the
1203 * start of the header.
1205 memptr = ((struct memhead *)cptr) - 1 ;
1208 * If the magic cookie is not intact, there must be some serious
1209 * problems somewhere. Inform the user about it, and exit.
1211 if (memptr->magic != MAGIC_COOKIE)
1212 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1215 * Update the statistics. Remember that we do not decrement the
1216 * variable 'allocated'. The real number of memory allocated is
1217 * the difference between those two.
1219 mt->deallocated -= memptr->count ;
1222 * Then unlink the chunk of memory from the linked list of allocated
1223 * memory. Set the pointers at its neighbors (if any) and set the
1224 * 'header' variable if it was first in the list.
1226 if (memptr->next)
1227 memptr->next->prev = memptr->prev ;
1229 if (memptr->prev)
1230 memptr->prev->next = memptr->next ;
1231 else
1232 mt->header0 = memptr->next ;
1234 #ifdef PATTERN_MEMORY
1236 * If we are to pattern the memory, overwrite the contents of the
1237 * memory, to provoke errors if parts of the interpreter use
1238 * memory after it have been deallocated.
1240 memset( memptr, BEEN_USED, memptr->count ) ;
1241 #endif
1244 * Then at last, deallocate the memory, either by giving it to
1245 * give_a_chunk (to be stored in the freelists) or by giving it
1246 * it directly to free().
1248 #ifdef FLISTS
1249 give_a_chunkTSD(TSD,memptr) ;
1250 #else
1251 TSD->MTFree(TSD,memptr) ;
1252 #endif
1257 /* have_allocated returns the amount of dynamic memory that has been
1258 * allocated, in bytes.
1260 int have_allocated( tsd_t *TSD, int flag )
1262 int result = -1 ;
1263 mem_tsd_t *mt;
1265 mt = (mem_tsd_t *)TSD->mem_tsd;
1266 switch ( flag )
1268 case ( MEM_CURRENT ) :
1269 result = mt->allocated - mt->deallocated ;
1270 break ;
1272 case ( MEM_ALLOC ) :
1273 result = mt->allocated - mt->deallocated - listleaked( TSD, MEMTRC_NONE ) ;
1274 break ;
1276 case ( MEM_LEAKED ) :
1277 result = listleaked( TSD, MEMTRC_NONE ) ;
1278 break ;
1280 default :
1281 exiterror( ERR_INCORRECT_CALL, 0 ) ;
1284 return result ;
1288 void regmarker( const tsd_t *TSD, void (*marker)(const tsd_t *TSD) )
1290 mem_tsd_t *mt;
1292 mt = (mem_tsd_t *)TSD->mem_tsd;
1294 if (mt->max_markers_regd>=MAX_MARKERS)
1295 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1297 mt->markers[mt->max_markers_regd++] = marker ;
1301 * This routine will three distinct things. First it iterates through
1302 * all the memory currently allocated and mark them as leaked. Then
1303 * it calls in sequence all the routines that mark the memory that the
1304 * various parts of the system claims. The pieces of memory that is
1305 * still marked leaked are then unclaimed. At last it iterates
1306 * through the list of memory once more, and dumps info about those
1307 * that are unclaimed by any part of the interpreter.
1309 * The parameter 'pflag' may have a value which is defined by the
1310 * macros MEMTRC_ in defs.h. These may be MEMTRC_NONE to not write out
1311 * anything; MEMTRC_ALL to list all memory; or MEMTRC_LEAKED which
1312 * only writes out the memory that is actually leaked.
1314 int listleaked( const tsd_t *TSD, int pflag )
1317 * Array of functions to call for marking all active chunks of dynamic
1318 * allocated memory. These will mark _all_ dynamically allocated
1319 * memory. Anything unmarked after all these routines are called,
1320 * must be leaked memory. Add more functions as you wish
1322 static void (* const fptr[])( const tsd_t *TSD ) = {
1323 mark_stack, /* the lines on the stack */
1324 mark_systeminfo, /* the system information box */
1325 mark_filetable, /* the file descriptor table */
1326 mark_param_cache, /* the parameter chache */
1327 mark_descrs, /* memory used by sting math routines */
1328 mark_signals, /* */
1329 NULL /* terminator */
1331 struct memhead *memptr ; /* ptr that iterates through the memory */
1332 int i ; /* general loop control variable */
1333 int sum ; /* the sum of allocated memory */
1334 char *string ; /* ptr to the current allocated memory */
1335 mem_tsd_t *mt;
1337 mt = (mem_tsd_t *)TSD->mem_tsd;
1339 * First, set the status of all pieces of memory to leaked.
1341 for (memptr=mt->header0; memptr; memptr=memptr->next)
1342 memptr->flag = TRC_LEAKED ;
1345 * Then, call the functions that claims the memory that belongs to
1346 * the various parts of the system. These routines are stored in the
1347 * array 'fptr'. If you ever write anything that uses more memory,
1348 * be sure to add a function that is able to mark it, and append the
1349 * name of that function to 'fptr'. If you don't, and garbage
1350 * collection is implemented, you are in deep trouble.
1352 * Note the mark_listleaked_params(), that is special, since it marks
1353 * the parameters that the is in use by during the calling of the
1354 * builtin function that invokes this function.
1356 mark_listleaked_params( TSD ) ;
1357 for (i=0;fptr[i];i++)
1358 (*(fptr[i]))( TSD ) ;
1360 for (i=0; i<mt->max_markers_regd; i++)
1361 (*(mt->markers[i]))( TSD ) ;
1364 * Write out a header for the output, but only if we actually are to
1365 * trace the values.
1367 if (! pflag==MEMTRC_NONE && TSD->stddump != NULL)
1368 fprintf(TSD->stddump," Len Flg Tag Seqv Address Caller Contents\n") ;
1371 * Then, loop through the allocated memory, and for each piece of
1372 * memory in the linked list, check to see if it is leaked. If we
1373 * were called with the MEMTRC_ALL flag, then list out for every
1374 * piece of memory.
1376 for (sum=0,memptr=mt->header0; memptr; memptr=memptr->next)
1378 if ((memptr->flag==TRC_LEAKED)||(pflag==MEMTRC_ALL))
1381 * Keep an account on how much memory is actually in use. If
1382 * we are not to write anything out, skip the rest of this
1383 * iteration.
1385 sum += memptr->count ;
1386 if (!(pflag==MEMTRC_NONE))
1389 * Dump info about the current piece of memory. That includes
1390 * the size (excl the header), the flag and the string
1391 * belonging to the flag, and then the sequence number.
1393 if (TSD->stddump != NULL)
1394 fprintf(TSD->stddump, "%5d %3d %-8s %4X %-10p %-10p \"",
1395 memptr->count - sizeof(struct memhead),
1396 memptr->flag, allocs[memptr->flag], memptr->seqv,
1397 memptr, memptr->addr );
1400 * Dump the contents of the piece of memory. One piece of
1401 * memory per line in the output.
1403 string = (char*)(memptr+1) ;
1404 if (TSD->stddump != NULL)
1405 for (i=0; i<(int)(memptr->count - sizeof(struct memhead)); i++ )
1407 if (i==40) /* bja 20->40 */
1410 * If it is more than 40 bytes long, terminate and write - bja 20->40
1411 * out "..." to indicate that there are more bytes in
1412 * the memory than was possible to write out.
1414 fprintf(TSD->stddump, " ..." ) ;
1415 break ;
1418 * Write out a byte. If it is not a printable character,
1419 * write out a "." instead, to indicate this.
1421 if ( rx_isprint( string[i] ) )
1422 putc( string[i], TSD->stddump ) ;
1423 else
1424 putc( '~', TSD->stddump ) ;
1426 if (TSD->stddump != NULL)
1427 fprintf( TSD->stddump, "\"\n" ) ;
1431 return sum ;
1436 * Marks a chunk of memory pointed to by 'ptr' to be of the kind
1437 * referenced in 'flag'. Might be defined as a macro, but since memory
1438 * garbagecollection is just for debugging purposes, there is really
1439 * no need to worry about that now.
1441 void markmemory( void *ptr, int flag )
1443 struct memhead *memptr ; /* work pointer to memory to be marked */
1446 * It's rather simple, ptr is non-NULL, decrement the memptr pointer
1447 * to the start of the header, and set the flag. I am not sure
1448 * whether an internal error should be given if 'ptr' is NULL.
1449 * Maybe lots of code could be extracted from other parts of the
1450 * interpreter if they don't have to worry about not sending NULL
1451 * pointer to markmemory()?
1453 * That is hardly a problem now, since this is only used for debugging.
1454 * The only confusing part of this routine might be the casting.
1456 if ((memptr=((struct memhead *)ptr)) != NULL)
1458 memptr-- ;
1459 memptr->flag = (unsigned char) flag ;
1461 else
1462 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1467 * This is really a simple routine, to write out the values of some
1468 * of the statistics gathered during (de)allocation of memory. Maybe it
1469 * should return the answer instead?
1471 void memory_stats(const tsd_t *TSD)
1473 mem_tsd_t *mt;
1475 mt = (mem_tsd_t *)TSD->mem_tsd;
1476 if (TSD->stddump == NULL)
1477 return;
1478 fprintf(TSD->stddump,
1479 "Allocated %d bytes in %d chunks, of which %d is deallocated\n",
1480 mt->allocated, mt->sequence, mt->deallocated ) ; /* bja - variables out of order */
1483 #endif /* TRACEMEM */
1485 #ifdef CHECK_MEMORY
1486 # if defined(TRACEMEM) || defined(FLISTS)
1487 # error CHECK_MEMORY should only be defined if FLISTS and TRACEMEM are not defined. Please, check the header files.
1488 # endif
1490 void give_a_streng( streng *ptr )
1492 give_a_strengTSD( __regina_get_tsd(), ptr ) ;
1495 void give_a_strengTSD( const tsd_t *TSD, streng *ptr )
1498 * The assert is not really needed if we check for ptr!=NULL for the
1499 * free(ptr->value). Note, that free(NULL) is allowed in ANSI. But we will
1500 * check for error free code in case of !defined(CHECK_MEMORY), thus, we
1501 * assert the freeing. FGC
1503 assert((ptr != NULL) && (ptr->value != NULL));
1504 TSD->MTFree(TSD,ptr->value);
1505 TSD->MTFree(TSD,ptr);
1508 #endif /* CHECK_MEMORY */