diff options
Diffstat (limited to 'dmake/dbug/malloc/malloc.c')
-rw-r--r-- | dmake/dbug/malloc/malloc.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/dmake/dbug/malloc/malloc.c b/dmake/dbug/malloc/malloc.c new file mode 100644 index 000000000000..ff84e3efce9f --- /dev/null +++ b/dmake/dbug/malloc/malloc.c @@ -0,0 +1,627 @@ +/* + * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil). + * You may copy, distribute, and use this software as long as this + * copyright statement is not removed. + */ +#include <stdio.h> +#include <fcntl.h> +#include "malloc.h" +#include "tostring.h" + +/* + * Function: malloc() + * + * Purpose: memory allocator + * + * Arguments: size - size of data area needed + * + * Returns: pointer to allocated area, or NULL if unable + * to allocate addtional data. + * + * Narrative: + * + */ +#ifndef lint +static +char rcs_hdr[] = "$Id: malloc.c,v 1.2 2006-07-25 10:08:36 rt Exp $"; +#endif + +extern int malloc_checking; +char * malloc_data_start; +char * malloc_data_end; +struct mlist * malloc_end; +int malloc_errfd = 2; +int malloc_errno; +int malloc_fatal_level = M_HANDLE_CORE; +struct mlist malloc_start; +int malloc_warn_level; +void malloc_memset(); + +char * +malloc(size) + unsigned int size; +{ + char * func = "malloc"; + char * getenv(); + void malloc_fatal(); + void malloc_init(); + void malloc_split(); + void malloc_warning(); + unsigned int need; + struct mlist * oldptr; + struct mlist * ptr; + char * sbrk(); + + /* + * If this is the first call to malloc... + */ + if( malloc_data_start == (char *) 0 ) + { + malloc_init(); + } + + /* + * If malloc chain checking is on, go do it. + */ + if( malloc_checking ) + { + (void) malloc_chain_check(1); + } + + /* + * always make sure there is at least on extra byte in the malloc + * area so that we can verify that the user does not overrun the + * data area. + */ + size++; + + /* + * Now look for a free area of memory of size bytes... + */ + oldptr = NULL; + for(ptr = &malloc_start; ; ptr = ptr->next) + { + /* + * Since the malloc chain is a forward only chain, any + * pointer that we get should always be positioned in + * memory following the previous pointer. If this is not + * so, we must have a corrupted chain. + */ + if( ptr ) + { + if( ptr<oldptr ) + { + malloc_errno = M_CODE_CHAIN_BROKE; + malloc_fatal(func); + return(NULL); + } + oldptr = ptr; + } + else if( oldptr != malloc_end ) + { + /* + * This should never happen. If it does, then + * we got a real problem. + */ + malloc_errno = M_CODE_NO_END; + malloc_fatal(func); + return(NULL); + } + + + /* + * if this element is already in use... + */ + if( ptr && ((ptr->flag & M_INUSE) != 0) ) + { + continue; + } + + /* + * if there isn't room for this block.. + */ + if( ptr && (ptr->s.size < size) ) + { + continue; + } + + /* + * If ptr is null, we have run out of memory and must sbrk more + */ + if( ptr == NULL ) + { + need = (size + M_SIZE) * (size > 10*1024 ? 1:2); + if( need < M_BLOCKSIZE ) + { + need = M_BLOCKSIZE; + } + else if( need & (M_BLOCKSIZE-1) ) + { + need &= ~(M_BLOCKSIZE-1); + need += M_BLOCKSIZE; + } + ptr = (struct mlist *) sbrk((int)need); + if( ptr == (struct mlist *) -1 ) + { + malloc_errno = M_CODE_NOMORE_MEM; + malloc_fatal(func); + } + malloc_data_end = sbrk((int)0); + + ptr->prev = oldptr; + ptr->next = (struct mlist *) 0; + ptr->s.size = need - M_SIZE; + ptr->flag = M_MAGIC; + + oldptr->next = ptr; + malloc_end = ptr; + + + } /* if( ptr ==... */ + + /* + * Now ptr points to a memory location that can store + * this data, so lets go to work. + */ + + ptr->r_size = size; /* save requested size */ + ptr->flag |= M_INUSE; + + /* + * split off unneeded data area in this block, if possible... + */ + malloc_split(ptr); + + /* + * re-adjust the requested size so that it is what the user + * actually requested... + */ + + ptr->r_size--; + + /* + * just to make sure that noone is misusing malloced + * memory without initializing it, lets set it to + * all '\01's. We call local_memset() because memset() + * may be checking for malloc'd ptrs and this isn't + * a malloc'd ptr yet. + */ + malloc_memset(ptr->data,M_FILL,(int)ptr->s.size); + + return( ptr->data); + + } /* for(... */ + +} /* malloc(... */ + +/* + * Function: malloc_split() + * + * Purpose: to split a malloc segment if there is enough room at the + * end of the segment that isn't being used + * + * Arguments: ptr - pointer to segment to split + * + * Returns: nothing of any use. + * + * Narrative: + * get the needed size of the module + * round the size up to appropriat boundry + * calculate amount of left over space + * if there is enough left over space + * create new malloc block out of remainder + * if next block is free + * join the two blocks together + * fill new empty block with free space filler + * re-adjust pointers and size of current malloc block + * + * + * + * Mod History: + * 90/01/27 cpcahil Initial revision. + */ +void +malloc_split(ptr) + struct mlist * ptr; +{ + extern struct mlist * malloc_end; + void malloc_join(); + int rest; + int size; + struct mlist * tptr; + + size = ptr->r_size; + + /* + * roundup size to the appropriate boundry + */ + + M_ROUNDUP(size); + + /* + * figure out how much room is left in the array. + * if there is enough room, create a new mlist + * structure there. + */ + + if( ptr->s.size > size ) + { + rest = ptr->s.size - size; + } + else + { + rest = 0; + } + + if( rest > (M_SIZE+M_RND) ) + { + tptr = (struct mlist *) (ptr->data+size); + tptr->prev = ptr; + tptr->next = ptr->next; + tptr->flag = M_MAGIC; + tptr->s.size = rest - M_SIZE; + + /* + * If possible, join this segment with the next one + */ + + malloc_join(tptr, tptr->next,0,0); + + if( tptr->next ) + { + tptr->next->prev = tptr; + } + + malloc_memset(tptr->data,M_FREE_FILL, (int)tptr->s.size); + + ptr->next = tptr; + ptr->s.size = size; + + if( malloc_end == ptr ) + { + malloc_end = tptr; + } + } + +} /* malloc_split(... */ + +/* + * Function: malloc_join() + * + * Purpose: to join two malloc segments together (if possible) + * + * Arguments: ptr - pointer to segment to join to. + * nextptr - pointer to next segment to join to ptr. + * + * Returns: nothing of any values. + * + * Narrative: + * + * Mod History: + * 90/01/27 cpcahil Initial revision. + */ +void +malloc_join(ptr,nextptr, inuse_override, fill_flag) + struct mlist * ptr; + struct mlist * nextptr; + int inuse_override; + int fill_flag; +{ + unsigned int newsize; + + if( ptr && ! (inuse_override || (ptr->flag & M_INUSE)) && + nextptr && ! (nextptr->flag & M_INUSE) && + ((ptr->data+ptr->s.size) == (char *) nextptr) ) + { + if( malloc_end == nextptr ) + { + malloc_end = ptr; + } + ptr->next = nextptr->next; + newsize = nextptr->s.size + M_SIZE; + + /* + * if we are to fill and this segment is in use, + * fill in with M_FILL newly added space... + */ + + if(fill_flag && (ptr->flag & M_INUSE) ) + { + malloc_memset(ptr->data+ptr->s.size, + M_FILL, (int)(nextptr->s.size + M_SIZE)); + } + + ptr->s.size += newsize; + if( ptr->next ) + { + ptr->next->prev = ptr; + } + } + +} /* malloc_join(... */ + + +/* + * The following mess is just to ensure that the versions of these functions in + * the current library are included (to make sure that we don't accidentaly get + * the libc versions. (This is the lazy man's -u ld directive) + */ + +void free(); +int strcmp(); +int memcmp(); +char * realloc(); + +void (*malloc_void_funcs[])() = +{ + free, +}; + +int (*malloc_int_funcs[])() = +{ + strcmp, + memcmp, +}; + +char * (*malloc_char_star_funcs[])() = +{ + realloc, +}; + +/* + * This is malloc's own memset which is used without checking the parameters. + */ + +void +malloc_memset(ptr,byte,len) + char * ptr; + char byte; + int len; +{ + + while(len-- > 0) + { + *ptr++ = byte; + } + +} /* malloc_memset(... */ + +/* + * Function: malloc_fatal() + * + * Purpose: to display fatal error message and take approrpriate action + * + * Arguments: funcname - name of function calling this routine + * + * Returns: nothing of any value + * + * Narrative: + * + * Notes: This routine does not make use of any libc functions to build + * and/or disply the error message. This is due to the fact that + * we are probably at a point where malloc is having a real problem + * and we don't want to call any function that may use malloc. + */ +void +malloc_fatal(funcname) + char * funcname; +{ + char errbuf[128]; + void exit(); + void malloc_err_handler(); + extern char * malloc_err_strings[]; + extern int malloc_errno; + extern int malloc_fatal_level; + char * s; + char * t; + + s = errbuf; + t = "Fatal error: "; + while( *s = *t++) + { + s++; + } + t = funcname; + while( *s = *t++) + { + s++; + } + + t = "(): "; + while( *s = *t++) + { + s++; + } + + t = malloc_err_strings[malloc_errno]; + while( *s = *t++) + { + s++; + } + + *(s++) = '\n'; + + if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf)) + { + (void) write(2,"I/O error to error file\n",(unsigned)24); + exit(110); + } + malloc_err_handler(malloc_fatal_level); + +} /* malloc_fatal(... */ + +/* + * Function: malloc_warning() + * + * Purpose: to display warning error message and take approrpriate action + * + * Arguments: funcname - name of function calling this routine + * + * Returns: nothing of any value + * + * Narrative: + * + * Notes: This routine does not make use of any libc functions to build + * and/or disply the error message. This is due to the fact that + * we are probably at a point where malloc is having a real problem + * and we don't want to call any function that may use malloc. + */ +void +malloc_warning(funcname) + char * funcname; +{ + char errbuf[128]; + void exit(); + void malloc_err_handler(); + extern char * malloc_err_strings[]; + extern int malloc_errno; + extern int malloc_warn_level; + char * s; + char * t; + + s = errbuf; + t = "Warning: "; + while( *s = *t++) + { + s++; + } + t = funcname; + while( *s = *t++) + { + s++; + } + + t = "(): "; + while( *s = *t++) + { + s++; + } + + t = malloc_err_strings[malloc_errno]; + while( *s = *t++) + { + s++; + } + + *(s++) = '\n'; + + if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf)) + { + (void) write(2,"I/O error to error file\n",(unsigned)24); + exit(110); + } + + malloc_err_handler(malloc_warn_level); + +} /* malloc_warning(... */ + +/* + * Function: malloc_err_handler() + * + * Purpose: to take the appropriate action for warning and/or fatal + * error conditions. + * + * Arguments: level - error handling level + * + * Returns: nothing of any value + * + * Narrative: + * + * Notes: This routine does not make use of any libc functions to build + * and/or disply the error message. This is due to the fact that + * we are probably at a point where malloc is having a real problem + * and we don't want to call any function that may use malloc. + */ +void +malloc_err_handler(level) +{ + void exit(); + void malloc_dump(); + extern int malloc_errfd; + + if( level & M_HANDLE_DUMP ) + { + malloc_dump(malloc_errfd); + } + + switch( level & ~M_HANDLE_DUMP ) + { + /* + * If we are to drop a core file and exit + */ + case M_HANDLE_ABORT: + (void) abort(); + break; + + /* + * If we are to exit.. + */ + case M_HANDLE_EXIT: + exit(200); + break; + +#ifndef __MSDOS__ + /* + * If we are to dump a core, but keep going on our merry way + */ + case M_HANDLE_CORE: + { + int pid; + + /* + * fork so child can abort (and dump core) + */ + if( (pid = fork()) == 0 ) + { + (void) write(2,"Child dumping core\n", + (unsigned)9); + (void) abort(); + } + + /* + * wait for child to finish dumping core + */ + while( wait((int *)0) != pid) + { + } + + /* + * Move core file to core.pid.cnt so + * multiple cores don't overwrite each + * other. + */ + if( access("core",0) == 0 ) + { + static int corecnt; + char filenam[32]; + filenam[0] = 'c'; + filenam[1] = 'o'; + filenam[2] = 'r'; + filenam[3] = 'e'; + filenam[4] = '.'; + (void)tostring(filenam+5,getpid(), + 5, B_DEC, '0'); + filenam[10] = '.'; + (void)tostring(filenam+11,corecnt++, + 3, B_DEC, '0'); + filenam[14] = '\0'; + (void) unlink(filenam); + if( link("core",filenam) == 0) + { + (void) unlink("core"); + } + } + } +#endif + + + /* + * If we are to just ignore the error and keep on processing + */ + case M_HANDLE_IGNORE: + break; + + } /* switch(... */ + +} /* malloc_err_handler(... */ + |