mirror of https://github.com/sheumann/dmake.git
655 lines
13 KiB
C
655 lines
13 KiB
C
/*
|
|
* (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.1 1992/01/24 03:29:05 dvadura 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( IsLess(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(... */
|
|
|
|
/*
|
|
* $Log: malloc.c,v $
|
|
* Revision 1.1 1992/01/24 03:29:05 dvadura
|
|
* dmake Version 3.8, Initial revision
|
|
*
|
|
* Revision 1.6 90/05/11 00:13:09 cpcahil
|
|
* added copyright statment
|
|
*
|
|
* Revision 1.5 90/02/25 11:01:18 cpcahil
|
|
* added support for malloc chain checking.
|
|
*
|
|
* Revision 1.4 90/02/24 21:50:21 cpcahil
|
|
* lots of lint fixes
|
|
*
|
|
* Revision 1.3 90/02/24 14:51:18 cpcahil
|
|
* 1. changed malloc_fatal and malloc_warn to use malloc_errno and be passed
|
|
* the function name as a parameter.
|
|
* 2. Added several function headers.
|
|
* 3. Changed uses of malloc_fatal/warning to conform to new usage.
|
|
*
|
|
* Revision 1.2 90/02/23 18:05:23 cpcahil
|
|
* fixed open of error log to use append mode.
|
|
*
|
|
* Revision 1.1 90/02/22 23:17:43 cpcahil
|
|
* Initial revision
|
|
*
|
|
*/
|