1 /***********************************************************************/
2 /* MEMORY.C - Memory management functions.                             */
3 /***********************************************************************/
4 /*
5  * THE - The Hessling Editor. A text editor similar to VM/CMS xedit.
6  * Copyright (C) 1991-2013 Mark Hessling
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to:
20  *
21  *    The Free Software Foundation, Inc.
22  *    675 Mass Ave,
23  *    Cambridge, MA 02139 USA.
24  *
25  *
26  * If you make modifications to this software that you feel increases
27  * it usefulness for the rest of the community, please email the
28  * changes, enhancements, bug fixes as well as any and all ideas to me.
29  * This software is going to be maintained and enhanced as deemed
30  * necessary by the community.
31  *
32  * Mark Hessling, mark@rexx.org  http://www.rexx.org/
33  *
34  * The code in this module is borrowed from:
35  * The Regina Rexx Interpreter
36  * Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>
37  */
38 
39 
40 /*
41  * The routines in this file try to minimize the the number of calls
42  * to malloc() and free(). Since it would generally not be possible to
43  * release memory, unless it actually is last in the virtual memory
44  * that the process holds, just don't release it, and let the
45  * interpreter grow. Memory are allocated in only certain sizes, and
46  * are "freed" to a freelist, which is within the interpreter.
47  *
48  * The important routines are get_a_chunk() and give_a_chunk(), which
49  * might be called a large number of times. All the other routines are
50  * either called once to initiate, or it is used in tracing and
51  * debugging, where speed and space is not important anyway.
52  *
53  * The algorithm works something like this: memory can only be allocated
54  * in predetermined sizes (8, 12, 16, 24, 32, ...) and allocation of a
55  * size other than that will have to allocate something slightly bigger.
56  * For each size, there is a linked list of free pieces of memory of
57  * that size, the first entry of each of these lists can be accessed
58  * through 'flists', which is an array of pointers to these lists.
59  *
60  * Every time someone needs a piece of memory, the first piece of the
61  * freelist containing memory of suitable size (as big or slightly
62  * bigger) is returned. If the list is empty, a large piece of
63  * memory is allocated by malloc(), chopped up and put on the freelist
64  * that was empty.
65  *
66  * When memory is released, the prime problem is to decide which
67  * freelist to put it on. To manage that, each time memory is
68  * allocated by malloc(), the upper and lower address of the memory
69  * is put in hashtable; given a particular address, the hashtable
70  * can be sought using the address as hashvalue, and the result will
71  * be the size of the memory chunks at that address.
72  *
73  * When dealloacting strings, we know the max-size of the string, and
74  * then we can calculate which freelist the string should be put on,
75  * without having to search the hashtable structure. Note that there
76  * is no need to deallocate strings using the give_a_string() function,
77  * the normal give_a_chunk() will work just as well, but is somewhat
78  * slower.
79  *
80  * If you don't #define FLISTS, then malloc() and free() should be
81  * used instead. That might be very slow on some machines, since rexx
82  * memory is traced, which also tend to be slow, since there is a lot
83  * current implementation you can use malloc()/free() in parallel with
84  * the routines defined here.
85  *
86  * Note that using this metod, the last piece of memory freed will be
87  * the first to be used when more memory is needed.
88  *
89  * The number of calls to malloc() seems to be negligable when using
90  * this metod (typical less than 100 for medium sized programs). But
91  * this is of course dependent on how the program uses memory.
92  *
93  * extention for debugging purposes. Whenever memory is allocated,
94  * used like this:
95  *
96  *   0       4       8      12       16 bytes
97  *   | count |f|m|seq| prev  | next  | start of allocated memory
98  *
99  * The 'count' is the number of bytes allocated, 'f' (flag) is used in
100  * garbage collection, and 'prev' and 'next' are pointers used in a
101  * double linked list. seqv is a sequence number which is iterated
102  * for each memoryallocation.
103  *
104  * count is int, prev and next are char*, f is char and seqv is a
105  * 16 bit integer. The 'm' is a magic number. Actually it is just
106  * there to fill the space, and can be used for more useful purposed
107  * if needed.
108  *
109  * memory with bitpatterns. If the PATTERN_MEMORY cpp-variable is set,
110  * is set BEEN_USED before deallocation.
111  *
112  * Garbage-collection is not implemented, but listleaked will list out
113  * every chunk of allocated memory that are not currently in use. The
114  * array markptrs contains a list of functions for marking memory.
115  * There is a potensial problem with garbage collection, since the
116  * interpreter might 'loose' some memory everytime it hits a syntax
117  * error, like "say random(.5)". To fix that, memory should either
118  * be traced and then garbage collected, or it should have a sort
119  * of transaction oriented memory management (yuk!).
120  *
121  *      this:  sizeof(int) = sizeof(char*) = 32 bits. It might work
122  *      guarantee it.
123  *
124  */
125 #include <stdio.h>
126 #include <assert.h>
127 
128 #ifdef HAVE_STRING_H
129 # include <string.h>
130 #endif
131 
132 #ifdef HAVE_STDLIB_H
133 # include <stdlib.h>
134 #endif
135 
136 #ifdef HAVE_MEMORY_H
137 # include <memory.h>
138 #endif
139 
140 #include <the.h>
141 #include <proto.h>
142 
143 #if defined(__BOUNDS_CHECKING_ON) || defined(__USING_EFENCE)
get_a_block(size_t size)144 void *get_a_block( size_t size )
145 {
146    return( malloc( size ) );
147 }
148 
give_a_block(void * ptr)149 void give_a_block( void *ptr )
150 {
151    free( ptr );
152 }
153 
resize_a_block(void * ptr,size_t size)154 void *resize_a_block( void *ptr, size_t size )
155 {
156    return( realloc( ptr, size ) );
157 }
158 
init_memory_table(void)159 void init_memory_table( void )
160 {
161 }
162 
the_free_flists(void)163 void the_free_flists( void )
164 {
165 }
166 #else
167 
168 #define FLISTS
169 #define PATTERN_MEMORY
170 
171 #ifdef FLISTS
172 
173 /*
174  * CHUNK_SIZE it the size in which memory is allocated using malloc(),
175  * and that memory is then divided into pieces of the wanted size.
176  * If you increase it, things will work slightly faster, but more
177  * memory is wasted, and vice versa. The 'right' size is dependent on
178  * your machine, rexx scripts and your personal taste.
179  */
180 #define CHUNK_SIZE (8192)
181 
182 /*
183  * MAX_INTERNAL_SIZE is the max size of individual pieces of memory
184  * that this system will handle itself. If bigger pieces are requested
185  * it will just forward the request to malloc()/free(). Note that
186  * this value should be less than or equal to CHUNK_SIZE.
187  */
188 #define MAX_INTERNAL_SIZE (4096)
189 
190 /*
191  * MEMINFO_HASHSIZE is the size of the 'hashtable' used to find the size
192  * of a chunk of memory, given an address of a byte within that chunk.
193  * Actually, this isn't much of a real hashtable, but still. Allocating
194  * large value will not make much harm other than wasting memory. Using
195  * too small value can seriously degrade execution. The optimal size
196  * is such that MEMINFO_HASHSIZE * CHUNK_SIZE is only slight bigger
197  * than the actual use of memory in your rexx script (including the
198  * memory that will be wasted)
199  */
200 #define MEMINFO_HASHSIZE (499)
201 
202 /*
203  * GET_SIZE() is a 'function' that returns a index into the 'hash'
204  * variable, given a specific number. The index returned will be the
205  * index of the ptr to the list of free memory entries that is identical
206  * or slightly bigger than the parameter in size.
207  */
208 #define GET_SIZE(a) (hash[((a)+3)>>2])
209 
210 /*
211  * This is the hashfunction for use with 'hashtable'. It will effectively
212  * just shift away some of the lower bits and fold the result around
213  * the 'hashtable'. Note that '13' is corresponent to CHUNK_SIZE, since
214  * 8192 == 1<<13, which is the optimal size. If you change one of them
215  * be sure to change the other.
216  *
217  * Maybe we could eliminate a division by letting MEMINFO_HASHSIZE have
218  * a number equal to a binary 'round' number (e.g. 512). There is no
219  * need to keep the size a prime number, since the elements in the
220  * table *will* be well distributed.
221  */
222 #define mem_hash_func(a) (((a)>>13)%MEMINFO_HASHSIZE)
223 
224 /*
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.
228  *
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.
235  */
236 #define NUMBER_SIZES 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 
242 /*
243  * The array of pointers to the freelists having memory of the sizes
244  * specified in 'sizes'. I.e. theflists[0] is a pointer to a linked list
245  * of free memory chunks of size 8, flist[1] to memory of size 12 etc.
246  * The size of this array is the same as the size of 'sizes'.
247  */
248 static char *theflists[NUMBER_SIZES] = { NULL } ;
249 
250 /*
251  * The type meminfo holds the info about the connection between the
252  * address of allocated memory and the size of that memory. When new
253  * memory is allocated by malloc(), in size CHUNK_SIZE, a new box of
254  * meminfo is created, which holds the address returned from malloc()
255  * and the size in which the chunk was divided {8,12,16,24,32...}.
256  */
257 typedef struct meminfo_type
258 {
259    char *start ;                /* start of memory's address */
260    char *last ;                 /* end of memory's address */
261    struct meminfo_type *next ;  /* next ptr in linked list */
262    int size ;                   /* size of chunks at that address */
263 } meminfo ;
264 
265 /*
266  * The 'hashtable'. Used for quick access to the size of a chunk of
267  * memory, given its address.
268  */
269 static meminfo *hashtable[ MEMINFO_HASHSIZE ] = { NULL } ;
270 
271 /*
272  * Array used for rounding a number to an 'approved' size, i.e. a size
273  * in which the interpreter will allocate memory. Remember that the
274  * approved sizes are {8,12,16,24,32 ...}? This function will return
275  * 8 for 1 through 8; 12 for 9 through 12; 16 for 13 through 16 etc.
276  * It is not initially set, but will be set by init_hash_table().
277  *
278  * Note: the 'step' in this table (4 as it is defined below) must not
279  * be bigger then the smallest gap in between two 'approved' sizes of
280  * memory. E.g the smallest gap as defined above is 12-8 = 4.
281  *
282  * Actually, the name is somewhat misleading, since this is not really
283  * a hashtable, it is just a leftover from the time when it actually
284  * was a hashtable.
285  *
286  * Due to how the hash array is initialized, we have to allocate one
287  * more item than is going to be used. This is really a klugde, and we
288  * really ought to fix it a more clean way.
289  */
290 static short hash[ CHUNK_SIZE/4 + 1 ] ;
291 #endif
292 
293 static meminfo *first_chunk=NULL;
294 static meminfo *curr_chunk=NULL;
295 
296 # ifdef THE_DEBUG_MEMORY2
show_a_free_list(int bin,char * str)297 static int show_a_free_list(int bin, char *str)
298 {
299    char *ptr;
300    int j=0;
301 
302    if ( theflists[bin] == NULL )
303    {
304       if (str)
305          fprintf(stderr,"%sbin[%d] Free List unallocated Maximum %d Size: %d\n",str,bin,(CHUNK_SIZE / sizes[bin]), sizes[bin]);
306    }
307    else
308    {
309       for (j=1,ptr=theflists[bin]; *(char**)ptr!=NULL && j<5000; ptr=*(char **)ptr,j++ );
310       if (str)
311          fprintf(stderr,"%sbin[%d] Number in Free List %d Maximum %d Size: %d\n",str,bin,j,(CHUNK_SIZE / sizes[bin]), sizes[bin]);
312    }
313    return j;
314 }
315 #endif
316 /*
317  * This function stores in a singly linked list all chunks of memory
318  * that are allocated with malloc(). This is so that they can all be
319  * free()ed by the_free_flists().
320  */
321 /******************************************************************************/
322 #ifdef HAVE_PROTO
register_mem(void * chunk)323 int register_mem( void *chunk )
324 #else
325 int register_mem( chunk )
326 void *chunk;
327 #endif
328 /******************************************************************************/
329 {
330    meminfo *mem=NULL;
331 
332    if ((mem = (meminfo *)malloc( sizeof( meminfo ))) == NULL )
333       return(1);
334    mem->start = (char *)chunk;
335    mem->next = NULL;
336    if (curr_chunk)
337    {
338       curr_chunk->next = mem;
339    }
340    curr_chunk = mem;
341    if (first_chunk == NULL)
342       first_chunk = curr_chunk;
343    return(0);
344 }
345 
346 /*
347  * This function initiates the variable 'hash'. 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'
354  *
355  * The values put into the array has been described above.
356  */
357 /******************************************************************************/
358 #ifdef HAVE_PROTO
init_memory_table(void)359 void init_memory_table( void )
360 #else
361 void init_memory_table()
362 #endif
363 /******************************************************************************/
364 {
365    int indeks ;   /* index into current element to be initiated */
366    int j ;
367    int size ;
368    int num ;
369 
370    /*
371     * Set the few lowest values manually, since the algoritm breaks
372     * down for sufficient small values.
373     */
374    indeks = 0 ;
375    hash[indeks++] = 0 ;  /* when size equals 0, well ... 8 :-) */
376    hash[indeks++] = 0 ;  /* for 1 <= size < 4 */
377    hash[indeks++] = 0 ;  /* for 4 <= size < 8 */
378 
379    /*
380     * The main loop. How does this algorithm work, well, look at the
381     * following table, in which all numbers should be multiplied with
382     * 4 to get the correct numbers.
383     *
384     *  bin        sizes
385     *   0   (8) :  2
386     *   1  (12) :  3
387     *   2  (16) :  4  5
388     *   3  (24) :  6  7
389     *   4  (32) :  8  9 10 11
390     *   5  (48) : 12 13 14 15
391     *   6  (64) : 16 17 18 19 20 21 22 23
392     *   7  (96) : 24 25 26 27 28 29 30 31
393     *   8 (128) : 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
394     *   9 (192) : 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
395     * etc
396     *
397     * The number to the left of the colon is the index into the
398     * 'sizes' array, and the number in parenthesis is the size which
399     * 'sizes' would return for that index. The numbers to the right of
400     * the colon are all the elements in 'hash' that contains that
401     * particular index into 'sizes'.  Notice that pairs of lines have
402     * equal number of numbers, and that the number of numbers doubles
403     * for every second line.
404     *
405     * Therefore, let size be the number of elements to initialize in
406     * each iteration, and double it at the end of the loop. 'size'
407     * will then loop through 8, 16, 32, 64, 128 ... For each iteration
408     * of that loop, initialize 'size'/2 numbers to 'num' and then the
409     * next 'size'/2 numbers to 'num'+1. Increment 'num' by two for
410     * each iteration. The 'indeks' is the current number in hash to
411     * initialize.
412     */
413    size = 1 ;
414    num = 1 ;
415    for (; indeks<(CHUNK_SIZE/4); )
416    {
417       /*
418        * Initalize first in each pair of bins of same length.
419        * I.e  8, 16, 32,  64 ... etc
420        */
421       for (j=0; j<size; j++ )
422          hash[indeks++] = num ;
423       num++ ;
424 
425       /*
426        * Initialize the second in each pair: 12, 24, 48, 96 ... etc
427        */
428       for (j=0; j<size; j++ )
429          hash[indeks++] = num ;
430       num++ ;
431       size = size << 1 ;
432    }
433 
434    /*
435     * Do I need this? I don't think so. It is a kludge to make something
436     * work on 64 bit machines, but I don't think it is needed anymore.
437     * Just let is be commented out, and the delete it if things seem
438     * to work.
439     */
440 
441    if (sizeof(int)>4 || sizeof(int*)>4)
442       hash[3] = 2 ;
443    memset( theflists, 0, NUMBER_SIZES * sizeof(char *) );
444 
445 }
446 
447 
448 
449 /*
450  * Adds information about a chunk of memory to the hashtable memory
451  * addresses and the chunksize at that address. Note that two addresses
452  * are sent as parameters, the start of the memory to be registerd, and
453  * the address under which the information is to be registered. Why?
454  * Look at the following figure:
455  *
456  * 0               8K               16K                24K
457  * +---------------+-----------------+------------------+-------------+
458  * |    AAAAAAAAAAAAAAAAAA   BBBBBBBBBBBBBBBBBB
459  * +----+----------------+---+----------------+-------------------------+
460  *      3K              11K 13K              21K
461  *
462  * Two chunks are allocated: A and B. The chunks are allocated in 8K
463  * blocks, but they will in general not follow the 8K boundaries of
464  * the machine. The 'hashtable' array have entries that _do_ follow
465  * the 8K boundaries of the machine. Therefore, chunk A must be
466  * registered under the in the 'hashtable' entries for both the 0-8K
467  * segment, and the 8-16K segment. And vice versa, the 8-16K segment
468  * may contain parts of chunk A and B.
469  *
470  * This could be avoided, if the chunks were aligned with the boundaries
471  * of the computer. If you change any of the constants in this part of
472  * the program, be sure to tune them to match eachother!
473  *
474  * Of course, this routines need memory to be able to register other
475  * memory, so to avoid a deadlock, it calls malloc directly. It will
476  * never release memory, since we can really not be sure that all
477  * memory has been released.
478  */
479 /******************************************************************************/
480 #ifdef HAVE_PROTO
add_entry(char * start,char * addr,int bin_no)481 static int add_entry( char *start, char *addr, int bin_no )
482 #else
483 static int add_entry( start, addr, bin_no )
484 char *start;
485 char *addr;
486 int bin_no;
487 #endif
488 /******************************************************************************/
489 {
490    meminfo *ptr ;              /* work ptr */
491    int tmp ;                   /* tmp storage for mem_hash_func() */
492    static meminfo *mem=NULL ;  /* ptr to array, empty at first */
493    static int indeks=128 ;      /* force it to allocate at first invocation */
494 
495    /*
496     * If we have used all free meminfo-boxes, allocate more. This is
497     * forces upon us at the first invocation. Allocate space for 128
498     * at a time.
499     */
500    if (indeks>=128)
501    {
502       /* Stupid SunOS acc gives incorrect warning for the next line */
503       if  (!(mem = (meminfo *)malloc( sizeof( meminfo) * 128 )))
504           return(1);
505       if (register_mem( (void *)mem ))
506          return(1);
507       indeks = 0 ;
508    }
509 
510    /*
511     * Fill in the fields of the box, and put it in the front of the
512     * requested bin in hashtable
513     */
514    ptr = &mem[ indeks++ ] ;
515    ptr->next = hashtable[tmp=mem_hash_func((unsigned long)addr)] ;
516    ptr->size = bin_no ;
517    ptr->start = start ;
518    hashtable[tmp] = ptr ;
519    return(0);
520 }
521 
522 /*
523  * Allocate a piece of memory. The size is given as the 'size' parameter.
524  * If size is more than MAX_INTERNAL_SIZE, it will call malloc()
525  * directly, else, it will return a piece of memory from the freelist,
526  * after possibly filling the freelist with more memory if is was
527  * empty in the first place.
528  */
529 /******************************************************************************/
530 #ifdef HAVE_PROTO
get_a_block(size_t size)531 void *get_a_block( size_t size )
532 #else
533 void *get_a_block( size )
534 int size;
535 #endif
536 /******************************************************************************/
537 {
538    register int bin ;     /* bin no in array of freelists */
539    register char *vptr ;  /* holds the result */
540    register void *result ;
541 #ifdef THE_DEBUG_MEMORY2
542    int before, after;
543 #endif
544 
545    /*
546     * If memory is too big, let malloc() handle the problem.
547     */
548    if (size>MAX_INTERNAL_SIZE)
549    {
550       if ((result=malloc( size )))
551       {
552          if (register_mem( result ))
553             return(NULL);
554          return result ;
555       }
556       else
557           return NULL;
558    }
559 
560    /*
561     * Get the first item from the appropriate freelist, and let 'vptr'
562     * point to it. Simultaneously set bin to the bin no in 'theflists'
563     * to avoid recalculating the number. If the freelist is empty
564     * (i.e vptr==NULL) then allocate more memory.
565     */
566    if ((vptr=theflists[bin=GET_SIZE(size)])==NULL)
567    {
568       char *ptr ;      /* work ptr, to loop through the memory */
569       char *topaddr ;  /* points to last item in memory */
570 
571       /*
572        * Allocate the memory, and set both vptr and initiate the
573        * right element in 'theflists'. Note that the value in 'flists' is
574        * 'incremented' later, so it must be set to the value which now
575        * is to be allocated.
576        */
577       vptr = (char *)malloc( CHUNK_SIZE ) ;
578       if (!vptr)
579           return(NULL);
580       theflists[bin] = vptr ;
581 
582       /*
583        * Calculate the top address of the memory allocated, and put
584        * the memory into 'topaddr'. Then register the chunk of memory
585        * in both the possible CHUNK_SIZE segments of the machine. In
586        * some rare cases the last registration might not be needed,
587        * but do it anyway, to avoid having to determine it.
588        */
589       topaddr = vptr + CHUNK_SIZE - sizes[bin] ;
590       if (register_mem( vptr ))
591          return(NULL);
592       if (add_entry( vptr, vptr, bin ))
593          return(NULL);
594       if (add_entry( vptr, vptr + CHUNK_SIZE, bin ))
595          return(NULL);
596 
597       /*
598        * Then loop through the individual pieced of memory within the
599        * newly allocated chunk, and make it a linked list, where the
600        * last ptr in the list is NULL.
601        */
602       for (ptr=vptr; ptr<topaddr; ptr=ptr+sizes[bin] )
603          *(char**)ptr = ptr + sizes[bin] ;
604 
605       *((char**)(ptr-sizes[bin])) = NULL ;
606 
607 #ifdef THE_DEBUG_MEMORY2
608       show_a_free_list( bin, "get_a_block(): empty freelist for ");
609 #endif
610    }
611 
612    /*
613     * Update the pointer in 'flist' to point to the next entry in the
614     * freelist instead of the one we just allocated, and return to
615     * caller.
616     */
617 #ifdef THE_DEBUG_MEMORY2
618    before = show_a_free_list( bin, NULL);
619 #endif
620    theflists[bin] = (*((char**)(vptr))) ;
621 #ifdef THE_DEBUG_MEMORY2
622    after = show_a_free_list( bin, NULL );
623    if ( before - 1 != after )
624       fprintf(stderr,"****** get_a_block() for bin [%d] failed. Before %d After %d\n",bin,before,after);
625 #endif
626    return (vptr) ;
627 }
628 
629 
630 /*
631  * The standard interface to freeing memory. The parameter 'ptr' is
632  * a pointer to the memory to be freed, is put first in the freelist
633  * pointed to by the appropriate element in 'theflists'.
634  *
635  * I am not really sure what cptr do in this, but I think it has
636  * something to do with *void != *char on Crays ... The main consumer
637  * of CPU in this routine is the for(;;) loop, it should be rewritten.
638  */
639 /******************************************************************************/
640 #ifdef HAVE_PROTO
give_a_block(void * ptr)641 void give_a_block( void *ptr )
642 #else
643 void give_a_block( ptr )
644 void *ptr;
645 #endif
646 /******************************************************************************/
647 {
648    char *cptr ;      /* pseudonym for 'ptr' */
649    meminfo *mptr ;   /* caches the right element in hashtable */
650 #ifdef THE_DEBUG_MEMORY2
651    int before, after;
652 #endif
653 
654    /*
655     * initialize a few values, 'cptr' is easy, while 'mptr' is the
656     * list of values for this piece of memory, that is in the
657     * hashtable that returns memory size given a specific address
658     */
659    cptr = (char*)ptr ;
660    mptr = hashtable[ mem_hash_func( ((unsigned long)cptr) ) ] ;
661 
662    /*
663     * For each element in the list attached to the specific hashvalue,
664     * loop through the list, and stop at the entry which has a start
665     * address _less_ than 'cptr' and a stop address _higher_ than
666     * 'cptr' (i.e. cptr is within the chunk.)
667     */
668    for ( ; (mptr) &&
669         ((mptr->start+CHUNK_SIZE<=cptr) || (mptr->start>cptr)) ;
670         mptr = mptr->next) ;
671 
672    /*
673     * Now, there are two possibilities, either is mptr==NULL, in which
674     * case this piece of memory is never registered in the system, or
675     * then we have more information. In the former case, just give
676     * the address to free(), hoping it knows more. In the latter, put
677     * the memory on the appropriate freelist.
678     */
679    if (mptr)
680    {
681       /*
682        * Link it into the first place of the freelist.
683        */
684 #ifdef THE_DEBUG_MEMORY2
685       before = show_a_free_list( mptr->size, NULL );
686 #endif
687       *((char**)cptr) = theflists[mptr->size] ;
688       theflists[mptr->size] = cptr ;
689 #ifdef THE_DEBUG_MEMORY2
690       after = show_a_free_list( mptr->size, NULL );
691       if ( before + 1 != after )
692          fprintf(stderr,"****** give_a_block() for bin [%d] failed. Before %d After %d\n",mptr->size,before,after);
693 #endif
694    }
695    else
696       free( ptr ) ;
697 }
698 
699 /*
700  * The interface to resizing memory. The parameter 'ptr' is
701  * a pointer to the memory to be resized. First, if the requested size
702  * is within the size of the existing block, just return it. Otherwise
703  * the block is put back on the free lists and a new block allocated.
704  */
705 /******************************************************************************/
706 #ifdef HAVE_PROTO
resize_a_block(void * ptr,size_t size)707 void *resize_a_block( void *ptr, size_t size )
708 #else
709 void *resize_a_block( ptr, size )
710 void *ptr;
711 int size;
712 #endif
713 /******************************************************************************/
714 {
715    char *cptr ;      /* pseudonym for 'ptr' */
716    meminfo *mptr ;   /* caches the right element in hashtable */
717    register void *result ;
718 
719    /*
720     * initialize a few values, 'cptr' is easy, while 'mptr' is the
721     * list of values for this piece of memory, that is in the
722     * hashtable that returns memory size given a specific address
723     */
724    cptr = (char*)ptr ;
725    mptr = hashtable[ mem_hash_func( ((unsigned long)cptr) ) ] ;
726 
727    /*
728     * For each element in the list attached to the specific hashvalue,
729     * loop through the list, and stop at the entry which has a start
730     * address _less_ than 'cptr' and a stop address _higher_ than
731     * 'cptr' (i.e. cptr is within the chunk.)
732     */
733    for ( ; (mptr) &&
734         ((mptr->start+CHUNK_SIZE<=cptr) || (mptr->start>cptr)) ;
735         mptr = mptr->next) ;
736 
737    /*
738     * Now, there are two possibilities, either mptr==NULL, in which
739     * case this piece of memory was never registered in the system, or
740     * we have more information. In the former case, just give
741     * the address to realloc(), and return. In the latter, if the
742     * requested size is still within the currently allocated size
743     * return it, or allocate a new chunk, copy the current contents
744     * to the new chunk and put the old piece of memory on the
745     * appropriate freelist.
746     */
747    if (!mptr)
748       return ( realloc(ptr, size) ) ;
749 
750    /*
751     * If the size of the block being resized is within the current
752     * block size, simply return the same pointer.
753     */
754    if (size <= sizes[mptr->size])
755       return ptr;
756 
757    /*
758     * Get the new chunk of memory. This MUST be larger than the
759     * previous chunk to have reached here.
760     */
761    result = get_a_block( size ) ;
762    if (result == NULL)
763       return NULL;
764    /*
765     * Copy the current contents into the new chunk.
766     */
767    memcpy( result, cptr, sizes[mptr->size] ) ;
768 
769    /*
770     * Put the old chunk into the first place of the freelist.
771     */
772    *((char**)cptr) = theflists[mptr->size] ;
773    theflists[mptr->size] = cptr ;
774 
775    return result;
776 }
777 
778 /******************************************************************************/
779 #ifdef HAVE_PROTO
the_free_flists(void)780 void the_free_flists( void )
781 #else
782 void the_free_flists()
783 #endif
784 /******************************************************************************/
785 {
786    meminfo *ptr = first_chunk;
787    meminfo *next = NULL;
788 
789    while( ptr )
790    {
791       next = ptr->next;
792       free( ptr );
793       ptr = next;
794    }
795    first_chunk = curr_chunk = NULL;
796    return;
797 }
798 #endif /* __BOUNDS_CHECKING_ON */
799