#ifdef MEMWRAP /* This software is written and copyright Sam Lantinga: mem.c and mem.h */ /* I have been having real problems with malloc() on an AT&T 3b2, so here is a customized memory handler specialized for many small requests for memory. It allocates a large chunk with malloc, and then lops hunks off for the user routines. Hopefully it is more efficient. -Sam Lantinga 6/8/93 */ #include <stdio.h> #include <errno.h> #include "mem.h" /* The memory include file */ static struct grain { int size; /* The request size in grains */ int used; /* Have we been allocated? */ char *bit; /* The grain of memory we are */ } yougetawarningifyouhavenotypehere; static struct memblock { int numfree; /* The number of free grains */ char *head; struct grain grains[GRAINS]; struct memblock *next; } memstart; static struct bigblock { char *data; struct bigblock *next; } Memstart; int debugmem=0; /* Memory debugging level */ static int havealloct=0; /* Have we initialized memory yet? */ static int tracemem=0; /* Do we trace allocated memory? */ /* Used during debugging to keep track of the memory allocated and freed. */ static struct memtrace { char *data; struct memtrace *next; } tracestart = { NULL, NULL }; void set_mtrace(on) int on; /* Turn it on or off? */ { if ( on ) tracemem=1; else tracemem=0; } void print_mtrace() { struct memtrace *memptr; fprintf(stderr, "Printing memory trace:\n"); for ( memptr=(&tracestart); memptr->next != NULL; memptr=memptr->next ) fprintf(stderr,"\ttracing address %u\n",(memptr->next)->data); } static int addtotrace(ptr) char *ptr; { struct memtrace *memptr; for (memptr=(&tracestart); memptr->next != NULL; memptr=memptr->next); if ( (memptr->next=(struct memtrace *)malloc(sizeof(struct memtrace))) == NULL ) return(-1); else memptr=memptr->next; memptr->data=ptr; memptr->next=NULL; return(0); } static int delfromtrace(ptr) char *ptr; { struct memtrace *prev, *memptr; for ( memptr=(&tracestart); memptr->next != NULL; memptr=memptr->next ) { if ( (memptr->next)->data == ptr ) { prev=(memptr->next)->next; (void) free(memptr->next); memptr->next=prev; return(0); } } fprintf(stderr, "Address %d not found in memory trace.\n"); return(-1); } static int meminit(blkptr) struct memblock *blkptr; { int i; char *newarea; if ( (blkptr->head=(char *)malloc(MEMSIZ)) == NULL ) return(-1); blkptr->numfree=GRAINS; for ( i=0, newarea=blkptr->head; i<GRAINS; ++i ) { blkptr->grains[i].bit=newarea; blkptr->grains[i].used=0; newarea+=GRAIN; } blkptr->next=NULL; #ifdef CLEANMEM zerout(blkptr->head, MEMSIZ); #endif return(0); } char *myalloc(size) int size; { int i=0; int needed=0; /* The number of grains needed to fulfill */ int need=0; /* The size of request unfulfilled */ int freestart=(-1); /* The first free grain */ struct memblock *blk, *temp; struct bigblock *Blk, *Temp; if ( ! havealloct ) { /* We need to initialize some memory */ if ( meminit(&memstart) < 0 ) return(NULL); Memstart.data=NULL; Memstart.next=NULL; havealloct=1; } /* If no need, no problem! */ if ( size == 0 ) return(NULL); /* Call malloc() directly if the request is larger than MEMSIZ */ /* Create a big block, and attatch it to the linked list */ if ( size > MEMSIZ ) { for ( Blk=Memstart.next, Temp=(&Memstart); Blk; Temp=Blk, Blk=Blk->next ); if ( (Blk=(struct bigblock *)malloc(sizeof(struct bigblock))) == NULL ) return(NULL); if ( (Blk->data=(char *)malloc(size)) == NULL ) { free(Blk); return(NULL); } Temp=Blk; Blk->next=NULL; return(Blk->data); } needed=((size+(GRAIN-1))/GRAIN); if ( debugmem > 1 ) fprintf(stderr, "myalloc():\n\tsize: %d\n\tneeded: %d\n", size, needed); for (blk=(&memstart),temp=blk; (blk != NULL); temp=blk,blk=blk->next ) { if ( needed <= blk->numfree ) { need=needed; for ( i=0; i<GRAINS; ++i ) { if ( blk->grains[i].used ) { freestart=(-1); need=needed; continue; } if ( freestart < 0 ) freestart=i; --need; if ( need == 0 ) { for ( i=freestart; i<(needed+freestart); ++i ) blk->grains[i].used=1; blk->grains[freestart].size=needed; blk->numfree-=needed; #ifdef CLEANMEM zerout(blk->grains[freestart].bit, (needed*GRAIN)); #endif /* CLEANMEM */ if ( tracemem ) { (void) addtotrace( blk->grains[freestart].bit); } return(blk->grains[freestart].bit); } } } } /* We didn't get the memory from a pool.. allocate a new one */ if ((blk=(struct memblock *)malloc(sizeof(struct memblock))) == NULL) return(NULL); if ( meminit(blk) < 0 ) return(NULL); else temp->next=blk; for ( i=0; i<needed; ++i ) blk->grains[i].used=1; blk->grains[0].size=needed; blk->numfree-=needed; return(blk->grains[0].bit); } int myfree(ptr) char *ptr; { int i, cur; struct memblock *blk; struct bigblock *Blk, *Temp; /* A little sanity please. :) */ if ( ptr == NULL ) return(0); if ( ! havealloct ) return(free(ptr)); if ( debugmem > 0 ) fprintf(stderr, "myfree(): freeing address %u\n", ptr); for ( blk=(&memstart); (blk != NULL); blk=blk->next ) { if ( (ptr >= blk->head) && (ptr < (blk->head+MEMSIZ)) ) { /* The area to be freed is in this block */ for ( i=0; i<GRAINS; ++i ) { if ( ptr == blk->grains[i].bit ) { if ( ! blk->grains[i].used ) return(-1); for( cur=i; (i<(blk->grains[cur].size+cur)); ++i ) blk->grains[i].used=0; blk->numfree+=blk->grains[cur].size; blk->grains[cur].size=0; if ( tracemem ) (void) delfromtrace(ptr); return(0); } } return(-1); } } /* Either the user passed us a bogus address, or it's from malloc() */ for (Blk=Memstart.next,Temp=(&Memstart); Blk; Temp=Blk,Blk=Blk->next) { if ( ptr == Blk->data ) { Temp->next=Blk->next; free(Blk->data); return(0); } } errno=EINVAL; return(-1); } /* A debug routine for the memory functions. It produces VOLUMOUS output. */ void mem_stat() { int i=0, k; struct memblock *blk; if ( ! havealloct ) return; for ( blk=(&memstart); (blk != NULL); blk=blk->next ) { fprintf(stderr, "Memory block #%d:\n", i++); fprintf(stderr, "\tfree grains: %d\n", blk->numfree); fprintf(stderr, "\tstarting address: %d\n", blk->head); fprintf(stderr, "\tending address: %d\n", blk->head+MEMSIZ); for ( k=0; k<GRAINS; ++k ) { if ( debugmem > 1 ) { if ( blk->grains[k].used ) fprintf(stderr, "\tgrain #%d is used.\n", k); } if ( blk->grains[k].size > 0 ) { fprintf(stderr, "\tgrain #%d is a Grain %d grains long at address %u\n", k, blk->grains[k].size, blk->grains[k].bit); } } } } /* Replacement for bzero(), which isn't always available. */ void zerout(data, size) char *data; int size; { int i; for ( i=0; (i < size); ++i, ++data ) *data='\0'; } /* Replacement for bcopy(), which isn't always available. */ void zcopy(frombuf, tobuf, size) char *frombuf; char *tobuf; int size; { int i; for ( i=0; (i < size); ++i, ++frombuf, ++tobuf ) *tobuf=(*frombuf); } #endif