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