1 /* Copyright (c) 1995, 2002, 2009 Xilinx, Inc.  All rights reserved.
2 
3    Redistribution and use in source and binary forms, with or without
4    modification, are permitted provided that the following conditions are
5    met:
6 
7    1.  Redistributions source code must retain the above copyright notice,
8    this list of conditions and the following disclaimer.
9 
10    2.  Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 
14    3.  Neither the name of Xilinx nor the names of its contributors may be
15    used to endorse or promote products derived from this software without
16    specific prior written permission.
17 
18    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS
19    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 */
31 
32 #ifdef DEBUG
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #else
37 typedef unsigned int size_t;
38 #define NULL 0
39 #endif
40 
41 #define sbrk xil_sbrk
42 
43 /* The only extern functions I need if not printing. */
44 extern  void* sbrk(size_t incr);
45 extern  void *memcpy(void *s1, const void *s2, size_t n);
46 extern  void *memset(void *s, int c, size_t n);
47 
48 
49 typedef unsigned char BOOLEAN;
50 const BOOLEAN FALSE=0;
51 const BOOLEAN TRUE =1;
52 
53 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
54 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
55 
56 #define M_DBG_NORMAL 0
57 #define M_DBG_PARTIAL 1
58 #define M_DBG_FULL 2
59 
60 /* debugging breakpoint aids */
61 static char xil_mem_null_free[] = "xil_mem_null_free";
62 static char xil_mem_chkcnt   [] = "xil_mem_chkcnt";
63 
64 /* Flag values describing the state of a memory block.
65 /* Indicator for allocated blk */
66 #define M_ALLOCEDFLAG 0x5a
67 /* End-of-block if debug level */
68 #define M_ALLOCED 0xc99cc99c
69 /* Free block indicator. */
70 #define M_FREEFLAG 0xa5
71 /* End-of-block if debug level */
72 #define M_FREE 0x9cc99cc9
73 /* Zero length block. */
74 #define M_ZEROFLAG 0xaa
75 
76 /* Header of a memory block. */
77 typedef unsigned char DATA_T;
78 typedef DATA_T *      DATA_P;
79 struct M_HEADER
80 {
81   unsigned       dbglev:2;       /* Debug level this was created with. */
82   unsigned       size:22;        /* Size of block / 8. 32 Meg max. */
83   unsigned       flag:8;         /* Indicates whether allocated or freed. */
84 };
85 typedef struct M_HEADER* M_HEADERP;
86 
isalloced(M_HEADERP this)87 BOOLEAN isalloced(M_HEADERP this)
88 {
89   return this->flag == M_ALLOCEDFLAG;
90 }
isfree(M_HEADERP this)91 BOOLEAN isfree(M_HEADERP this)
92 {
93   return this->flag == M_FREEFLAG;
94 }
iszero(M_HEADERP this)95 BOOLEAN iszero(M_HEADERP this)
96 {
97   return this->flag == M_ZEROFLAG;
98 }
99 
setalloced(M_HEADERP this)100 void           setalloced(M_HEADERP this)     { this->flag = M_ALLOCEDFLAG; }
setfree(M_HEADERP this)101 void           setfree(M_HEADERP this)        { this->flag = M_FREEFLAG; }
setzero(M_HEADERP this)102 void           setzero(M_HEADERP this)        { this->flag = M_ZEROFLAG; }
103 
getdbglev(M_HEADERP this)104 int            getdbglev(M_HEADERP this)      { return this->dbglev; }
setdbglev(M_HEADERP this,int d)105 void           setdbglev(M_HEADERP this, int d) { this->dbglev = d; }
106 
getsize(M_HEADERP this)107 size_t         getsize(M_HEADERP this)        { return this->size << 3; }  /* Alignment is 8. */
setsize(M_HEADERP this,size_t s)108 void           setsize(M_HEADERP this, size_t s){ this->size = s >> 3; }
109 
getend(M_HEADERP this)110 DATA_T *       getend(M_HEADERP this)         { return (((DATA_T *)this)+getsize(this)); }
111 
112 /* Next pointer is after data in block. */
getnext(M_HEADERP this)113 M_HEADERP     getnext(M_HEADERP this)        { return *(((M_HEADERP*)getend(this)) - 1); }
setnext(M_HEADERP this,M_HEADERP n)114 void           setnext(M_HEADERP this, M_HEADERP n) { *(((M_HEADERP*)getend(this)) - 1) = n; }
115 
116 /* Routines used to set a flag at end of block if debuglevel != normal. */
117 /* Sentinel is right BEFORE the next pointer. */
118 unsigned long* getsentinel(M_HEADERP this);
119 void           setsentinel(M_HEADERP this, unsigned long lflag);
120 BOOLEAN        testsentinel(M_HEADERP this, unsigned long lflag);
121 
122 /* Routines to handle data.  Depend on debug level. */
getdata(M_HEADERP this)123 DATA_T *       getdata(M_HEADERP this)        { return (((DATA_T*)this)+sizeof(*this)); }
124 size_t         getdatasize(M_HEADERP this);
125 
126 /* Fill data with a pattern. */
127 void           setdata(M_HEADERP this, int f);
128 
129 /* Debug routines */
130 BOOLEAN        checkalloc(M_HEADERP this);    /* Is this a valid allocated memory pointer? */
131 BOOLEAN        checkfree(M_HEADERP this);     /* Is this a valid freelist entry? */
132 
133 
134 
135 /* Get length of data. */
136 size_t
getdatasize(M_HEADERP this)137 getdatasize(M_HEADERP this)
138 {
139   /* By default, size is size of block - size of header. */
140   int tmp_size = getsize(this) - sizeof(struct M_HEADER);
141 
142   if (this->dbglev != M_DBG_NORMAL)
143     {
144       /* Subtract size of sentinel, and next pointer. */
145       tmp_size -= sizeof(long) + sizeof(M_HEADERP);
146       /* If only eight bytes, no room for sentinel. */
147       if (tmp_size < 0)
148         tmp_size = 0;
149     }
150   else
151     {
152       /* Free block always has a next pointer.  Otherwise not. */
153       if (isfree(this))
154         tmp_size -= sizeof(M_HEADERP);
155     }
156   return tmp_size;
157 }
158 
159 /* Set the data buffer to value f. */
160 void
setdata(M_HEADERP this,int f)161 setdata(M_HEADERP this, int f)
162 {
163   memset(getdata(this), f, getdatasize(this));
164 }
165 
166 /* At the end of the block, there may be a longword with
167    special meaning.  This is the sentinel.  If there is a sentinel,
168    there is by definition a next pointer. */
169 unsigned long*
getsentinel(M_HEADERP this)170 getsentinel(M_HEADERP this)
171 {
172   DATA_T* addr = (getend(this) - sizeof(M_HEADERP)); /* location of next pointer. */
173   if (getdata(this) < addr)
174     return ((unsigned long*)addr) - 1;        /* Right before next pointer. */
175   else
176     return NULL;                      /* Block too small.  No room for sent. */
177 }
178 
179 void
setsentinel(M_HEADERP this,unsigned long lflag)180 setsentinel(M_HEADERP this, unsigned long lflag)
181 {
182   unsigned long* addr = getsentinel(this);
183   if (addr)
184     *addr = lflag;
185 }
186 
187 BOOLEAN
testsentinel(M_HEADERP this,unsigned long lflag)188 testsentinel(M_HEADERP this, unsigned long lflag)
189 {
190   unsigned long* addr = getsentinel(this);
191   if (addr)
192     return *addr == lflag;
193   else
194     return TRUE;
195 }
196 
197 /*  sizeof(struct M_HEADER)+sizeof(M_HEADERP);  Alignment */
198 #define M_BLOCKSIZE 8
199 /*  4096 / 8; // M_BLOCKSIZE ;      Number of freelist entries. */
200 #define M_FREESIZE 512
201 /*  64 * 1024;                 Size of incremental memory hunks allocated, */
202 #define M_BRKINC 2048
203 
204 static M_HEADERP freelist[M_FREESIZE];       /* Free list. */
205 
206 static M_HEADERP alloclist = NULL;           /* Pointer to linked list
207                                                 of Allocated blocks. */
208 static int mdebuglevel = M_DBG_NORMAL;
209 
210 static DATA_T zerobuf[M_BLOCKSIZE] = { M_ZEROFLAG, M_ZEROFLAG, M_ZEROFLAG,
211                                        M_ZEROFLAG, M_ZEROFLAG, M_ZEROFLAG,
212                                        M_ZEROFLAG, M_ZEROFLAG };
213 static M_HEADERP zeroblock = (M_HEADERP)zerobuf;
214 
215 static unsigned long totalallocated = 0;        /* NOT actually malloced, but
216                                                    rather the size of the pool. */
217 
218 static unsigned long totalmalloc = 0;           /* Total amount malloced. */
219 
220 static unsigned long highwater = 0;             /* Largest amount of memory
221                                                    allocated at any time. */
222 static long nummallocs = 0;
223 static long numfrees = 0;
224 static long numreallocs = 0;
225 
226 int m_prtflag  = 0;
227 int m_stopaddr = 0;
228 int m_stopcnt  = 0;
229 int m_reenter  = 0;
230 static int m_curcount = 0;
231 
232 M_HEADERP
getmemblock(size_t n)233 getmemblock(size_t n)
234 {
235   M_HEADERP block = (M_HEADERP) sbrk(n);
236   if (block != NULL)
237     totalallocated += n;
238 
239   return block;
240 }
241 
242 
243 static BOOLEAN
die(char * msg)244 die (char* msg)
245 {
246   mdebuglevel = M_DBG_NORMAL;
247 #ifdef DEBUG
248   printf ("%s\n", msg);
249   exit (1);
250 #else
251   /* Go into infinite loop. */
252   for (;;)
253     ;
254 #endif
255   return FALSE;
256 }
257 
258 int
getfreeindex(size_t size)259 getfreeindex(size_t size)
260 {
261   return MIN(size / M_BLOCKSIZE, M_FREESIZE - 1);
262 }
263 
264 static
coalesce(M_HEADERP h)265 void coalesce(M_HEADERP h)
266 {
267   /* Coalesce block h with free block any free blocks after it.
268      Assumes that H is currently allocated.  Sentinel at end is
269      set to allocated so if H is free, caller has to fix it. */
270   for (;;)
271     {
272       long i;
273       M_HEADERP f;
274       M_HEADERP next = (M_HEADERP)getend(h);
275 
276       if (next || isalloced(next))
277         break; /* no more coalscing can be done. */
278 
279       /* Take it off the free list. */
280       i = getfreeindex(getsize(next));
281       f = freelist[i];
282       if (f == next)
283         freelist[i] = getnext(next);
284       else
285 	{
286           while (f != NULL && getnext(f) != next)
287             f = getnext(f);
288 
289           /* Didn't find it in the free list. */
290           if (f == NULL)
291             die ("Coalesce failed.");
292 
293           setnext(f, getnext(next));
294         }
295 
296       /* Add two blocks together and start over. */
297       setsize(h, getsize(h) + getsize(next));
298 
299       if (getdbglev(h) > M_DBG_NORMAL)
300 	{
301           setsentinel(h, M_ALLOCED);
302         }
303     } /* forever */
304 }
305 
306 BOOLEAN
checkalloc(M_HEADERP this)307 checkalloc(M_HEADERP this)
308 {
309   if (!isalloced(this))
310     return die ("checkalloc: pointer header clobbered.");
311 
312   if (getdbglev(this) > M_DBG_NORMAL)
313     {
314       if (!testsentinel(this, M_ALLOCED))
315         return die ("checkalloc: pointer length overrun.");
316     }
317   return TRUE;
318 }
319 
320 BOOLEAN
checkfree(M_HEADERP this)321 checkfree(M_HEADERP this)
322 {
323   DATA_T *d;
324   int i;
325   if (!isfree(this))
326     die ("checkfree: pointer header clobbered.");
327 
328   if (getdbglev(this) > M_DBG_NORMAL)
329     {
330       if (!testsentinel(this, M_FREE))
331         die ("checkfree: pointer length overrun.");
332 
333       d = getdata(this);
334       i = getdatasize(this);
335       while (i-- > 0) {
336         if (*d++ != M_FREEFLAG)
337           die("checkfree: freed data clobbered.");
338       }
339     }
340   return TRUE;
341 }
342 
343 static void
checkfreelist()344 checkfreelist()
345 {
346   long i;
347   for (i = 0; i < M_FREESIZE; i += 1)
348     {
349       M_HEADERP h = (M_HEADERP) freelist[i];
350       while (h != NULL)
351         {
352         checkfree(h);
353         if (i != (M_FREESIZE - 1) && getsize(h) != (i * M_BLOCKSIZE))
354           die ("checkfreelist: free list size mismatch.");
355         h = getnext(h);
356         }
357     }
358 }
359 
360 static void
checkalloclist()361 checkalloclist()
362 {
363   M_HEADERP a = (M_HEADERP) alloclist;
364   while (a != NULL)
365     {
366       checkalloc(a);
367       a = getnext(a);
368     }
369 }
370 
371 /* Free a block of memory.  This is done by adding to the free list. */
372 static void
addtofreelist(M_HEADERP h)373 addtofreelist (M_HEADERP h)
374 {
375   long i;
376   /* Merge freed blocks together. */
377   coalesce(h);
378 
379   /* link this block to the front of the appropriate free list. */
380   i = getfreeindex(getsize(h));
381   setnext(h, freelist[i]);
382   freelist[i] = h;
383 
384   /* Set the flag info. */
385   setfree(h);
386   setdbglev(h, mdebuglevel);
387   if (mdebuglevel > M_DBG_NORMAL)
388     {
389       /* Fill with some meaningful (and testable) data. */
390       setdata(h, M_FREEFLAG);
391       setsentinel(h, M_FREE);
392     }
393 }
394 
395 void
xil_malloc_verify()396 xil_malloc_verify()
397 {
398   int i;
399   for ( i = 0; i < M_BLOCKSIZE; i += 1)
400     {
401       if (zerobuf[i] != M_ZEROFLAG)
402         die ("malloc_verify: Zero block clobbered.");
403     }
404   checkfreelist();
405   checkalloclist();
406 }
407 
408 void
xil_malloc_debug(int level)409 xil_malloc_debug (int level)
410 {
411   mdebuglevel = MAX (M_DBG_NORMAL, MIN (M_DBG_FULL, level));
412 }
413 
414 void*
xil_malloc(size_t nbytes)415 xil_malloc (size_t nbytes)
416 {
417   int i;
418   int minf;
419   int maxf;
420   size_t msize;
421   M_HEADERP p;
422   M_HEADERP h;
423 
424   nummallocs += 1;
425 
426   if (nbytes == 0)
427     return getdata(zeroblock);
428 
429   if (mdebuglevel == M_DBG_FULL)
430     {
431 #ifdef DEBUG
432       static unsigned do_cnt = ~0;
433       static unsigned done_cnt = 0;
434       if (do_cnt == ~0)
435 	{
436           char *x = (char *)getenv(xil_mem_chkcnt);
437           do_cnt = 1;
438           if (x)
439             do_cnt = atoi(x);
440         }
441       if (do_cnt == 1 || done_cnt % do_cnt == 0)
442         xil_malloc_verify();
443       done_cnt++;
444 #else
445       xil_malloc_verify();
446 #endif
447     }
448 
449   nbytes += sizeof (struct M_HEADER);
450 
451   /* If debug, leave room for flag and next pointer. */
452   if (mdebuglevel > M_DBG_NORMAL)
453     nbytes += sizeof (long) + sizeof (M_HEADERP*);
454 
455   /* Round up to allocation unit */
456   msize = ((nbytes + M_BLOCKSIZE - 1) / M_BLOCKSIZE) * M_BLOCKSIZE;
457 
458   /* Look around for a block of approximately the right size. */
459   h = NULL;
460   minf = getfreeindex(msize);
461   maxf = MIN(minf * 2, M_FREESIZE);
462 
463   for (i = minf; i < M_FREESIZE; i += 1)
464     {
465       if (i >= maxf)
466         i = M_FREESIZE - 1;    /* Skip over blocks too large. */
467 
468       h = freelist[i];
469       p = NULL;       /* Previous. */
470       while (h != NULL)
471 	{
472           if (getsize(h) >= nbytes)
473 	    {
474               /* Take h out of linked list */
475               if (p)
476                 setnext(p, getnext(h));
477               else
478                 freelist[i] = getnext(h);
479 
480               if (!isfree(h))
481                 die ("malloc: freelist clobbered.\n");
482 
483               goto gotit;
484             }
485           else
486 	    {
487               p = h;
488               h = getnext(h);
489             }
490         }
491     }
492 
493   /* Didn't find any free pointers.  Allocate more heap.
494      Round up to next heap increment. */
495   i = ((msize + sizeof(long) + M_BRKINC - 1) / M_BRKINC) * M_BRKINC;
496   if ((h = getmemblock (i)) == NULL)
497     {
498 #ifdef DEBUG
499       printf ("xil_malloc: Out of dynamic memory.\n");
500 #endif
501       return NULL;
502     }
503 
504   /* Mark end of block with zero for four bytes so we don't merge next block
505      into free list accidentally. */
506   setsize(h, i - sizeof(long));
507   *((long*)getend(h)) = 0;
508 
509  gotit:
510   /* Merge allocated blocks so we can free a bigger part of what is left! */
511   coalesce(h);
512   if (getsize(h) >= msize + M_BLOCKSIZE)
513     {
514       M_HEADERP r;
515       int rsize;
516       /* add the remainder of this block to the free list. */
517       rsize = getsize(h) - msize;
518       r = (M_HEADERP) (((DATA_T *)h) + msize);
519       setsize (r, rsize);
520       setsize (h, msize);
521       addtofreelist (r);
522     }
523 
524   setalloced(h);
525   setdbglev(h, mdebuglevel);
526   if (mdebuglevel > M_DBG_NORMAL)
527     {
528       // Chain into alloc'd list and set sentinel. */
529       setsentinel(h, M_ALLOCED);
530       setnext(h, alloclist);
531       alloclist = h;
532     }
533 
534 #ifdef DEBUG
535   if (!m_reenter && m_prtflag)
536     {
537       m_reenter = 1;
538       printf("%d      malloc\n",h+1);
539       fflush(stdout);
540       if (m_stopaddr)
541         {
542           if ((DATA_T *)m_stopaddr == getdata(h))
543             {
544               if (m_stopcnt == ++m_curcount)
545                 exit(10);
546             }
547         }
548       m_reenter = 0;
549     }
550 #endif
551 
552   totalmalloc += getsize(h);
553   if (totalmalloc > highwater)
554     highwater = totalmalloc;
555 
556   return getdata(h);
557 }
558 
559 void
xil_free(void * ap)560 xil_free(void* ap)
561 {
562   M_HEADERP h;
563   numfrees += 1;
564 
565   if (ap == NULL)
566    {
567 #ifdef DEBUG
568      if (mdebuglevel != M_DBG_NORMAL && getenv(xil_mem_null_free))
569        die ("free: tried to free NULL pointer.");
570      else
571        return;        /* Let `em do it. */
572 #else
573      return;
574 #endif
575    }
576 
577   /* Drop through to here if not a smartheap allocation.  This
578      handles free of both xil_malloc and libc malloc. */
579 
580   h = (M_HEADERP) (((DATA_T *)ap) - sizeof (struct M_HEADER));
581 
582   if (h == zeroblock)
583     return;
584 
585 #ifdef DEBUG
586   if (!m_reenter && m_prtflag) {
587     m_reenter = 1;
588     printf("%d      mfree\n",h+1);
589     fflush(stdout);
590     m_reenter = 0;
591   }
592 #endif
593 
594   if (!isalloced(h)) {
595     if (isfree(h))
596       die ("free: tried to free pointer twice.");
597     else
598       die ("free: tried to free a block not allocated by malloc.");
599     return;
600   }
601 
602   if (getdbglev(h) > M_DBG_NORMAL)
603     {
604       /* Make sure things look reasonable. */
605       checkalloc(h);
606 
607       /* Try to find the pointer in the alloc list. */
608       if (alloclist == h)
609         alloclist = getnext(h);
610       else
611 	{
612           M_HEADERP a = alloclist;
613           while (a != NULL && getnext(a) != h)
614             a = getnext(a);
615 
616           /* If a is NULL, debuglevel must have been reset at some point. */
617           if (a != NULL)
618             setnext(a, getnext(h));
619         }
620     }
621 
622   totalmalloc -= getsize(h);
623 
624   addtofreelist (h);
625 
626   if (mdebuglevel == M_DBG_FULL)
627     {
628 #ifdef DEBUG
629       static unsigned do_cnt = ~0;
630       static unsigned done_cnt = 0;
631       if (do_cnt == ~0)
632 	{
633           char *x = (char *)getenv(xil_mem_chkcnt);
634           do_cnt = 1;
635           if (x)
636             do_cnt = atoi(x);
637         }
638       if (do_cnt == 1 || done_cnt % do_cnt == 0)
639         xil_malloc_verify();
640       done_cnt++;
641 #else
642       xil_malloc_verify();
643 #endif
644     }
645 }
646 
647 unsigned
xil_msize(void * ap)648 xil_msize (void* ap)
649 {
650   M_HEADERP h = (M_HEADERP) (((DATA_T *)ap) - sizeof (struct M_HEADER));
651   return getdatasize(h);
652 }
653 
654 void*
xil_realloc(void * oldblk,size_t newsize)655 xil_realloc (void* oldblk, size_t newsize )
656 {
657   M_HEADERP h;
658   size_t oldsize;
659   void* newblk;
660 
661   numreallocs += 1;
662 
663   if (oldblk == NULL)
664     {
665       if (mdebuglevel != M_DBG_NORMAL)
666         die ("realloc: tried to realloc NULL pointer.");
667       else
668         return xil_malloc(newsize);        /* Don't need to copy anything. */
669     }
670 
671   /* Make sure this is a valid block. */
672   h = (M_HEADERP) (((char*)oldblk) - sizeof (struct M_HEADER));
673 
674   /* if old block was zero bytes, just alloc a new one. */
675   if (h == zeroblock)
676     return xil_malloc(newsize);           /* Source is empty anyway. */
677 
678   /* If old block was already freed, error. */
679   if (isfree(h))
680     die ("realloc: tried to realloc freed pointer.");
681 
682   if (!isalloced(h))
683     {
684       long* pdesc = *(long**)h;         /* Get pointer to the block descriptor. */
685       long* pnextdesc = (long*)*pdesc;
686       if ((pdesc[1] & ~3) != (long)h)   /* Should point back to block. */
687         die ("realloc: header clobbered.");
688 
689       /* This must be a libc block.  We need to figure out how big it is.
690          Length of block is delta between two descriptors - sizeof (void*). */
691 
692       oldsize = (size_t) ((pnextdesc[1] & ~3) - (pdesc[1] & ~3)-sizeof(void*));
693 
694       /* Don't bother to change anything unless there's not enough room. */
695       if (oldsize < newsize)
696 	{
697           /* Alloc a new block with our malloc. */
698           if ((newblk = xil_malloc(newsize)) == NULL )
699             return NULL ;
700 
701           /* Copy the old data to it. */
702           memcpy (newblk, oldblk, (newsize < oldsize) ? newsize : oldsize);
703           xil_free(oldblk);
704           return newblk;
705         }
706     }
707 
708   /* If the new size is bigger than my allocated
709      size, or if more than 1/4 of the block would be left free, allocate
710      a new block and copy the data.  Otherwise, leave well enough alone. */
711 
712   coalesce(h);
713 
714   oldsize = getdatasize(h);
715 
716   if (oldsize < newsize
717       || (newsize > (2*M_BLOCKSIZE) && (newsize*4) < (oldsize*3)))
718     {
719       if (( newblk = xil_malloc( newsize )) == NULL )
720         return NULL ;
721 
722       memcpy (newblk, oldblk, (newsize < oldsize) ? newsize : oldsize);
723 
724       xil_free (oldblk);
725       return newblk;
726     }
727   else
728     return oldblk;
729 }
730 
731 void*
xil_calloc(size_t number,size_t size)732 xil_calloc (size_t number, size_t size)
733 {
734   long*  longptr ;
735   void*  blockptr ;
736   size_t temp   = number * size + sizeof (long) - 1;
737   temp -= temp % sizeof (long);
738 
739   blockptr = xil_malloc( temp );
740   if ( blockptr != 0 )
741     {
742       longptr = (long*) blockptr ;
743       temp /= sizeof (long);
744       while ( temp-- > 0 )
745 	{
746           *longptr++ = 0 ;
747         }
748     }
749   return blockptr ;
750 }
751 
752 #define M_STAT_NORMAL 0
753 #define M_STAT_VERBOSE 1
754 #define M_STAT_REALLYVERBOSE 2
755 
756 #ifdef DEBUG
757 void
xil_mstats(int verbosity)758 xil_mstats(int verbosity)
759 {
760   unsigned long totalfree = 0;
761   int i;
762   printf("Memory Statics:\n"
763          "---------------\n");
764   printf("   Number of calls to malloc:   %ld.\n", nummallocs);
765   printf("   Number of calls to free:     %ld.\n", numfrees);
766   printf("   Number of calls to realloc:  %ld.\n", numreallocs);
767   printf("   Total allocated memory:      %lu (0x%lx)\n",
768          totalallocated, totalallocated);
769   printf("   Currently malloced memory:   %lu (0x%lx)\n",
770          totalmalloc, totalmalloc);
771   fflush(stdout);
772 
773 
774   for (i = 0; i < M_FREESIZE; i += 1)
775     {
776       M_HEADERP h = freelist[i];
777       unsigned long numblocks = 0;
778       while (h != NULL)
779 	{
780           totalfree += getsize(h);
781           numblocks += 1;
782           h = getnext(h);
783         }
784       if (verbosity > M_STAT_NORMAL && numblocks > 0)
785 	{
786           printf("   There are %d blocks on freelist for size %d\n",
787                  numblocks, i * M_BLOCKSIZE);
788           fflush(stdout);
789         }
790     }
791   printf("   Currently free memory:       %lu (0x%lx)\n",
792          totalfree, totalfree);
793   printf("   High water mark:             %lu (0x%lx)\n",
794          highwater, highwater);
795 
796   printf("\n");
797   fflush(stdout);
798 }
799 #else
800 void
xil_mstats(int verbosity)801 xil_mstats(int verbosity)
802 {
803 }
804 #endif
805