1 /*****************************************************************************
3 * Dynamic Memory Allocation
5 * Author: Daniel Stenberg
8 * Email: Daniel.Stenberg@sth.frontec.se
11 * Read 'thoughts' for theories and details of this implementation.
14 * - I once again managed to gain some memory. BLOCK allocations now only use
15 * a 4 bytes header (instead of previos 8) just as FRAGMENTS.
18 * - Re-adjusted the fragment sizes to better fit into the somewhat larger
22 * - Made realloc(NULL, size) work as it should. Which is like a malloc(size)
24 *****************************************************************************/
35 #define SEMAPHORE /* the PSOS routines use semaphore protection */
37 #include <stdlib.h> /* makes the PSOS complain on the 'size_t' typedef */
44 /* Each TOP takes care of a chain of BLOCKS */
46 struct MemBlock
*chain
; /* pointer to the BLOCK chain */
47 long nfree
; /* total number of free FRAGMENTS in the chain */
48 short nmax
; /* total number of FRAGMENTS in this kind of BLOCK */
49 size_t fragsize
; /* the size of each FRAGMENT */
51 #ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */
52 long semaphore_id
; /* semaphore used to lock this particular list */
57 /* Each BLOCK takes care of an amount of FRAGMENTS */
59 struct MemTop
*top
; /* our TOP struct */
60 struct MemBlock
*next
; /* next BLOCK */
61 struct MemBlock
*prev
; /* prev BLOCK */
63 struct MemFrag
*first
; /* the first free FRAGMENT in this block */
65 short nfree
; /* number of free FRAGMENTS in this BLOCK */
68 /* This is the data kept in all _free_ FRAGMENTS */
70 struct MemFrag
*next
; /* next free FRAGMENT */
71 struct MemFrag
*prev
; /* prev free FRAGMENT */
74 /* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this
75 to the allocation size first thing in the ALLOC function to make room for
80 /* which BLOCK is our father, if BLOCK_BIT is set it means this is a
81 stand-alone, large allocation and then the rest of the bits should be
82 treated as the size of the block */
86 /* ---------------------------------------------------------------------- */
88 /* ---------------------------------------------------------------------- */
91 #define MEMINCR(addr,x) memchange(addr, x)
92 #define MEMDECR(addr,x) memchange(addr,-(x))
98 /* The low level functions used to get memory from the OS and to return memory
99 to the OS, we may also define a stub that does the actual allocation and
100 free, these are the defined function names used in the dmalloc system
105 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
106 #define DMEM_OSFREEMEM(x) dbgfree(x)
108 #define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer)
109 /* Similar, but this returns the memory */
110 #define DMEM_OSFREEMEM(x) rn_retseg(0, x)
114 #define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0)
116 #define SEMAPHORERETURN(x) sm_v(x)
117 /* Argument: <name> <id-variable name> */
118 #define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y))
121 #ifdef BMALLOC /* use our own big-memory-allocation system */
122 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size)
123 #define DMEM_OSFREEMEM(x) bfree(x)
125 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
126 #define DMEM_OSFREEMEM(x) dbgfree(x)
128 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size)
129 #define DMEM_OSFREEMEM(x) free(x)
134 /* the largest memory allocation that is made a FRAGMENT: (grab the highest
135 number from the list below) */
136 #define DMEM_LARGESTSIZE 2032
138 /* The total size of a BLOCK used for FRAGMENTS
139 In order to make this use only *1* even alignment from the big-block-
140 allocation-system (possible the bmalloc() system also written by me)
141 we need to subtract the [maximum] struct sizes that could get added all
142 the way through to the grab from the memory. */
143 #define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */
145 /* Since the blocksize isn't an even 2^X story anymore, we make a table with
146 the FRAGMENT sizes and amounts that fills up a BLOCK nicely */
148 /* a little 'bc' script that helps us maximize the usage:
149 - for 32-bit aligned addresses (SPARC crashes otherwise):
150 for(i=20; i<2040; i++) { a=4064/i; if(a*i >= 4060) { if(i%4==0) {i;} } }
153 I try to approximate a double of each size, starting with ~20. We don't do
154 ODD sizes since several CPU flavours dump core when accessing such
155 addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain
159 #if BIGBLOCKS==4060 /* previously */
160 short qinfo
[]= { 20, 28, 52, 116, 312, 580, 812, 2028 };
162 short qinfo
[]= { 20, 28, 52, 116, 312, 580, 1016, 2032};
163 /* 52 and 312 only make use of 4056 bytes, but without them there are too
167 #define MIN(x,y) ((x)<(y)?(x):(y))
169 /* ---------------------------------------------------------------------- */
171 /* ---------------------------------------------------------------------- */
173 /* keeper of the chain of BLOCKS */
174 static struct MemTop top
[ sizeof(qinfo
)/sizeof(qinfo
[0]) ];
176 /* are we experienced? */
177 static char initialized
= 0;
179 /* ---------------------------------------------------------------------- */
180 /* Start of the real code */
181 /* ---------------------------------------------------------------------- */
185 * A few functions that are verbose and tells us about the current status
186 * of the dmalloc system
189 static void dmalloc_status()
195 struct MemBlock
*block
;
196 for(i
=0; i
<sizeof(qinfo
)/sizeof(qinfo
[0]);i
++) {
197 block
= top
[i
].chain
;
201 used
+= top
[i
].nmax
-block
->nfree
;
205 printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n",
206 i
, top
[i
].fragsize
, used
, top
[i
].nfree
,
207 top
[i
].nfree
*top
[i
].fragsize
, num
);
208 totalfree
+= top
[i
].nfree
*top
[i
].fragsize
;
210 printf("Total unused memory stolen by dmalloc: %d\n", totalfree
);
213 static void dmalloc_failed(size_t size
)
215 printf("*** " __FILE__
" Couldn't allocate %d bytes\n", size
);
219 #define dmalloc_failed(x)
226 void *dbgmalloc(int size
)
231 rn_getseg(0,size
,RN_NOWAIT
,0,(void **)&mem
);
236 memset(mem
, 0xaa, BORDER
/2);
237 memset(mem
+BORDER
/2, 0xbb, size
-BORDER
);
238 memset(mem
-BORDER
/2+size
, 0xcc, BORDER
/2);
242 printf("OSmalloc(%p)\n", mem
);
246 void checkmem(char *ptr
)
252 for(i
=4; i
<(BORDER
/2); i
++)
253 if((unsigned char)ptr
[i
] != 0xaa) {
254 printf("########### ALERT ALERT\n");
258 for(i
=size
-1; i
>=(size
- BORDER
/2); i
--)
259 if((unsigned char)ptr
[i
] != 0xcc) {
260 printf("********* POST ALERT\n");
265 void dbgfree(char *ptr
)
272 printf("OSfree(%ld)\n", size
);
281 #define DBG(x) syslog x
283 void syslog(char *fmt
, ...)
287 vfprintf(stdout
, fmt
, ap
);
291 void memchange(void *a
, int x
)
299 DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count
, a
, x
, memory
, max
));
305 /****************************************************************************
309 * This function makes FRAGMENTS of the BLOCK sent as argument.
311 ***************************************************************************/
313 static void FragBlock(char *memp
, int size
)
315 struct MemFrag
*frag
=(struct MemFrag
*)memp
;
316 struct MemFrag
*prev
=NULL
; /* no previous in the first round */
318 while((count
+size
) <= DMEM_BLOCKSIZE
) {
320 frag
->next
= (struct MemFrag
*)memp
;
326 prev
->next
= NULL
; /* the last one has no next struct */
329 /***************************************************************************
333 * Called in the first dmalloc(). Inits a few memory things.
335 **************************************************************************/
336 static void initialize(void)
339 /* Setup the nmax and fragsize fields of the top structs */
340 for(i
=0; i
< sizeof(qinfo
)/sizeof(qinfo
[0]); i
++) {
341 top
[i
].fragsize
= qinfo
[i
];
342 top
[i
].nmax
= DMEM_BLOCKSIZE
/qinfo
[i
];
345 /* for some reason, these aren't nulled from start: */
346 top
[i
].chain
= NULL
; /* no BLOCKS */
347 top
[i
].nfree
= 0; /* no FRAGMENTS */
352 sprintf(name
, "MEM%d", i
);
353 SEMAPHORECREATE(name
, top
[i
].semaphore_id
);
354 /* doesn't matter if it failed, we continue anyway ;-( */
361 /****************************************************************************
365 * This should return a fragment from the block and mark it as used
368 ***************************************************************************/
370 static void *FragFromBlock(struct MemBlock
*block
)
372 /* make frag point to the first free FRAGMENT */
373 struct MemFrag
*frag
= block
->first
;
374 struct MemInfo
*mem
= (struct MemInfo
*)frag
;
377 * Remove the FRAGMENT from the list and decrease the free counters.
379 block
->first
= frag
->next
; /* new first free FRAGMENT */
381 block
->nfree
--; /* BLOCK counter */
382 block
->top
->nfree
--; /* TOP counter */
384 /* heal the FRAGMENT list */
386 frag
->prev
->next
= frag
->next
;
389 frag
->next
->prev
= frag
->prev
;
391 mem
->block
= block
; /* no block bit set here */
393 return ((char *)mem
)+sizeof(struct MemInfo
);
396 /***************************************************************************
400 * This needs no explanation. A malloc() look-alike.
402 **************************************************************************/
404 void *dmalloc(size_t size
)
408 DBG(("dmalloc(%d)\n", size
));
413 /* First, we make room for the space needed in every allocation */
414 size
+= sizeof(struct MemInfo
);
416 if(size
< DMEM_LARGESTSIZE
) {
419 struct MemBlock
*block
=NULL
; /* SAFE */
420 struct MemBlock
*newblock
=NULL
; /* SAFE */
421 struct MemTop
*memtop
=NULL
; /* SAFE */
423 /* Determine which queue to use */
425 for(queue
=0; size
> qinfo
[queue
]; queue
++)
428 /* This is the head master of our chain: */
429 memtop
= &top
[queue
];
431 DBG(("Top info: %p %d %d %d\n",
438 if(SEMAPHOREOBTAIN(memtop
->semaphore_id
))
439 return NULL
; /* failed somehow */
442 /* get the first BLOCK in the chain */
443 block
= memtop
->chain
;
445 /* check if we have a free FRAGMENT */
447 /* there exists a free FRAGMENT in this chain */
449 /* I WANT THIS LOOP OUT OF HERE! */
451 /* search for the free FRAGMENT */
453 block
= block
->next
; /* check next BLOCK */
456 * Now 'block' is the first BLOCK with a free FRAGMENT
459 mem
= FragFromBlock(block
);
463 /* we do *not* have a free FRAGMENT but need to get us a new BLOCK */
465 DMEM_OSALLOCMEM(DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
),
469 if(++queue
< sizeof(qinfo
)/sizeof(qinfo
[0])) {
470 /* There are queues for bigger FRAGMENTS that we should check
471 before we fail this for real */
473 printf("*** " __FILE__
" Trying a bigger Q: %d\n", queue
);
478 dmalloc_failed(size
- sizeof(struct MemInfo
));
479 return NULL
; /* not enough memory */
483 /* allocation of big BLOCK was successful */
485 MEMINCR(newblock
, DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
));
487 memtop
->chain
= newblock
; /* attach this BLOCK to the chain */
488 newblock
->next
= block
; /* point to the previous first BLOCK */
490 block
->prev
= newblock
; /* point back on this new BLOCK */
491 newblock
->prev
= NULL
; /* no previous */
492 newblock
->top
= memtop
; /* our head master */
494 /* point to the new first FRAGMENT */
495 newblock
->first
= (struct MemFrag
*)
496 ((char *)newblock
+sizeof(struct MemBlock
));
498 /* create FRAGMENTS of the BLOCK: */
499 FragBlock((char *)newblock
->first
, memtop
->fragsize
);
501 #if defined(DEBUG) && !defined(BMALLOC)
502 checkmem((char *)newblock
);
505 /* fix the nfree counters */
506 newblock
->nfree
= memtop
->nmax
;
507 memtop
->nfree
+= memtop
->nmax
;
509 /* get a FRAGMENT from the BLOCK */
510 mem
= FragFromBlock(newblock
);
514 SEMAPHORERETURN(memtop
->semaphore_id
); /* let it go */
516 } while(NULL
== mem
); /* if we should retry a larger FRAGMENT */
519 /* get a stand-alone BLOCK */
520 struct MemInfo
*meminfo
;
523 /* don't leave this with an odd size since we'll use that bit for
527 DMEM_OSALLOCMEM(size
, meminfo
, struct MemInfo
*);
530 MEMINCR(meminfo
, size
);
531 meminfo
->block
= (void *)(size
|BLOCK_BIT
);
532 mem
= (char *)meminfo
+ sizeof(struct MemInfo
);
535 dmalloc_failed(size
);
542 /***************************************************************************
546 * This needs no explanation. A free() look-alike.
548 **************************************************************************/
550 void dfree(void *memp
)
552 struct MemInfo
*meminfo
= (struct MemInfo
*)
553 ((char *)memp
- sizeof(struct MemInfo
));
555 DBG(("dfree(%p)\n", memp
));
557 if(!((size_t)meminfo
->block
&BLOCK_BIT
)) {
558 /* this is a FRAGMENT we have to deal with */
560 struct MemBlock
*block
=meminfo
->block
;
561 struct MemTop
*memtop
= block
->top
;
564 SEMAPHOREOBTAIN(memtop
->semaphore_id
);
567 /* increase counters */
571 /* is this BLOCK completely empty now? */
572 if(block
->nfree
== memtop
->nmax
) {
573 /* yes, return the BLOCK to the system */
575 block
->prev
->next
= block
->next
;
577 memtop
->chain
= block
->next
;
579 block
->next
->prev
= block
->prev
;
581 memtop
->nfree
-= memtop
->nmax
; /* total counter subtraction */
582 MEMDECR(block
, DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
));
583 DMEM_OSFREEMEM((void *)block
); /* return the whole block */
586 /* there are still used FRAGMENTS in the BLOCK, link this one
587 into the chain of free ones */
588 struct MemFrag
*frag
= (struct MemFrag
*)meminfo
;
590 frag
->next
= block
->first
;
592 block
->first
->prev
= frag
;
596 SEMAPHORERETURN(memtop
->semaphore_id
);
600 /* big stand-alone block, just give it back to the OS: */
601 MEMDECR(&meminfo
->block
, (size_t)meminfo
->block
&~BLOCK_BIT
); /* clean BLOCK_BIT */
602 DMEM_OSFREEMEM((void *)meminfo
);
606 /***************************************************************************
610 * This needs no explanation. A realloc() look-alike.
612 **************************************************************************/
614 void *drealloc(char *ptr
, size_t size
)
616 struct MemInfo
*meminfo
= (struct MemInfo
*)
617 ((char *)ptr
- sizeof(struct MemInfo
));
619 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
620 * NOTE: the ->size field of the meminfo will now contain the MemInfo
622 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
624 void *mem
=NULL
; /* SAFE */
627 /* NOTE that this is only valid if BLOCK_BIT isn't set: */
628 struct MemBlock
*block
;
630 DBG(("drealloc(%p, %d)\n", ptr
, size
));
633 return dmalloc( size
);
635 block
= meminfo
->block
;
637 if(!((size_t)meminfo
->block
&BLOCK_BIT
) &&
638 (size
+ sizeof(struct MemInfo
) <
639 (prevsize
= block
->top
->fragsize
) )) {
640 /* This is a FRAGMENT and new size is possible to retain within the same
642 if((prevsize
> qinfo
[0]) &&
643 /* this is not the smallest memory Q */
644 (size
< (block
->top
-1)->fragsize
))
645 /* this fits in a smaller Q */
648 mem
= ptr
; /* Just return the same pointer as we got in. */
651 /* This is a stand-alone BLOCK or a realloc that no longer fits within
654 if((size_t)meminfo
->block
&BLOCK_BIT
) {
655 prevsize
= ((size_t)meminfo
->block
&~BLOCK_BIT
) -
656 sizeof(struct MemInfo
);
659 prevsize
-= sizeof(struct MemInfo
);
661 /* No tricks involved here, just grab a new bite of memory, copy the data
662 * from the old place and free the old memory again. */
665 memcpy(mem
, ptr
, MIN(size
, prevsize
) );
672 /***************************************************************************
676 * This needs no explanation. A calloc() look-alike.
678 **************************************************************************/
679 /* Allocate an array of NMEMB elements each SIZE bytes long.
680 The entire array is initialized to zeros. */
682 dcalloc (size_t nmemb
, size_t size
)
684 void *result
= dmalloc (nmemb
* size
);
687 memset (result
, 0, nmemb
* size
);
691 /*****************************************************************************
693 * Dynamic Memory Allocation
695 * Author: Daniel Stenberg
696 * Date: March 10, 1997
698 * Email: Daniel.Stenberg@sth.frontec.se
701 * Read 'thoughts' for theories and details of this implementation.
704 * - I once again managed to gain some memory. BLOCK allocations now only use
705 * a 4 bytes header (instead of previos 8) just as FRAGMENTS.
708 * - Re-adjusted the fragment sizes to better fit into the somewhat larger
712 * - Made realloc(NULL, size) work as it should. Which is like a malloc(size)
714 *****************************************************************************/
725 #define SEMAPHORE /* the PSOS routines use semaphore protection */
727 #include <stdlib.h> /* makes the PSOS complain on the 'size_t' typedef */
734 /* Each TOP takes care of a chain of BLOCKS */
736 struct MemBlock
*chain
; /* pointer to the BLOCK chain */
737 long nfree
; /* total number of free FRAGMENTS in the chain */
738 short nmax
; /* total number of FRAGMENTS in this kind of BLOCK */
739 size_t fragsize
; /* the size of each FRAGMENT */
741 #ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */
742 long semaphore_id
; /* semaphore used to lock this particular list */
747 /* Each BLOCK takes care of an amount of FRAGMENTS */
749 struct MemTop
*top
; /* our TOP struct */
750 struct MemBlock
*next
; /* next BLOCK */
751 struct MemBlock
*prev
; /* prev BLOCK */
753 struct MemFrag
*first
; /* the first free FRAGMENT in this block */
755 short nfree
; /* number of free FRAGMENTS in this BLOCK */
758 /* This is the data kept in all _free_ FRAGMENTS */
760 struct MemFrag
*next
; /* next free FRAGMENT */
761 struct MemFrag
*prev
; /* prev free FRAGMENT */
764 /* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this
765 to the allocation size first thing in the ALLOC function to make room for
770 /* which BLOCK is our father, if BLOCK_BIT is set it means this is a
771 stand-alone, large allocation and then the rest of the bits should be
772 treated as the size of the block */
776 /* ---------------------------------------------------------------------- */
778 /* ---------------------------------------------------------------------- */
781 #define MEMINCR(addr,x) memchange(addr, x)
782 #define MEMDECR(addr,x) memchange(addr,-(x))
788 /* The low level functions used to get memory from the OS and to return memory
789 to the OS, we may also define a stub that does the actual allocation and
790 free, these are the defined function names used in the dmalloc system
795 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
796 #define DMEM_OSFREEMEM(x) dbgfree(x)
798 #define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer)
799 /* Similar, but this returns the memory */
800 #define DMEM_OSFREEMEM(x) rn_retseg(0, x)
804 #define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0)
806 #define SEMAPHORERETURN(x) sm_v(x)
807 /* Argument: <name> <id-variable name> */
808 #define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y))
811 #ifdef BMALLOC /* use our own big-memory-allocation system */
812 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size)
813 #define DMEM_OSFREEMEM(x) bfree(x)
815 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
816 #define DMEM_OSFREEMEM(x) dbgfree(x)
818 #define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size)
819 #define DMEM_OSFREEMEM(x) free(x)
824 /* the largest memory allocation that is made a FRAGMENT: (grab the highest
825 number from the list below) */
826 #define DMEM_LARGESTSIZE 2032
828 /* The total size of a BLOCK used for FRAGMENTS
829 In order to make this use only *1* even alignment from the big-block-
830 allocation-system (possible the bmalloc() system also written by me)
831 we need to subtract the [maximum] struct sizes that could get added all
832 the way through to the grab from the memory. */
833 #define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */
835 /* Since the blocksize isn't an even 2^X story anymore, we make a table with
836 the FRAGMENT sizes and amounts that fills up a BLOCK nicely */
838 /* a little 'bc' script that helps us maximize the usage:
839 - for 32-bit aligned addresses (SPARC crashes otherwise):
840 for(i=20; i<2040; i++) { a=4064/i; if(a*i >= 4060) { if(i%4==0) {i;} } }
843 I try to approximate a double of each size, starting with ~20. We don't do
844 ODD sizes since several CPU flavours dump core when accessing such
845 addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain
849 #if BIGBLOCKS==4060 /* previously */
850 short qinfo
[]= { 20, 28, 52, 116, 312, 580, 812, 2028 };
852 short qinfo
[]= { 20, 28, 52, 116, 312, 580, 1016, 2032};
853 /* 52 and 312 only make use of 4056 bytes, but without them there are too
857 #define MIN(x,y) ((x)<(y)?(x):(y))
859 /* ---------------------------------------------------------------------- */
861 /* ---------------------------------------------------------------------- */
863 /* keeper of the chain of BLOCKS */
864 static struct MemTop top
[ sizeof(qinfo
)/sizeof(qinfo
[0]) ];
866 /* are we experienced? */
867 static char initialized
= 0;
869 /* ---------------------------------------------------------------------- */
870 /* Start of the real code */
871 /* ---------------------------------------------------------------------- */
875 * A few functions that are verbose and tells us about the current status
876 * of the dmalloc system
879 static void dmalloc_status()
885 struct MemBlock
*block
;
886 for(i
=0; i
<sizeof(qinfo
)/sizeof(qinfo
[0]);i
++) {
887 block
= top
[i
].chain
;
891 used
+= top
[i
].nmax
-block
->nfree
;
895 printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n",
896 i
, top
[i
].fragsize
, used
, top
[i
].nfree
,
897 top
[i
].nfree
*top
[i
].fragsize
, num
);
898 totalfree
+= top
[i
].nfree
*top
[i
].fragsize
;
900 printf("Total unused memory stolen by dmalloc: %d\n", totalfree
);
903 static void dmalloc_failed(size_t size
)
905 printf("*** " __FILE__
" Couldn't allocate %d bytes\n", size
);
909 #define dmalloc_failed(x)
916 void *dbgmalloc(int size
)
921 rn_getseg(0,size
,RN_NOWAIT
,0,(void **)&mem
);
926 memset(mem
, 0xaa, BORDER
/2);
927 memset(mem
+BORDER
/2, 0xbb, size
-BORDER
);
928 memset(mem
-BORDER
/2+size
, 0xcc, BORDER
/2);
932 printf("OSmalloc(%p)\n", mem
);
936 void checkmem(char *ptr
)
942 for(i
=4; i
<(BORDER
/2); i
++)
943 if((unsigned char)ptr
[i
] != 0xaa) {
944 printf("########### ALERT ALERT\n");
948 for(i
=size
-1; i
>=(size
- BORDER
/2); i
--)
949 if((unsigned char)ptr
[i
] != 0xcc) {
950 printf("********* POST ALERT\n");
955 void dbgfree(char *ptr
)
962 printf("OSfree(%ld)\n", size
);
971 #define DBG(x) syslog x
973 void syslog(char *fmt
, ...)
977 vfprintf(stdout
, fmt
, ap
);
981 void memchange(void *a
, int x
)
989 DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count
, a
, x
, memory
, max
));
995 /****************************************************************************
999 * This function makes FRAGMENTS of the BLOCK sent as argument.
1001 ***************************************************************************/
1003 static void FragBlock(char *memp
, int size
)
1005 struct MemFrag
*frag
=(struct MemFrag
*)memp
;
1006 struct MemFrag
*prev
=NULL
; /* no previous in the first round */
1008 while((count
+size
) <= DMEM_BLOCKSIZE
) {
1010 frag
->next
= (struct MemFrag
*)memp
;
1016 prev
->next
= NULL
; /* the last one has no next struct */
1019 /***************************************************************************
1023 * Called in the first dmalloc(). Inits a few memory things.
1025 **************************************************************************/
1026 static void initialize(void)
1029 /* Setup the nmax and fragsize fields of the top structs */
1030 for(i
=0; i
< sizeof(qinfo
)/sizeof(qinfo
[0]); i
++) {
1031 top
[i
].fragsize
= qinfo
[i
];
1032 top
[i
].nmax
= DMEM_BLOCKSIZE
/qinfo
[i
];
1035 /* for some reason, these aren't nulled from start: */
1036 top
[i
].chain
= NULL
; /* no BLOCKS */
1037 top
[i
].nfree
= 0; /* no FRAGMENTS */
1042 sprintf(name
, "MEM%d", i
);
1043 SEMAPHORECREATE(name
, top
[i
].semaphore_id
);
1044 /* doesn't matter if it failed, we continue anyway ;-( */
1051 /****************************************************************************
1055 * This should return a fragment from the block and mark it as used
1058 ***************************************************************************/
1060 static void *FragFromBlock(struct MemBlock
*block
)
1062 /* make frag point to the first free FRAGMENT */
1063 struct MemFrag
*frag
= block
->first
;
1064 struct MemInfo
*mem
= (struct MemInfo
*)frag
;
1067 * Remove the FRAGMENT from the list and decrease the free counters.
1069 block
->first
= frag
->next
; /* new first free FRAGMENT */
1071 block
->nfree
--; /* BLOCK counter */
1072 block
->top
->nfree
--; /* TOP counter */
1074 /* heal the FRAGMENT list */
1076 frag
->prev
->next
= frag
->next
;
1079 frag
->next
->prev
= frag
->prev
;
1081 mem
->block
= block
; /* no block bit set here */
1083 return ((char *)mem
)+sizeof(struct MemInfo
);
1086 /***************************************************************************
1090 * This needs no explanation. A malloc() look-alike.
1092 **************************************************************************/
1094 void *dmalloc(size_t size
)
1098 DBG(("dmalloc(%d)\n", size
));
1103 /* First, we make room for the space needed in every allocation */
1104 size
+= sizeof(struct MemInfo
);
1106 if(size
< DMEM_LARGESTSIZE
) {
1107 /* get a FRAGMENT */
1109 struct MemBlock
*block
=NULL
; /* SAFE */
1110 struct MemBlock
*newblock
=NULL
; /* SAFE */
1111 struct MemTop
*memtop
=NULL
; /* SAFE */
1113 /* Determine which queue to use */
1115 for(queue
=0; size
> qinfo
[queue
]; queue
++)
1118 /* This is the head master of our chain: */
1119 memtop
= &top
[queue
];
1121 DBG(("Top info: %p %d %d %d\n",
1128 if(SEMAPHOREOBTAIN(memtop
->semaphore_id
))
1129 return NULL
; /* failed somehow */
1132 /* get the first BLOCK in the chain */
1133 block
= memtop
->chain
;
1135 /* check if we have a free FRAGMENT */
1137 /* there exists a free FRAGMENT in this chain */
1139 /* I WANT THIS LOOP OUT OF HERE! */
1141 /* search for the free FRAGMENT */
1142 while(!block
->nfree
)
1143 block
= block
->next
; /* check next BLOCK */
1146 * Now 'block' is the first BLOCK with a free FRAGMENT
1149 mem
= FragFromBlock(block
);
1153 /* we do *not* have a free FRAGMENT but need to get us a new BLOCK */
1155 DMEM_OSALLOCMEM(DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
),
1159 if(++queue
< sizeof(qinfo
)/sizeof(qinfo
[0])) {
1160 /* There are queues for bigger FRAGMENTS that we should check
1161 before we fail this for real */
1163 printf("*** " __FILE__
" Trying a bigger Q: %d\n", queue
);
1168 dmalloc_failed(size
- sizeof(struct MemInfo
));
1169 return NULL
; /* not enough memory */
1173 /* allocation of big BLOCK was successful */
1175 MEMINCR(newblock
, DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
));
1177 memtop
->chain
= newblock
; /* attach this BLOCK to the chain */
1178 newblock
->next
= block
; /* point to the previous first BLOCK */
1180 block
->prev
= newblock
; /* point back on this new BLOCK */
1181 newblock
->prev
= NULL
; /* no previous */
1182 newblock
->top
= memtop
; /* our head master */
1184 /* point to the new first FRAGMENT */
1185 newblock
->first
= (struct MemFrag
*)
1186 ((char *)newblock
+sizeof(struct MemBlock
));
1188 /* create FRAGMENTS of the BLOCK: */
1189 FragBlock((char *)newblock
->first
, memtop
->fragsize
);
1191 #if defined(DEBUG) && !defined(BMALLOC)
1192 checkmem((char *)newblock
);
1195 /* fix the nfree counters */
1196 newblock
->nfree
= memtop
->nmax
;
1197 memtop
->nfree
+= memtop
->nmax
;
1199 /* get a FRAGMENT from the BLOCK */
1200 mem
= FragFromBlock(newblock
);
1204 SEMAPHORERETURN(memtop
->semaphore_id
); /* let it go */
1206 } while(NULL
== mem
); /* if we should retry a larger FRAGMENT */
1209 /* get a stand-alone BLOCK */
1210 struct MemInfo
*meminfo
;
1213 /* don't leave this with an odd size since we'll use that bit for
1217 DMEM_OSALLOCMEM(size
, meminfo
, struct MemInfo
*);
1220 MEMINCR(meminfo
, size
);
1221 meminfo
->block
= (void *)(size
|BLOCK_BIT
);
1222 mem
= (char *)meminfo
+ sizeof(struct MemInfo
);
1225 dmalloc_failed(size
);
1232 /***************************************************************************
1236 * This needs no explanation. A free() look-alike.
1238 **************************************************************************/
1240 void dfree(void *memp
)
1242 struct MemInfo
*meminfo
= (struct MemInfo
*)
1243 ((char *)memp
- sizeof(struct MemInfo
));
1245 DBG(("dfree(%p)\n", memp
));
1247 if(!((size_t)meminfo
->block
&BLOCK_BIT
)) {
1248 /* this is a FRAGMENT we have to deal with */
1250 struct MemBlock
*block
=meminfo
->block
;
1251 struct MemTop
*memtop
= block
->top
;
1254 SEMAPHOREOBTAIN(memtop
->semaphore_id
);
1257 /* increase counters */
1261 /* is this BLOCK completely empty now? */
1262 if(block
->nfree
== memtop
->nmax
) {
1263 /* yes, return the BLOCK to the system */
1265 block
->prev
->next
= block
->next
;
1267 memtop
->chain
= block
->next
;
1269 block
->next
->prev
= block
->prev
;
1271 memtop
->nfree
-= memtop
->nmax
; /* total counter subtraction */
1272 MEMDECR(block
, DMEM_BLOCKSIZE
+ sizeof(struct MemBlock
));
1273 DMEM_OSFREEMEM((void *)block
); /* return the whole block */
1276 /* there are still used FRAGMENTS in the BLOCK, link this one
1277 into the chain of free ones */
1278 struct MemFrag
*frag
= (struct MemFrag
*)meminfo
;
1280 frag
->next
= block
->first
;
1282 block
->first
->prev
= frag
;
1283 block
->first
= frag
;
1286 SEMAPHORERETURN(memtop
->semaphore_id
);
1290 /* big stand-alone block, just give it back to the OS: */
1291 MEMDECR(&meminfo
->block
, (size_t)meminfo
->block
&~BLOCK_BIT
); /* clean BLOCK_BIT */
1292 DMEM_OSFREEMEM((void *)meminfo
);
1296 /***************************************************************************
1300 * This needs no explanation. A realloc() look-alike.
1302 **************************************************************************/
1304 void *drealloc(char *ptr
, size_t size
)
1306 struct MemInfo
*meminfo
= (struct MemInfo
*)
1307 ((char *)ptr
- sizeof(struct MemInfo
));
1309 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1310 * NOTE: the ->size field of the meminfo will now contain the MemInfo
1312 * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1314 void *mem
=NULL
; /* SAFE */
1317 /* NOTE that this is only valid if BLOCK_BIT isn't set: */
1318 struct MemBlock
*block
;
1320 DBG(("drealloc(%p, %d)\n", ptr
, size
));
1323 return dmalloc( size
);
1325 block
= meminfo
->block
;
1327 if(!((size_t)meminfo
->block
&BLOCK_BIT
) &&
1328 (size
+ sizeof(struct MemInfo
) <
1329 (prevsize
= block
->top
->fragsize
) )) {
1330 /* This is a FRAGMENT and new size is possible to retain within the same
1332 if((prevsize
> qinfo
[0]) &&
1333 /* this is not the smallest memory Q */
1334 (size
< (block
->top
-1)->fragsize
))
1335 /* this fits in a smaller Q */
1338 mem
= ptr
; /* Just return the same pointer as we got in. */
1341 /* This is a stand-alone BLOCK or a realloc that no longer fits within
1342 the same FRAGMENT */
1344 if((size_t)meminfo
->block
&BLOCK_BIT
) {
1345 prevsize
= ((size_t)meminfo
->block
&~BLOCK_BIT
) -
1346 sizeof(struct MemInfo
);
1349 prevsize
-= sizeof(struct MemInfo
);
1351 /* No tricks involved here, just grab a new bite of memory, copy the data
1352 * from the old place and free the old memory again. */
1353 mem
= dmalloc(size
);
1355 memcpy(mem
, ptr
, MIN(size
, prevsize
) );
1362 /***************************************************************************
1366 * This needs no explanation. A calloc() look-alike.
1368 **************************************************************************/
1369 /* Allocate an array of NMEMB elements each SIZE bytes long.
1370 The entire array is initialized to zeros. */
1372 dcalloc (size_t nmemb
, size_t size
)
1374 void *result
= dmalloc (nmemb
* size
);
1377 memset (result
, 0, nmemb
* size
);