Cygwin: dirent.h: fix a comment
[newlib-cygwin.git] / libgloss / microblaze / xil_malloc.c
blobdac31ea620e8ebf855ff0ec13a7d2bb69adf01e5
1 /* Copyright (c) 1995, 2002, 2009 Xilinx, Inc. All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions are
5 met:
7 1. Redistributions source code must retain the above copyright notice,
8 this list of conditions and the following disclaimer.
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.
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.
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.
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
41 #define sbrk xil_sbrk
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);
49 typedef unsigned char BOOLEAN;
50 const BOOLEAN FALSE=0;
51 const BOOLEAN TRUE =1;
53 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
54 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
56 #define M_DBG_NORMAL 0
57 #define M_DBG_PARTIAL 1
58 #define M_DBG_FULL 2
60 /* debugging breakpoint aids */
61 static char xil_mem_null_free[] = "xil_mem_null_free";
62 static char xil_mem_chkcnt [] = "xil_mem_chkcnt";
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
76 /* Header of a memory block. */
77 typedef unsigned char DATA_T;
78 typedef DATA_T * DATA_P;
79 struct M_HEADER
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. */
85 typedef struct M_HEADER* M_HEADERP;
87 BOOLEAN isalloced(M_HEADERP this)
89 return this->flag == M_ALLOCEDFLAG;
91 BOOLEAN isfree(M_HEADERP this)
93 return this->flag == M_FREEFLAG;
95 BOOLEAN iszero(M_HEADERP this)
97 return this->flag == M_ZEROFLAG;
100 void setalloced(M_HEADERP this) { this->flag = M_ALLOCEDFLAG; }
101 void setfree(M_HEADERP this) { this->flag = M_FREEFLAG; }
102 void setzero(M_HEADERP this) { this->flag = M_ZEROFLAG; }
104 int getdbglev(M_HEADERP this) { return this->dbglev; }
105 void setdbglev(M_HEADERP this, int d) { this->dbglev = d; }
107 size_t getsize(M_HEADERP this) { return this->size << 3; } /* Alignment is 8. */
108 void setsize(M_HEADERP this, size_t s){ this->size = s >> 3; }
110 DATA_T * getend(M_HEADERP this) { return (((DATA_T *)this)+getsize(this)); }
112 /* Next pointer is after data in block. */
113 M_HEADERP getnext(M_HEADERP this) { return *(((M_HEADERP*)getend(this)) - 1); }
114 void setnext(M_HEADERP this, M_HEADERP n) { *(((M_HEADERP*)getend(this)) - 1) = n; }
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);
122 /* Routines to handle data. Depend on debug level. */
123 DATA_T * getdata(M_HEADERP this) { return (((DATA_T*)this)+sizeof(*this)); }
124 size_t getdatasize(M_HEADERP this);
126 /* Fill data with a pattern. */
127 void setdata(M_HEADERP this, int f);
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? */
135 /* Get length of data. */
136 size_t
137 getdatasize(M_HEADERP this)
139 /* By default, size is size of block - size of header. */
140 int tmp_size = getsize(this) - sizeof(struct M_HEADER);
142 if (this->dbglev != M_DBG_NORMAL)
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;
150 else
152 /* Free block always has a next pointer. Otherwise not. */
153 if (isfree(this))
154 tmp_size -= sizeof(M_HEADERP);
156 return tmp_size;
159 /* Set the data buffer to value f. */
160 void
161 setdata(M_HEADERP this, int f)
163 memset(getdata(this), f, getdatasize(this));
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*
170 getsentinel(M_HEADERP this)
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. */
179 void
180 setsentinel(M_HEADERP this, unsigned long lflag)
182 unsigned long* addr = getsentinel(this);
183 if (addr)
184 *addr = lflag;
187 BOOLEAN
188 testsentinel(M_HEADERP this, unsigned long lflag)
190 unsigned long* addr = getsentinel(this);
191 if (addr)
192 return *addr == lflag;
193 else
194 return TRUE;
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
204 static M_HEADERP freelist[M_FREESIZE]; /* Free list. */
206 static M_HEADERP alloclist = NULL; /* Pointer to linked list
207 of Allocated blocks. */
208 static int mdebuglevel = M_DBG_NORMAL;
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;
215 static unsigned long totalallocated = 0; /* NOT actually malloced, but
216 rather the size of the pool. */
218 static unsigned long totalmalloc = 0; /* Total amount malloced. */
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;
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;
232 M_HEADERP
233 getmemblock(size_t n)
235 M_HEADERP block = (M_HEADERP) sbrk(n);
236 if (block != NULL)
237 totalallocated += n;
239 return block;
243 static BOOLEAN
244 die (char* msg)
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 (;;)
254 #endif
255 return FALSE;
258 int
259 getfreeindex(size_t size)
261 return MIN(size / M_BLOCKSIZE, M_FREESIZE - 1);
264 static
265 void coalesce(M_HEADERP h)
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 (;;)
272 long i;
273 M_HEADERP f;
274 M_HEADERP next = (M_HEADERP)getend(h);
276 if (next || isalloced(next))
277 break; /* no more coalscing can be done. */
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
286 while (f != NULL && getnext(f) != next)
287 f = getnext(f);
289 /* Didn't find it in the free list. */
290 if (f == NULL)
291 die ("Coalesce failed.");
293 setnext(f, getnext(next));
296 /* Add two blocks together and start over. */
297 setsize(h, getsize(h) + getsize(next));
299 if (getdbglev(h) > M_DBG_NORMAL)
301 setsentinel(h, M_ALLOCED);
303 } /* forever */
306 BOOLEAN
307 checkalloc(M_HEADERP this)
309 if (!isalloced(this))
310 return die ("checkalloc: pointer header clobbered.");
312 if (getdbglev(this) > M_DBG_NORMAL)
314 if (!testsentinel(this, M_ALLOCED))
315 return die ("checkalloc: pointer length overrun.");
317 return TRUE;
320 BOOLEAN
321 checkfree(M_HEADERP this)
323 DATA_T *d;
324 int i;
325 if (!isfree(this))
326 die ("checkfree: pointer header clobbered.");
328 if (getdbglev(this) > M_DBG_NORMAL)
330 if (!testsentinel(this, M_FREE))
331 die ("checkfree: pointer length overrun.");
333 d = getdata(this);
334 i = getdatasize(this);
335 while (i-- > 0) {
336 if (*d++ != M_FREEFLAG)
337 die("checkfree: freed data clobbered.");
340 return TRUE;
343 static void
344 checkfreelist()
346 long i;
347 for (i = 0; i < M_FREESIZE; i += 1)
349 M_HEADERP h = (M_HEADERP) freelist[i];
350 while (h != NULL)
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);
360 static void
361 checkalloclist()
363 M_HEADERP a = (M_HEADERP) alloclist;
364 while (a != NULL)
366 checkalloc(a);
367 a = getnext(a);
371 /* Free a block of memory. This is done by adding to the free list. */
372 static void
373 addtofreelist (M_HEADERP h)
375 long i;
376 /* Merge freed blocks together. */
377 coalesce(h);
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;
384 /* Set the flag info. */
385 setfree(h);
386 setdbglev(h, mdebuglevel);
387 if (mdebuglevel > M_DBG_NORMAL)
389 /* Fill with some meaningful (and testable) data. */
390 setdata(h, M_FREEFLAG);
391 setsentinel(h, M_FREE);
395 void
396 xil_malloc_verify()
398 int i;
399 for ( i = 0; i < M_BLOCKSIZE; i += 1)
401 if (zerobuf[i] != M_ZEROFLAG)
402 die ("malloc_verify: Zero block clobbered.");
404 checkfreelist();
405 checkalloclist();
408 void
409 xil_malloc_debug (int level)
411 mdebuglevel = MAX (M_DBG_NORMAL, MIN (M_DBG_FULL, level));
414 void*
415 xil_malloc (size_t nbytes)
417 int i;
418 int minf;
419 int maxf;
420 size_t msize;
421 M_HEADERP p;
422 M_HEADERP h;
424 nummallocs += 1;
426 if (nbytes == 0)
427 return getdata(zeroblock);
429 if (mdebuglevel == M_DBG_FULL)
431 #ifdef DEBUG
432 static unsigned do_cnt = ~0;
433 static unsigned done_cnt = 0;
434 if (do_cnt == ~0)
436 char *x = (char *)getenv(xil_mem_chkcnt);
437 do_cnt = 1;
438 if (x)
439 do_cnt = atoi(x);
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
449 nbytes += sizeof (struct M_HEADER);
451 /* If debug, leave room for flag and next pointer. */
452 if (mdebuglevel > M_DBG_NORMAL)
453 nbytes += sizeof (long) + sizeof (M_HEADERP*);
455 /* Round up to allocation unit */
456 msize = ((nbytes + M_BLOCKSIZE - 1) / M_BLOCKSIZE) * M_BLOCKSIZE;
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);
463 for (i = minf; i < M_FREESIZE; i += 1)
465 if (i >= maxf)
466 i = M_FREESIZE - 1; /* Skip over blocks too large. */
468 h = freelist[i];
469 p = NULL; /* Previous. */
470 while (h != NULL)
472 if (getsize(h) >= nbytes)
474 /* Take h out of linked list */
475 if (p)
476 setnext(p, getnext(h));
477 else
478 freelist[i] = getnext(h);
480 if (!isfree(h))
481 die ("malloc: freelist clobbered.\n");
483 goto gotit;
485 else
487 p = h;
488 h = getnext(h);
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)
498 #ifdef DEBUG
499 printf ("xil_malloc: Out of dynamic memory.\n");
500 #endif
501 return NULL;
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;
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)
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);
524 setalloced(h);
525 setdbglev(h, mdebuglevel);
526 if (mdebuglevel > M_DBG_NORMAL)
528 // Chain into alloc'd list and set sentinel. */
529 setsentinel(h, M_ALLOCED);
530 setnext(h, alloclist);
531 alloclist = h;
534 #ifdef DEBUG
535 if (!m_reenter && m_prtflag)
537 m_reenter = 1;
538 printf("%d malloc\n",h+1);
539 fflush(stdout);
540 if (m_stopaddr)
542 if ((DATA_T *)m_stopaddr == getdata(h))
544 if (m_stopcnt == ++m_curcount)
545 exit(10);
548 m_reenter = 0;
550 #endif
552 totalmalloc += getsize(h);
553 if (totalmalloc > highwater)
554 highwater = totalmalloc;
556 return getdata(h);
559 void
560 xil_free(void* ap)
562 M_HEADERP h;
563 numfrees += 1;
565 if (ap == NULL)
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
577 /* Drop through to here if not a smartheap allocation. This
578 handles free of both xil_malloc and libc malloc. */
580 h = (M_HEADERP) (((DATA_T *)ap) - sizeof (struct M_HEADER));
582 if (h == zeroblock)
583 return;
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;
592 #endif
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;
602 if (getdbglev(h) > M_DBG_NORMAL)
604 /* Make sure things look reasonable. */
605 checkalloc(h);
607 /* Try to find the pointer in the alloc list. */
608 if (alloclist == h)
609 alloclist = getnext(h);
610 else
612 M_HEADERP a = alloclist;
613 while (a != NULL && getnext(a) != h)
614 a = getnext(a);
616 /* If a is NULL, debuglevel must have been reset at some point. */
617 if (a != NULL)
618 setnext(a, getnext(h));
622 totalmalloc -= getsize(h);
624 addtofreelist (h);
626 if (mdebuglevel == M_DBG_FULL)
628 #ifdef DEBUG
629 static unsigned do_cnt = ~0;
630 static unsigned done_cnt = 0;
631 if (do_cnt == ~0)
633 char *x = (char *)getenv(xil_mem_chkcnt);
634 do_cnt = 1;
635 if (x)
636 do_cnt = atoi(x);
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
647 unsigned
648 xil_msize (void* ap)
650 M_HEADERP h = (M_HEADERP) (((DATA_T *)ap) - sizeof (struct M_HEADER));
651 return getdatasize(h);
654 void*
655 xil_realloc (void* oldblk, size_t newsize )
657 M_HEADERP h;
658 size_t oldsize;
659 void* newblk;
661 numreallocs += 1;
663 if (oldblk == NULL)
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. */
671 /* Make sure this is a valid block. */
672 h = (M_HEADERP) (((char*)oldblk) - sizeof (struct M_HEADER));
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. */
678 /* If old block was already freed, error. */
679 if (isfree(h))
680 die ("realloc: tried to realloc freed pointer.");
682 if (!isalloced(h))
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.");
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*). */
692 oldsize = (size_t) ((pnextdesc[1] & ~3) - (pdesc[1] & ~3)-sizeof(void*));
694 /* Don't bother to change anything unless there's not enough room. */
695 if (oldsize < newsize)
697 /* Alloc a new block with our malloc. */
698 if ((newblk = xil_malloc(newsize)) == NULL )
699 return NULL ;
701 /* Copy the old data to it. */
702 memcpy (newblk, oldblk, (newsize < oldsize) ? newsize : oldsize);
703 xil_free(oldblk);
704 return newblk;
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. */
712 coalesce(h);
714 oldsize = getdatasize(h);
716 if (oldsize < newsize
717 || (newsize > (2*M_BLOCKSIZE) && (newsize*4) < (oldsize*3)))
719 if (( newblk = xil_malloc( newsize )) == NULL )
720 return NULL ;
722 memcpy (newblk, oldblk, (newsize < oldsize) ? newsize : oldsize);
724 xil_free (oldblk);
725 return newblk;
727 else
728 return oldblk;
731 void*
732 xil_calloc (size_t number, size_t size)
734 long* longptr ;
735 void* blockptr ;
736 size_t temp = number * size + sizeof (long) - 1;
737 temp -= temp % sizeof (long);
739 blockptr = xil_malloc( temp );
740 if ( blockptr != 0 )
742 longptr = (long*) blockptr ;
743 temp /= sizeof (long);
744 while ( temp-- > 0 )
746 *longptr++ = 0 ;
749 return blockptr ;
752 #define M_STAT_NORMAL 0
753 #define M_STAT_VERBOSE 1
754 #define M_STAT_REALLYVERBOSE 2
756 #ifdef DEBUG
757 void
758 xil_mstats(int verbosity)
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);
774 for (i = 0; i < M_FREESIZE; i += 1)
776 M_HEADERP h = freelist[i];
777 unsigned long numblocks = 0;
778 while (h != NULL)
780 totalfree += getsize(h);
781 numblocks += 1;
782 h = getnext(h);
784 if (verbosity > M_STAT_NORMAL && numblocks > 0)
786 printf(" There are %d blocks on freelist for size %d\n",
787 numblocks, i * M_BLOCKSIZE);
788 fflush(stdout);
791 printf(" Currently free memory: %lu (0x%lx)\n",
792 totalfree, totalfree);
793 printf(" High water mark: %lu (0x%lx)\n",
794 highwater, highwater);
796 printf("\n");
797 fflush(stdout);
799 #else
800 void
801 xil_mstats(int verbosity)
804 #endif