2 static char *RCSid
= "$Id$";
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library 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 GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 * The routines in this file try to minimize the the number of calls
26 * to malloc() and free(). Since it would generally not be possible to
27 * release memory, unless it actually is last in the virtual memory
28 * that the process holds, just don't release it, and let the
29 * interpreter grow. Memory are allocated in only certain sizes, and
30 * are "freed" to a freelist, which is within the interpreter.
32 * The important routines are get_a_chunk() and give_a_chunk(), which
33 * might be called a large number of times. All the other routines are
34 * either called once to initiate, or it is used in tracing and
35 * debugging, where speed and space is not important anyway.
37 * The algorithm works something like this: memory can only be allocated
38 * in predetermined sizes (8, 12, 16, 24, 32, ...) and allocation of a
39 * size other than that will have to allocate something slightly bigger.
40 * For each size, there is a linked list of free pieces of memory of
41 * that size, the first entry of each of these lists can be accessed
42 * through 'flists', which is an array of pointers to these lists.
44 * Every time someone needs a piece of memory, the first piece of the
45 * freelist containing memory of suitable size (as big or slightly
46 * bigger) is returned. If the list is empty, a large piece of
47 * memory is allocated by malloc(), chopped up and put on the freelist
50 * When memory is released, the prime problem is to decide which
51 * freelist to put it on. To manage that, each time memory is
52 * allocated by malloc(), the upper and lower address of the memory
53 * is put in hashtable; given a particular address, the hashtable
54 * can be sought using the address as hashvalue, and the result will
55 * be the size of the memory chunks at that address.
57 * When dealloacting strings, we know the max-size of the string, and
58 * then we can calculate which freelist the string should be put on,
59 * without having to search the hashtable structure. Note that there
60 * is no need to deallocate strings using the give_a_string() function,
61 * the normal give_a_chunk() will work just as well, but is somewhat
64 * If you don't #define FLISTS, then malloc() and free() should be
65 * used instead. That might be very slow on some machines, since rexx
66 * tend to use lots of small size memory. If you #define TRACEMEM,
67 * memory is traced, which also tend to be slow, since there is a lot
68 * of overhead in allocation and deallocation. Also note that in the
69 * current implementation you can use malloc()/free() in parallel with
70 * the routines defined here.
72 * Note that using this metod, the last piece of memory freed will be
73 * the first to be used when more memory is needed.
75 * The number of calls to malloc() seems to be negligable when using
76 * this metod (typical less than 100 for medium sized programs). But
77 * this is of course dependent on how the program uses memory.
79 * The tracing part of this file, (#ifdef TRACEMEM) is an optional
80 * extention for debugging purposes. Whenever memory is allocated,
81 * mymalloc() allocates 16 bytes more than needed. These bytes are
85 * | count |f|m|seq| prev | next | start of allocated memory
87 * The 'count' is the number of bytes allocated, 'f' (flag) is used in
88 * garbage collection, and 'prev' and 'next' are pointers used in a
89 * double linked list. seqv is a sequence number which is iterated
90 * for each memoryallocation.
92 * count is int, prev and next are char*, f is char and seqv is a
93 * 16 bit integer. The 'm' is a magic number. Actually it is just
94 * there to fill the space, and can be used for more useful purposed
97 * An additional option to TRACEMEM is filling allocated and deallocated
98 * memory with bitpatterns. If the PATTERN_MEMORY cpp-variable is set,
99 * all allocated memory is initated to NOT_USED, and deallocated memory
100 * is set BEEN_USED before deallocation.
102 * Garbage-collection is not implemented, but listleaked will list out
103 * every chunk of allocated memory that are not currently in use. The
104 * array markptrs contains a list of functions for marking memory.
105 * There is a potensial problem with garbage collection, since the
106 * interpreter might 'loose' some memory everytime it hits a syntax
107 * error, like "say random(.5)". To fix that, memory should either
108 * be traced and then garbage collected, or it should have a sort
109 * of transaction oriented memory management (yuk!).
111 * NOTE that #define'ing TRACEMEM requires that your machine follows
112 * this: sizeof(int) = sizeof(char*) = 32 bits. It might work
113 * for other machines to (having larger word size), but I don't
126 * If we are tracing memory, each piece of allocated memory gets the
127 * following header prepended, which are used to keep track of that
130 typedef struct memhead
132 int count
; /* Size of this piece of memeory */
133 struct memhead
*prev
, *next
; /* Ptrs in double linked list */
134 unsigned short seqv
; /* Sequential counter */
135 unsigned char flag
; /* What is this memory used for */
136 unsigned char magic
; /* Not really used */
139 # ifdef PATTERN_MEMORY
141 * The two byte values NOT_USED and BEEN_USED are patterns which newly
142 * allocated dynamic memory will be set to, and memory to be freed
143 * will be set to, respectively. This is done to provoke problems if
144 * memory is used but not initialized, or if it used after is has
148 # define NOT_USED (0x42) /* letter 'B' */
149 # define BEEN_USED (0x69) /* letter 'i' */
152 * The magic cookie is just a placeholder, it is checked for consistency
153 * but could easily be used for something else, if the space is needed.
155 # define MAGIC_COOKIE (0xd4)
157 # endif /* PATTERN_MEMORY */
158 #endif /* TRACEMEM */
163 * CHUNK_SIZE it the size in which memory is allocated using malloc(),
164 * and that memory is then divided into pieces of the wanted size.
165 * If you increase it, things will work slightly faster, but more
166 * memory is wasted, and vice versa. The 'right' size is dependent on
167 * your machine, rexx scripts and your personal taste.
169 #define CHUNK_SIZE (8192)
172 * MAX_INTERNAL_SIZE is the max size of individual pieces of memory
173 * that this system will handle itself. If bigger pieces are requested
174 * it will just forward the request to malloc()/free(). Note that
175 * this value should be less than or equal to CHUNK_SIZE.
177 #define MAX_INTERNAL_SIZE (4096)
180 * MEMINFO_HASHSIZE is the size of the 'hashtable' used to find the size
181 * of a chunk of memory, given an address of a byte within that chunk.
182 * Actually, this isn't much of a real hashtable, but still. Allocating
183 * large value will not make much harm other than wasting memory. Using
184 * too small value can seriously degrade execution. The optimal size
185 * is such that MEMINFO_HASHSIZE * CHUNK_SIZE is only slight bigger
186 * than the actual use of memory in your rexx script (including the
187 * memory that will be wasted)
189 #define MEMINFO_HASHSIZE (499)
192 * FLIST_ARRAY_SIZE is the element count of an array which holds meminfo's
193 * (see below) while allocating space. Have a look at add_entry() below.
195 #define FLIST_ARRAY_SIZE 128
198 * GET_SIZE() is a 'function' that returns a index into the 'hash'
199 * variable, given a specific number. The index returned will be the
200 * index of the ptr to the list of free memory entries that is identical
201 * or slightly bigger than the parameter in size.
203 #define GET_SIZE(mt,a) (mt->hash[((a)+3)>>2])
206 * This is the hashfunction for use with 'hashtable'. It will effectively
207 * just shift away some of the lower bits and fold the result around
208 * the 'hashtable'. Note that '13' is corresponent to CHUNK_SIZE, since
209 * 8192 == 1<<13, which is the optimal size. If you change one of them
210 * be sure to change the other.
212 * Maybe we could eliminate a division by letting MEMINFO_HASHSIZE have
213 * a number equal to a binary 'round' number (e.g. 512). There is no
214 * need to keep the size a prime number, since the elements in the
215 * table *will* be well distributed.
217 #define mem_hash_func(a) (((a)>>13)%MEMINFO_HASHSIZE)
220 * Here are the list of the 'approved' sizes. Memory is only allocatable
221 * in these sizes. If you need anything else, use the lowest number that
222 * is higher than what you need.
224 * Why exactly these numbers? Why not? Note that these are a subset
225 * of the series {8,16,32,64,128...} and {12,24,48,96} mingled together.
226 * Note that you can not allocate memory in smaller sizes than is
227 * possible to fit a pointer (to char and/or void) into. Also take
228 * into consideration that all these sizes should be aligned according
229 * to the size of ints and pointers, so don't make them too small.
231 #define NUMBER_SIZES 19
232 static const int sizes
[NUMBER_SIZES
] =
233 { 8, 12, 16, 24, 32, 48, 64, 96,
234 128, 192 , 256, 384, 512, 768, 1024, 1536,
237 * The type meminfo holds the info about the connection between the
238 * address of allocated memory and the size of that memory. When new
239 * memory is allocated by malloc(), in size CHUNK_SIZE, a new box of
240 * meminfo is created, which holds the address returned from malloc()
241 * and the size in which the chunk was divided {8,12,16,24,32...}.
243 typedef struct meminfo_type
245 char *start
; /* start of memory's address */
246 char *last
; /* end of memory's address */
247 struct meminfo_type
*next
; /* next ptr in linked list */
248 int size
; /* size of chunks at that address */
252 typedef struct { /* mem_tsd: static variables of this module (thread-safe) */
255 * The array of pointers to the freelists having memory of the sizes
256 * specified in 'sizes'. I.e. flists[0] is a pointer to a linked list
257 * of free memory chunks of size 8, flist[1] to memory of size 12 etc.
258 * The size of this array is the same as the size of 'sizes'.
260 char *flists
[NUMBER_SIZES
];
263 * The 'hashtable'. Used for quick access to the size of a chunk of
264 * memory, given its address.
266 meminfo
*hashtable
[ MEMINFO_HASHSIZE
];
269 * These variables track the allocation of memory allocated by
270 * MallocTSD() and used by the internal memory allocation
273 meminfo
*first_entry
;
276 * Array used for rounding a number to an 'approved' size, i.e. a size
277 * in which the interpreter will allocate memory. Remember that the
278 * approved sizes are {8,12,16,24,32 ...}? This function will return
279 * 8 for 1 through 8; 12 for 9 through 12; 16 for 13 through 16 etc.
280 * It is not initially set, but will be set by init_memory().
282 * Note: the 'step' in this table (4 as it is defined below) must not
283 * be bigger then the smallest gap in between two 'approved' sizes of
284 * memory. E.g the smallest gap as defined above is 12-8 = 4.
286 * Actually, the name is somewhat misleading, since this is not really
287 * a hashtable, it is just a leftover from the time when it actually
290 * Due to how the hash array is initialized, we have to allocate one
291 * more item than is going to be used. This is really a klugde, and we
292 * really ought to fix it a more clean way.
294 short hash
[ CHUNK_SIZE
/4 + 1 ] ;
296 /* See add_entry() for the following two variables */
303 * Counter for dynamically memory allocated, in bytes, and ditto for
304 * the deallocated memory, dynamic memory currently in use is the
305 * difference between these. This is only used for gathering
312 * Sequence number for newly allocated memory, incremented for each
313 * new allocation of dynamic memory. Actually, it is stored as a
314 * unsigned short in the memhead of each memory allocation. That might
315 * be slightly too small, since the number of memory allocation can
316 * easily reach 100000, even for relatively small programs.
318 * Therefore, the sequence number might be stored as a 24 bit number,
319 * (on 32 bit machines). But anyway, who cares, it is only used for
320 * debugging purposes.
325 * Pointer to last (most newly) allocated memorychunk in double linked
326 * list of all allocated dynamic memory.
328 struct memhead
*header0
;
330 #define MAX_MARKERS 100
331 void (*(markers
[MAX_MARKERS
]))(const tsd_t
*TSD
) ;
332 int max_markers_regd
;
334 int FillerForThisStructure
;
335 } mem_tsd_t
; /* thread-specific but only needed by this module. see
340 static void init_hash_table( mem_tsd_t
*mt
) ;
341 # ifdef REGINA_DEBUG_MEMORY
342 static int show_a_free_list(mem_tsd_t
*mt
, int bin
, char *str
);
347 * This function initiates the 'mem_tsd'. This might have been
348 * done initially, since the values in this will never change. But
349 * since the size is rather big. it is more efficient to spend some
350 * CPU on initiating it. The startup time might be decreased by swapping
351 * this routine for a pre-defined variable. Perhaps it should be
352 * rewritten to use two arrays, one for large pieces of memory and
353 * one for small pieces. That would save space in 'hash'
355 * The values put into the array has been described above.
356 * The function returns 1 on success, 0 if memory is short.
358 int init_memory( tsd_t
*TSD
)
362 if (TSD
->mem_tsd
!= NULL
)
365 if ((mt
= TSD
->mem_tsd
= TSD
->MTMalloc(TSD
,sizeof(mem_tsd_t
))) == NULL
)
367 memset(mt
,0,sizeof(mem_tsd_t
));
369 * Don't register this chunk of memory! It contains the list of all
370 * other blocks of memory to be freed!
373 init_hash_table( mt
) ;
380 * This function initiates the variable 'hash'. This might have been
381 * done initially, since the values in this will never change. But
382 * since the size is rather big. it is more efficient to spend some
383 * CPU on initiating it. The startup time might be decreased by swapping
384 * this routine for a pre-defined variable. Perhaps it should be
385 * rewritten to use two arrays, one for large pieces of memory and
386 * one for small pieces. That would save space in 'hash'
388 * The values put into the array has been described above.
390 static void init_hash_table( mem_tsd_t
*mt
)
392 int indeks
; /* index into current element to be initiated */
397 /* Force allocation of the first mem_ctl: */
398 mt
->mem_ctl_idx
= FLIST_ARRAY_SIZE
;
401 * Set the few lowest values manually, since the algoritm breaks
402 * down for sufficient small values.
405 mt
->hash
[indeks
++] = 0 ; /* when size equals 0, well ... 8 :-) */
406 mt
->hash
[indeks
++] = 0 ; /* for 1 <= size < 4 */
407 mt
->hash
[indeks
++] = 0 ; /* for 4 <= size < 8 */
410 * The main loop. How does this algorithm work, well, look at the
411 * following table, in which all numbers should be multiplied with
412 * 4 to get the correct numbers.
420 * 5 (48) : 12 13 14 15
421 * 6 (64) : 16 17 18 19 20 21 22 23
422 * 7 (96) : 24 25 26 27 28 29 30 31
423 * 8 (128) : 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
424 * 9 (192) : 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
427 * The number to the left of the colon is the index into the
428 * 'sizes' array, and the number in parenthesis is the size which
429 * 'sizes' would return for that index. The numbers to the right of
430 * the colon are all the elements in 'hash' that contains that
431 * particular index into 'sizes'. Notice that pairs of lines have
432 * equal number of numbers, and that the number of numbers doubles
433 * for every second line.
435 * Therefore, let size be the number of elements to initialize in
436 * each iteration, and double it at the end of the loop. 'size'
437 * will then loop through 8, 16, 32, 64, 128 ... For each iteration
438 * of that loop, initialize 'size'/2 numbers to 'num' and then the
439 * next 'size'/2 numbers to 'num'+1. Increment 'num' by two for
440 * each iteration. The 'indeks' is the current number in hash to
445 for (; indeks
<(CHUNK_SIZE
/4); )
448 * Initalize first in each pair of bins of same length.
449 * I.e 8, 16, 32, 64 ... etc
451 for (j
=0; j
<size
; j
++ )
452 mt
->hash
[indeks
++] = (short) num
;
456 * Initialize the second in each pair: 12, 24, 48, 96 ... etc
458 for (j
=0; j
<size
; j
++ )
459 mt
->hash
[indeks
++] = (short) num
;
465 * Do I need this? I don't think so. It is a kludge to make something
466 * work on 64 bit machines, but I don't think it is needed anymore.
467 * Just let is be commented out, and the delete it if things seem
471 /* We need to know if "int" or "int*" ar larger than 4 bytes. Since the
472 * sizeof operator is evaluated at compile time and we don't want to
473 * get a message "expression is constant" we use a more complex
474 * expression. We assume that there is no machine with an "int"-size
475 * of 2 and a pointer size of 8 or something else.
478 size
+= sizeof(int*) ;
481 memset( mt
->flists
, 0, NUMBER_SIZES
* sizeof(char *) );
484 * This function stores in a singly linked list all chunks of memory
485 * that are allocated with malloc(). This is so that they can all be
486 * free()ed by the_free_flists().
488 static int register_mem( const tsd_t
*TSD
, void *chunk
)
491 mem_tsd_t
*mt
=TSD
->mem_tsd
;
493 if ((mem
= (meminfo
*)TSD
->MTMalloc( TSD
, sizeof( meminfo
))) == NULL
)
499 mt
->curr_entry
->next
= mem
;
501 mt
->curr_entry
= mem
;
502 if (mt
->first_entry
== NULL
)
503 mt
->first_entry
= mt
->curr_entry
;
510 * Adds information about a chunk of memory to the hashtable memory
511 * addresses and the chunksize at that address. Note that two addresses
512 * are sent as parameters, the start of the memory to be registerd, and
513 * the address under which the information is to be registered. Why?
514 * Look at the following figure:
517 * +---------------+-----------------+------------------+-------------+
518 * | AAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBB
519 * +----+----------------+---+----------------+-------------------------+
522 * Two chunks are allocated: A and B. The chunks are allocated in 8K
523 * blocks, but they will in general not follow the 8K boundaries of
524 * the machine. The 'hashtable' array have entries that _do_ follow
525 * the 8K boundaries of the machine. Therefore, chunk A must be
526 * registered under the in the 'hashtable' entries for both the 0-8K
527 * segment, and the 8-16K segment. And vice versa, the 8-16K segment
528 * may contain parts of chunk A and B.
530 * This could be avoided, if the chunks were aligned with the boundaries
531 * of the computer. If you change any of the constants in this part of
532 * the program, be sure to tune them to match eachother!
534 * Of course, this routines need memory to be able to register other
535 * memory, so to avoid a deadlock, it calls malloc directly. It will
536 * never release memory, since we can really not be sure that all
537 * memory has been released.
539 static void add_entry( const tsd_t
*TSD
, char *start
, const char *addr
, int bin_no
)
541 mem_tsd_t
*mt
= TSD
->mem_tsd
;
542 meminfo
*ptr
; /* work ptr */
543 int tmp
; /* tmp storage for mem_hash_func() */
546 * If we have used all free meminfo-boxes, allocate more. This is
547 * forces upon us at the first invocation. Allocate space for 128
550 if (mt
->mem_ctl_idx
>=FLIST_ARRAY_SIZE
)
552 /* Stupid SunOS acc gives incorrect warning for the next line */
553 if ((mt
->mem_ctl
= TSD
->MTMalloc( TSD
, sizeof( meminfo
) * FLIST_ARRAY_SIZE
)) == NULL
)
554 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
555 mt
->mem_ctl_idx
= 0 ;
556 if ( register_mem( TSD
, mt
->mem_ctl
) )
557 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
561 * Fill in the fields of the box, and put it in the front of the
562 * requested bin in hashtable
564 ptr
= &mt
->mem_ctl
[ mt
->mem_ctl_idx
++ ] ;
565 ptr
->next
= mt
->hashtable
[tmp
=mem_hash_func((unsigned long)addr
)] ;
568 mt
->hashtable
[tmp
] = ptr
;
573 * Allocate a piece of memory. The size is given as the 'size' parameter.
574 * If size is more than MAX_INTERNAL_SIZE, it will call malloc()
575 * directly, else, it will return a piece of memory from the freelist,
576 * after possibly filling the freelist with more memory if is was
577 * empty in the first place.
579 void *get_a_chunk( int size
)
581 return get_a_chunkTSD(__regina_get_tsd(), size
) ;
584 void *get_a_chunkTSD( const tsd_t
*TSD
, int size
)
586 int bin
; /* bin no in array of freelists */
587 char *vptr
; /* holds the result */
590 char *ptr
; /* work ptr, to loop through the memory */
591 char *topaddr
; /* points to last item in memory */
592 #ifdef REGINA_DEBUG_MEMORY
596 #ifdef REGINA_DEBUG_MEMORY1
597 fprintf(stderr
,"get_a_chunkTSD(): want %d bytes...\n",size
);
603 * If memory is too big, let malloc() handle the problem.
605 if (size
>MAX_INTERNAL_SIZE
)
607 if ((result
=TSD
->MTMalloc( TSD
, size
)) != NULL
)
609 if ( register_mem( TSD
, result
) )
610 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
614 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
618 * Get the first item from the appropriate freelist, and let 'vptr'
619 * point to it. Simultaneously set bin to the bin no in 'flists'
620 * to avoid recalculating the number. If the freelist is empty
621 * (i.e vptr==NULL) then allocate more memory.
623 if ((vptr
=mt
->flists
[bin
=GET_SIZE(mt
,size
)])==NULL
)
626 * Allocate the memory, and set both vptr and initiate the
627 * right element in 'flists'. Note that the value in 'flists' is
628 * 'incremented' later, so it must be set to the value which now
629 * is to be allocated.
631 vptr
= TSD
->MTMalloc( TSD
, CHUNK_SIZE
) ;
633 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
634 if ( register_mem( TSD
, vptr
) )
635 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
636 mt
->flists
[bin
] = vptr
;
637 #ifdef REGINA_DEBUG_MEMORY3
638 memset( vptr
, 0xC0+bin
, CHUNK_SIZE
);
642 * Calculate the top address of the memory allocated, and put
643 * the memory into 'topaddr'. Then register the chunk of memory
644 * in both the possible CHUNK_SIZE segments of the machine. In
645 * some rare cases the last registration might not be needed,
646 * but do it anyway, to avoid having to determine it.
648 topaddr
= vptr
+ CHUNK_SIZE
- sizes
[bin
] ;
649 add_entry( TSD
, vptr
, vptr
, bin
) ;
650 add_entry( TSD
, vptr
, vptr
+ CHUNK_SIZE
, bin
) ;
653 * Then loop through the individual pieced of memory within the
654 * newly allocated chunk, and make it a linked list, where the
655 * last ptr in the list is NULL.
657 for (ptr
=vptr
; ptr
<topaddr
; ptr
=ptr
+sizes
[bin
] )
658 *(char**)ptr
= ptr
+ sizes
[bin
] ;
660 *((char**)(ptr
-sizes
[bin
])) = NULL
;
661 #ifdef REGINA_DEBUG_MEMORY
662 show_a_free_list( mt
, bin
, "get_a_chunkTSD(): empty freelist for ");
667 * Update the pointer in 'flist' to point to the next entry in the
668 * freelist instead of the one we just allocated, and return to
671 #ifdef REGINA_DEBUG_MEMORY2
672 before
= show_a_free_list( mt
, bin
, NULL
);
674 mt
->flists
[bin
] = (*((char**)(vptr
))) ;
675 #ifdef REGINA_DEBUG_MEMORY2
676 after
= show_a_free_list( mt
, bin
, NULL
);
677 if ( before
- 1 != after
)
678 fprintf(stderr
,"****** get_a_chunkTSD() for bin [%d] failed. Before %d After %d\n",bin
,before
,after
);
684 streng
*get_a_streng( int size
)
686 return get_a_strengTSD(__regina_get_tsd(), size
) ;
689 streng
*get_a_strengTSD( const tsd_t
*TSD
, int size
)
691 register int bin
; /* bin no in array of freelists */
692 register char *vptr
; /* holds the result */
693 register streng
*result
;
695 char *ptr
; /* work ptr, to loop through the memory */
696 char *topaddr
; /* points to last item in memory */
697 #ifdef REGINA_DEBUG_MEMORY
701 size
= size
+ STRHEAD
;
704 * If memory is too big, let malloc() handle the problem.
706 #ifdef REGINA_DEBUG_MEMORY1
707 fprintf(stderr
,"get_a_strengTSD(): want %d bytes...\n",size
-STRHEAD
);
709 if (size
>MAX_INTERNAL_SIZE
)
711 if ((result
=TSD
->MTMalloc( TSD
, size
)) != NULL
)
714 result
->max
= size
-STRHEAD
;
715 if ( register_mem( TSD
, result
) )
716 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
720 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
726 * Get the first item from the appropriate freelist, and let 'vptr'
727 * point to it. Simultaneously set bin to the bin no in 'flists'
728 * to avoid recalculating the number. If the freelist is empty
729 * (i.e vptr==NULL) then allocate more memory.
731 if ((vptr
=mt
->flists
[bin
=GET_SIZE(mt
,size
)])==NULL
)
734 * Allocate the memory, and set both vptr and initiate the
735 * right element in 'flists'. Note that the value in 'flists' is
736 * 'incremented' later, so it must be set to the value which now
737 * is to be allocated.
739 vptr
= TSD
->MTMalloc( TSD
, CHUNK_SIZE
) ;
741 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
742 if ( register_mem( TSD
, vptr
) )
743 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
744 mt
->flists
[bin
] = vptr
;
745 #ifdef REGINA_DEBUG_MEMORY3
746 memset( vptr
, 0xA0+bin
, CHUNK_SIZE
);
750 * Calculate the top address of the memory allocated, and put
751 * the memory into 'topaddr'. Then register the chunk of memory
752 * in both the possible CHUNK_SIZE segments of the machine. In
753 * some rare cases the last registration might not be needed,
754 * but do it anyway, to avoid having to determine it.
756 topaddr
= vptr
+ CHUNK_SIZE
- sizes
[bin
] ;
757 add_entry( TSD
, vptr
, vptr
, bin
) ;
758 add_entry( TSD
, vptr
, vptr
+ CHUNK_SIZE
, bin
) ;
761 * Then loop through the individual pieced of memory within the
762 * newly allocated chunk, and make it a linked list, where the
763 * last ptr in the list is NULL.
765 for (ptr
=vptr
; ptr
<topaddr
; ptr
=ptr
+sizes
[bin
] )
766 *(char**)ptr
= ptr
+ sizes
[bin
] ;
768 *((char**)(ptr
-sizes
[bin
])) = NULL
;
770 #ifdef REGINA_DEBUG_MEMORY
771 show_a_free_list( mt
, bin
, "get_a_strengTSD(): empty freelist for ");
776 * Update the pointer in 'flist' to point to the next entry in the
777 * freelist instead of the one we just allocated, and return to
780 #ifdef REGINA_DEBUG_MEMORY2
781 before
= show_a_free_list( mt
, bin
, NULL
);
783 mt
->flists
[bin
] = (*((char**)(vptr
))) ;
784 ((streng
*)vptr
)->len
= 0 ;
785 ((streng
*)vptr
)->max
= size
-STRHEAD
;
786 #ifdef REGINA_DEBUG_MEMORY2
787 after
= show_a_free_list( mt
, bin
, NULL
);
788 if ( before
- 1 != after
)
789 fprintf(stderr
,"****** get_a_strengTSD() for bin [%d] failed. Before %d After %d\n",bin
,before
,after
);
792 return ((streng
*)vptr
) ;
796 * Shortcut to deallocate a streng. Since we know the max size of a
797 * streng, we don't really need to calculate the size using of the
798 * hashtable structure. That saves some time, since a lot of the
799 * memorychunks in rexx are strengs.
801 * Note that strengs can just as well be deallocated using the
802 * 'normal' method, but this interface saves some time. Just a thought:
803 * if all allocated string were sure to have a max size that did not
804 * waste any memory, we didn't have to expand the GET_SIZE macro,
805 * and thereby saving even a few more cycles
807 void give_a_streng( streng
*ptr
)
809 give_a_strengTSD(__regina_get_tsd(), ptr
) ;
812 void give_a_strengTSD( const tsd_t
*TSD
, streng
*ptr
)
814 char **tptr
; /* tmp variable, points to element in flists */
817 #ifdef REGINA_DEBUG_MEMORY
821 #ifdef REGINA_DEBUG_MEMORY1
822 fprintf(stderr
,"give_a_strengTSD() going to free %x...\n", ptr
);
824 assert( ptr
->len
<= ptr
->max
) ;
825 if ((ptr
->max
+STRHEAD
) > MAX_INTERNAL_SIZE
) /* off-by-one error ? */
827 TSD
->MTFree(TSD
, ptr
) ;
834 * First find the right element in flists, then link this piece
835 * of memory into the start of the list, clean and simple. 'tptr'
836 * is the old first element in the freelist, and 'ptr' is the
839 bin
= GET_SIZE(mt
,ptr
->max
+ STRHEAD
);
840 #ifdef REGINA_DEBUG_MEMORY2
841 before
= show_a_free_list( mt
, bin
, NULL
);
843 tptr
= &mt
->flists
[bin
] ;
844 *((char**)ptr
) = *tptr
;
846 #ifdef REGINA_DEBUG_MEMORY2
847 after
= show_a_free_list( mt
, bin
, NULL
);
848 if ( before
+ 1 != after
)
849 fprintf(stderr
,"****** give_a_strengTSD() for bin [%d] failed. Before %d After %d\n",bin
,before
,after
);
854 * The standard interface to freeing memory. The parameter 'ptr' is
855 * a pointer to the memory to be freed, is put first in the freelist
856 * pointed to by the appropriate element in 'flists'.
858 * I am not really sure what cptr do in this, but I think it has
859 * something to do with *void != *char on Crays ... The main consumer
860 * of CPU in this routine is the for(;;) loop, it should be rewritten.
862 void give_a_chunk( void *ptr
)
864 give_a_chunkTSD(__regina_get_tsd(), ptr
) ;
867 void give_a_chunkTSD( const tsd_t
*TSD
, void *ptr
)
869 char *cptr
; /* pseudonym for 'ptr' */
870 meminfo
*mptr
; /* caches the right element in hashtable */
872 #ifdef REGINA_DEBUG_MEMORY
878 * initialize a few values, 'cptr' is easy, while 'mptr' is the
879 * list of values for this piece of memory, that is in the
880 * hashtable that returns memory size given a specific address
883 mptr
= mt
->hashtable
[ mem_hash_func( ((unsigned long)cptr
) ) ] ;
884 #ifdef REGINA_DEBUG_MEMORY1
885 fprintf(stderr
,"give_a_chunkTSD() going to free %x hashtable %d...\n", ptr
, mem_hash_func( ((unsigned int)cptr
) ) );
889 * For each element in the list attached to the specific hashvalue,
890 * loop through the list, and stop at the entry which has a start
891 * address _less_ than 'cptr' and a stop address _higher_ than
892 * 'cptr' (i.e. cptr is within the chunk.)
894 for ( ; (mptr
) && ((mptr
->start
+CHUNK_SIZE
<=cptr
) || (mptr
->start
>cptr
)); mptr
= mptr
->next
) ;
897 * Now, there are two possibilities, either is mptr==NULL, in which
898 * case this piece of memory is never registered in the system, or
899 * then we have more information. In the former case, just give
900 * the address to free(), hoping it knows more. In the latter, put
901 * the memory on the appropriate freelist.
906 * Link it into the first place of the freelist.
908 #ifdef REGINA_DEBUG_MEMORY2
909 before
= show_a_free_list( mt
, mptr
->size
, NULL
);
911 *((char**)cptr
) = mt
->flists
[mptr
->size
] ;
912 mt
->flists
[mptr
->size
] = cptr
;
913 #ifdef REGINA_DEBUG_MEMORY2
914 after
= show_a_free_list( mt
, mptr
->size
, NULL
);
915 if ( before
+ 1 != after
)
916 fprintf(stderr
,"****** give_a_chunkTSD() for bin [%d] failed. Before %d After %d\n",mptr
->size
,before
,after
);
921 TSD
->MTFree(TSD
, ptr
) ;
926 * This function frees up all memory allocated by the flists internal
927 * meomory management routines
929 void purge_flists( const tsd_t
*TSD
)
936 ptr
= mt
->first_entry
;
941 TSD
->MTFree(TSD
, ptr
) ;
944 mt
->first_entry
= mt
->curr_entry
= NULL
;
948 # ifdef REGINA_DEBUG_MEMORY
949 static int show_a_free_list(mem_tsd_t
*mt
, int bin
, char *str
)
954 if ( mt
->flists
[bin
] == NULL
)
957 fprintf(stderr
,"%sbin[%d] Free List unallocated Maximum %d Size: %d\n",str
,bin
,(CHUNK_SIZE
/ sizes
[bin
]),sizes
[bin
]);
961 for (j
=1,ptr
=mt
->flists
[bin
]; *(char**)ptr
!=NULL
&& j
<5000; ptr
=*(char **)ptr
,j
++ )
966 fprintf(stderr
,"%sbin[%d] Number in Free List %d Maximum %d Size: %d\n",str
,bin
,j
,(CHUNK_SIZE
/ sizes
[bin
]), sizes
[bin
]);
971 int show_free_lists(const tsd_t
*TSD
)
973 int num_bins
= sizeof(sizes
)/sizeof(sizes
[0]);
978 for (i
=0;i
<num_bins
;i
++)
980 show_a_free_list( mt
, i
, "" );
984 # endif /* REGINA_DEBUG_MEMORY */
990 * Strings used to mark chunks of memory when listing dynamically
991 * allocated memory in listleaked(). Length is max 8 chars.
993 * NOTE: There is a close correspondace between these and the cpp
994 * variables TRC_* in defs.h. If you change one of them, please
995 * change the other too.
997 static const char *allocs
[] = {
998 "leaked", /* status unknown, probably leaked */
999 "hashtab", /* holds hashtable in variable subsystem */
1000 "procbox", /* the info local to a single routine */
1001 "source", /* a line of source code */
1002 "srcbox", /* box in list of source lines */
1003 "treenode", /* node in the parse three */
1004 "var_val", /* value of a variable */
1005 "var_nam", /* name of a variable */
1006 "var_box", /* other structure in the variable subsystem */
1007 "stc_box", /* box in linked list of the stack lines */
1008 "stc_line", /* stack line */
1009 "sys_info", /* the common info for a whole program */
1010 "file_ptr", /* holds the filetable */
1011 "proc_arg", /* holds arguments for internal or builtin functions */
1012 "label", /* holds info about labels */
1013 "static", /* names of special variables */
1014 "argcache", /* the proc argument cache */
1015 "math", /* dynamic workarrays in the math funcstion */
1016 "envirbx", /* box holding environment definition */
1017 "envirnm", /* name in a box holding environment definition */
1018 "spcvarbx", /* special variable box */
1019 "spcvarnm", /* special variable name */
1020 "spcnumbx", /* special number box */
1021 "spcnumnm", /* special number contents */
1022 NULL
/* terminator */
1027 * This routine obtains memory, either through get_a_chunk, or through
1028 * malloc() if we are not running with freelists. The memory requested
1029 * will be increased with the size of a memhead structure (32 bytes on
1030 * 'normal' 32 bit machines).
1032 * The function also updates the statistics, linkes it into the list
1033 * of currently allocated memory, and might pattern the memory.
1035 void *mymalloc( int bytes
)
1037 return mymallocTSD(__regina_get_tsd(), bytes
) ;
1040 void *mymallocTSD( const tsd_t
*TSD
, int bytes
)
1042 struct memhead
*memptr
; /* holds the result */
1048 * Increase the size of the memory wanted, so we can put the
1049 * header into it first. You'd better not have played with the
1050 * parameters above in such a way that the result is non-aligned.
1052 mt
->allocated
+= (bytes
+= sizeof(struct memhead
) ) ;
1055 * Do the actual allocation of memory, either call get_a_chunk()
1056 * or be boring and call plain old malloc(). In either case,
1057 * chicken out if there are not any more memory left. Hmmm, this
1058 * situation should be handled better. Memory management should
1059 * be transaction oriented
1062 if ((memptr
=get_a_chunk(bytes
)) == NULL
)
1064 if ((memptr
=TSD
->MTMalloc(TSD
,bytes
)) == NULL
)
1066 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ) ;
1068 #ifdef PATTERN_MEMORY
1070 * If the options for memory patterning is set, perform it. This is
1071 * only useful during debugging, to provoke error due to the use of
1072 * uninitialized variables. Other than that, it is just a pure waste
1075 memset( memptr
, NOT_USED
, bytes
) ;
1076 #endif /* PATTERN_MEMORY */
1079 * Fill in the fields of the header: the size, the sequence number,
1080 * the magic number, initialize the flag, and then link it into the
1081 * linked list of allocated memory, at the start of the list.
1083 memptr
->count
= bytes
;
1085 memptr
->magic
= MAGIC_COOKIE
;
1086 memptr
->seqv
= (unsigned short) ++mt
->sequence
;
1087 memptr
->prev
= NULL
;
1088 memptr
->next
= mt
->header0
;
1090 mt
->header0
->prev
= memptr
;
1093 * Increment the pointer to the start of the memory that the user
1094 * is allowed to use, i.e past the header. The return.
1096 mt
->header0
= memptr
++ ;
1103 * myfree takes a pointer to memory to be deallocated, it is a wrapper
1104 * for free(3), and does some housekeeping tasks
1106 void myfree( void *cptr
)
1108 myfreeTSD(__regina_get_tsd(), cptr
) ;
1111 void myfreeTSD( const tsd_t
*TSD
, void *cptr
)
1113 struct memhead
*memptr
; /* ptr to memory to be freed */
1118 * The header part of the memory is prepended to the part of the
1119 * memory that the user saw, so move the pointer backwards to the
1120 * start of the header.
1122 memptr
= ((struct memhead
*)cptr
) - 1 ;
1125 * If the magic cookie is not intact, there must be some serious
1126 * problems somewhere. Inform the user about it, and exit.
1128 if (memptr
->magic
!= MAGIC_COOKIE
)
1129 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1132 * Update the statistics. Remember that we do not decrement the
1133 * variable 'allocated'. The real number of memory allocated is
1134 * the difference between those two.
1136 mt
->deallocated
-= memptr
->count
;
1139 * Then unlink the chunk of memory from the linked list of allocated
1140 * memory. Set the pointers at its neighbors (if any) and set the
1141 * 'header' variable if it was first in the list.
1144 memptr
->next
->prev
= memptr
->prev
;
1147 memptr
->prev
->next
= memptr
->next
;
1149 mt
->header0
= memptr
->next
;
1151 #ifdef PATTERN_MEMORY
1153 * If we are to pattern the memory, overwrite the contents of the
1154 * memory, to provoke errors if parts of the interpreter use
1155 * memory after it have been deallocated.
1157 memset( memptr
, BEEN_USED
, memptr
->count
) ;
1161 * Then at last, deallocate the memory, either by giving it to
1162 * give_a_chunk (to be stored in the freelists) or by giving it
1163 * it directly to free().
1166 give_a_chunk(memptr
) ;
1168 TSD
->MTFree(TSD
,memptr
) ;
1174 /* have_allocated returns the amount of dynamic memory that has been
1175 * allocated, in bytes.
1177 int have_allocated( tsd_t
*TSD
, int flag
)
1185 case ( MEM_CURRENT
) :
1186 result
= mt
->allocated
- mt
->deallocated
;
1189 case ( MEM_ALLOC
) :
1190 result
= mt
->allocated
- mt
->deallocated
- listleaked( TSD
, MEMTRC_NONE
) ;
1193 case ( MEM_LEAKED
) :
1194 result
= listleaked( TSD
, MEMTRC_NONE
) ;
1198 exiterror( ERR_INCORRECT_CALL
, 0 ) ;
1205 void regmarker( const tsd_t
*TSD
, void (*marker
)(const tsd_t
*TSD
) )
1211 if (mt
->max_markers_regd
>=MAX_MARKERS
)
1212 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1214 mt
->markers
[mt
->max_markers_regd
++] = marker
;
1218 * This routine will three distinct things. First it iterates through
1219 * all the memory currently allocated and mark them as leaked. Then
1220 * it calls in sequence all the routines that mark the memory that the
1221 * various parts of the system claims. The pieces of memory that is
1222 * still marked leaked are then unclaimed. At last it iterates
1223 * through the list of memory once more, and dumps info about those
1224 * that are unclaimed by any part of the interpreter.
1226 * The parameter 'pflag' may have a value which is defined by the
1227 * macros MEMTRC_ in defs.h. These may be MEMTRC_NONE to not write out
1228 * anything; MEMTRC_ALL to list all memory; or MEMTRC_LEAKED which
1229 * only writes out the memory that is actually leaked.
1231 int listleaked( const tsd_t
*TSD
, int pflag
)
1234 * Array of functions to call for marking all active chunks of dynamic
1235 * allocated memory. These will mark _all_ dynamically allocated
1236 * memory. Anything unmarked after all these routines are called,
1237 * must be leaked memory. Add more functions as you wish
1239 static void (* const fptr
[])( const tsd_t
*TSD
) = {
1240 mark_stack
, /* the lines on the stack */
1241 mark_systeminfo
, /* the system information box */
1242 mark_filetable
, /* the file descriptor table */
1243 mark_param_cache
, /* the parameter chache */
1244 mark_descrs
, /* memory used by sting math routines */
1246 NULL
/* terminator */
1248 struct memhead
*memptr
; /* ptr that iterates through the memory */
1249 int i
; /* general loop control variable */
1250 int sum
; /* the sum of allocated memory */
1251 char *string
; /* ptr to the current allocated memory */
1256 * First, set the status of all pieces of memory to leaked.
1258 for (memptr
=mt
->header0
; memptr
; memptr
=memptr
->next
)
1259 memptr
->flag
= TRC_LEAKED
;
1262 * Then, call the functions that claims the memory that belongs to
1263 * the various parts of the system. These routines are stored in the
1264 * array 'fptr'. If you ever write anything that uses more memory,
1265 * be sure to add a function that is able to mark it, and append the
1266 * name of that function to 'fptr'. If you don't, and garbage
1267 * collection is implemented, you are in deep trouble.
1269 * Note the mark_listleaked_params(), that is special, since it marks
1270 * the parameters that the is in use by during the calling of the
1271 * builtin function that invokes this function.
1273 mark_listleaked_params( TSD
) ;
1274 for (i
=0;fptr
[i
];i
++)
1275 (*(fptr
[i
]))( TSD
) ;
1277 for (i
=0; i
<mt
->max_markers_regd
; i
++)
1278 (*(mt
->markers
[i
]))( TSD
) ;
1281 * Write out a header for the output, but only if we actually are to
1284 if (! pflag
==MEMTRC_NONE
&& TSD
->stddump
!= NULL
)
1285 fprintf(TSD
->stddump
," Len Flg Tag Seqv Address Contents\n") ;
1288 * Then, loop through the allocated memory, and for each piece of
1289 * memory in the linked list, check to see if it is leaked. If we
1290 * were called with the MEMTRC_ALL flag, then list out for every
1293 for (sum
=0,memptr
=mt
->header0
; memptr
; memptr
=memptr
->next
)
1294 if ((memptr
->flag
==TRC_LEAKED
)||(pflag
==MEMTRC_ALL
))
1297 * Keep an account on how much memory is actually in use. If
1298 * we are not to write anything out, skip the rest of this
1301 sum
+= memptr
->count
;
1302 if (!(pflag
==MEMTRC_NONE
))
1305 * Dump info about the current piece of memory. That includes
1306 * the size (excl the header), the flag and the string
1307 * belonging to the flag, and then the sequence number.
1309 if (TSD
->stddump
!= NULL
)
1310 fprintf(TSD
->stddump
, "%5d %3d %-8s %4d 0x%8x \"",
1311 memptr
->count
- sizeof(struct memhead
),
1312 memptr
->flag
, allocs
[memptr
->flag
], memptr
->seqv
, memptr
) ;
1315 * Dump the contents of the piece of memory. One piece of
1316 * memory per line in the output.
1318 string
= (char*)(memptr
+1) ;
1319 if (TSD
->stddump
!= NULL
)
1320 for (i
=0; i
<(int)(memptr
->count
- sizeof(struct memhead
)); i
++ )
1322 if (i
==40) /* bja 20->40 */
1325 * If it is more than 40 bytes long, terminate and write - bja 20->40
1326 * out "..." to indicate that there are more bytes in
1327 * the memory than was possible to write out.
1329 fprintf(TSD
->stddump
, " ..." ) ;
1333 * Write out a byte. If it is not a printable character,
1334 * write out a "?" instead, to indicate this. Perhaps this
1335 * should really be done using isprint() instead of
1336 * testing for a specific range of values?
1338 if ((string
[i
]>=' ')&&(string
[i
]<0x7f))
1339 putc( string
[i
], TSD
->stddump
) ;
1341 putc( '?', TSD
->stddump
) ;
1343 if (TSD
->stddump
!= NULL
)
1344 fprintf( TSD
->stddump
, "\"\n" ) ;
1353 * Marks a chunk of memory pointed to by 'ptr' to be of the kind
1354 * referenced in 'flag'. Might be defined as a macro, but since memory
1355 * garbagecollection is just for debugging purposes, there is really
1356 * no need to worry about that now.
1358 void markmemory( void *ptr
, int flag
)
1360 struct memhead
*memptr
; /* work pointer to memory to be marked */
1363 * It's rather simple, ptr is non-NULL, decrement the memptr pointer
1364 * to the start of the header, and set the flag. I am not sure
1365 * whether an internal error should be given if 'ptr' is NULL.
1366 * Maybe lots of code could be extracted from other parts of the
1367 * interpreter if they don't have to worry about not sending NULL
1368 * pointer to markmemory()?
1370 * That is hardly a problem now, since this is only used for debugging.
1371 * The only confusing part of this routine might be the casting.
1373 if ((memptr
=((struct memhead
*)ptr
)) != NULL
)
1376 memptr
->flag
= (unsigned char) flag
;
1379 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
1384 * This is really a simple routine, to write out the values of some
1385 * of the statistics gathered during (de)allocation of memory. Maybe it
1386 * should return the answer instead?
1388 void memory_stats(const tsd_t
*TSD
)
1393 if (TSD
->stddump
== NULL
)
1395 fprintf(TSD
->stddump
,
1396 "Allocated %d bytes in %d chunks, of which %d is deallocated\n",
1397 mt
->allocated
, mt
->sequence
, mt
->deallocated
) ; /* bja - variables out of order */
1400 #endif /* TRACEMEM */
1403 # if defined(TRACEMEM) || defined(FLISTS)
1404 # error CHECK_MEMORY should only be defined if FLISTS and TRACEMEM are not defined. Please, check the header files.
1407 void give_a_streng( streng
*ptr
)
1409 give_a_strengTSD( __regina_get_tsd(), ptr
) ;
1412 void give_a_strengTSD( const tsd_t
*TSD
, streng
*ptr
)
1415 * The assert is not really needed if we check for ptr!=NULL for the
1416 * free(ptr->value). Note, that free(NULL) is allowed in ANSI. But we will
1417 * check for error free code in case of !defined(CHECK_MEMORY), thus, we
1418 * assert the freeing. FGC
1420 assert((ptr
!= NULL
) && (ptr
->value
!= NULL
));
1421 TSD
->MTFree(TSD
,ptr
->value
);
1422 TSD
->MTFree(TSD
,ptr
);
1425 #endif /* CHECK_MEMORY */