1299 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1299 lines
		
	
	
		
			31 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file READ_ME
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/*
 | 
						|
	PROGRAM
 | 
						|
		malloc(), free(), realloc()
 | 
						|
	AUTHOR
 | 
						|
		Dick Grune, Free University, Amsterdam
 | 
						|
		Modified by Ceriel Jacobs, Free University, Amsterdam,
 | 
						|
		to make it faster
 | 
						|
	VERSION
 | 
						|
		$Header$
 | 
						|
	DESCRIPTION
 | 
						|
	This is an independent rewrite of the malloc/free package; it is
 | 
						|
	fast and efficient.  Free blocks are kept in doubly linked lists,
 | 
						|
	list N holding blocks with sizes between 2**N and 2**(N+1)-1.
 | 
						|
	Consequently neither malloc nor free have to do any searching:
 | 
						|
	the cost of a call of malloc() (or free()) is constant, however
 | 
						|
	many blocks you have got.
 | 
						|
	
 | 
						|
	If you switch on the NON_STANDARD macro (see param.h) every block
 | 
						|
	costs 2 pointers overhead (otherwise it's 4).
 | 
						|
*/
 | 
						|
/*
 | 
						|
	There is an organisational problem here: during devellopment
 | 
						|
	I want the package divided into modules, which implies external
 | 
						|
	names for the communication.  The only external names I want in
 | 
						|
	the finished product are malloc, realloc and free.  This requires
 | 
						|
	some hanky-panky.
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file size_type.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
#if	_EM_WSIZE == _EM_PSIZE
 | 
						|
typedef unsigned int size_type;
 | 
						|
#elif	_EM_LSIZE == _EM_PSIZE
 | 
						|
typedef unsigned long size_type;
 | 
						|
#else
 | 
						|
#error funny pointer size
 | 
						|
#endif
 | 
						|
#include	<stdlib.h>
 | 
						|
#include	<stdio.h>
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file param.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
 | 
						|
#	undef	NON_STANDARD	/*	If defined, the contents of a block
 | 
						|
					will NOT be left undisturbed after it
 | 
						|
					is freed, as opposed to what it says
 | 
						|
					in the manual (malloc(2)).
 | 
						|
					Setting this option reduces the memory
 | 
						|
					overhead considerably.  I personally
 | 
						|
					consider the specified behaviour an
 | 
						|
					artefact of the original
 | 
						|
					implementation.
 | 
						|
				*/
 | 
						|
 | 
						|
#	define	ASSERT		/*	If defined, some inexpensive tests
 | 
						|
					will be made to ensure the
 | 
						|
					correctness of some sensitive data.
 | 
						|
					It often turns an uncontrolled crash
 | 
						|
					into a controlled one.
 | 
						|
				*/
 | 
						|
 | 
						|
#	define	CHECK		/*	If defined, extensive and expensive
 | 
						|
					tests will be done, inculding a
 | 
						|
					checksum on the mallinks (chunk
 | 
						|
					information blocks).  The resulting
 | 
						|
					information will be printed on a file
 | 
						|
					called mal.out .
 | 
						|
					Additionally a function
 | 
						|
						maldump(n) int n;
 | 
						|
					will be defined, which will dump
 | 
						|
					pertinent info in pseudo-readable
 | 
						|
					form; it aborts afterwards if n != 0.
 | 
						|
				*/
 | 
						|
 | 
						|
#	undef	EXTERN		/*	If defined, all static names will
 | 
						|
					become extern, which is a help in
 | 
						|
					using adb(1) or prof(1)
 | 
						|
				*/
 | 
						|
 | 
						|
#	define	STORE		/*	If defined, separate free lists will
 | 
						|
					be kept of chunks with small sizes,
 | 
						|
					to speed things up a little.
 | 
						|
				*/
 | 
						|
 | 
						|
#	undef SYSTEM		/*	If defined, the system module is used.
 | 
						|
					Otherwise, "sbrk" is called directly.
 | 
						|
				*/
 | 
						|
 | 
						|
#define	ALIGNMENT	8	
 | 
						|
				/* alignment common to all types */
 | 
						|
#define	LOG_MIN_SIZE	3
 | 
						|
#define	LOG_MAX_SIZE	24
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file impl.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/*	This file essentially describes how the mallink info block
 | 
						|
	is implemented.
 | 
						|
*/
 | 
						|
 | 
						|
#define	MIN_SIZE	(1<<LOG_MIN_SIZE)
 | 
						|
#define	MAX_FLIST	(LOG_MAX_SIZE - LOG_MIN_SIZE)
 | 
						|
#if ALIGNMENT != 4 && ALIGNMENT != 8 && ALIGNMENT != 16
 | 
						|
#error ALIGNMENT must be 4, 8 or 16
 | 
						|
#elif ALIGNMENT % _EM_LSIZE
 | 
						|
/* since calloc() does it's initialization in longs */
 | 
						|
#error ALIGNMENT must be a multiple of the long size
 | 
						|
#endif
 | 
						|
#define align(n)	(((n) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
 | 
						|
 | 
						|
union _inf {
 | 
						|
	union _inf *ptr;
 | 
						|
	size_type ui;
 | 
						|
};
 | 
						|
 | 
						|
typedef union _inf mallink;
 | 
						|
#define	MAL_NULL	((mallink *)0)
 | 
						|
 | 
						|
/*	Access macros; only these macros know where to find values.
 | 
						|
	They are also lvalues.
 | 
						|
*/
 | 
						|
#ifndef	NON_STANDARD
 | 
						|
#define	OFF_SET	0
 | 
						|
#else	/* def NON_STANDARD */
 | 
						|
#define	OFF_SET	2
 | 
						|
#endif	/* NON_STANDARD */
 | 
						|
 | 
						|
#define	_log_prev_of(ml)	((ml)[-1+OFF_SET]).ptr
 | 
						|
#define	_log_next_of(ml)	((ml)[-2+OFF_SET]).ptr
 | 
						|
#define	_phys_prev_of(ml)	((ml)[-3+OFF_SET]).ptr
 | 
						|
#define	_this_size_of(ml)	((ml)[-4+OFF_SET]).ui
 | 
						|
#ifndef	CHECK
 | 
						|
#define	N_WORDS			4
 | 
						|
#else	/* ifdef	CHECK */
 | 
						|
#define	_checksum_of(ml)	((ml)[-5+OFF_SET]).ui
 | 
						|
#define	_print_of(ml)		((ml)[-6+OFF_SET]).ui
 | 
						|
#define	_mark_of(ml)		((ml)[-7+OFF_SET]).ui
 | 
						|
#define	N_WORDS			7
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
#define	mallink_size()		(size_t) \
 | 
						|
	align((N_WORDS - OFF_SET) * sizeof (mallink))
 | 
						|
 | 
						|
#ifdef	CHECK
 | 
						|
#define	set_mark(ml,e)		(_mark_of(ml) = (e))
 | 
						|
#define	mark_of(ml)		(_mark_of(ml))
 | 
						|
 | 
						|
#define	set_checksum(ml,e)	(_checksum_of(ml) = (e))
 | 
						|
#define	checksum_of(ml)		(_checksum_of(ml))
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
#define new_mallink(ml)		( _log_prev_of(ml) = 0, \
 | 
						|
				  _log_next_of(ml) = 0, \
 | 
						|
				  _phys_prev_of(ml) = 0, \
 | 
						|
				  _this_size_of(ml) = 0 )
 | 
						|
 | 
						|
#define	block_of_mallink(ml)	((void *)ml)
 | 
						|
#define	mallink_of_block(addr)	((mallink *)addr)
 | 
						|
 | 
						|
#define	public	extern
 | 
						|
#define	publicdata	extern
 | 
						|
#ifndef	EXTERN
 | 
						|
#define	private	static
 | 
						|
#define	privatedata	static
 | 
						|
#else	/* def	EXTERN */
 | 
						|
#define	private	extern
 | 
						|
#define	privatedata
 | 
						|
#endif	/* EXTERN */
 | 
						|
 | 
						|
#ifdef	ASSERT
 | 
						|
private m_assert(const char *fn, int ln);
 | 
						|
#define	assert(b)		(!(b) ? m_assert(__FILE__, __LINE__) : 0)
 | 
						|
#else	/* ndef	ASSERT */
 | 
						|
#define	assert(b)		0
 | 
						|
#endif	/* ASSERT */
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file check.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
#ifdef	CHECK
 | 
						|
 | 
						|
private check_mallinks(const char *s), calc_checksum(mallink *ml);
 | 
						|
private check_work_empty(const char *s);
 | 
						|
private started_working_on(mallink *ml), stopped_working_on(mallink *ml);
 | 
						|
 | 
						|
#else	/* ifndef	CHECK */
 | 
						|
 | 
						|
#define	maldump(n)		abort()
 | 
						|
#define	check_mallinks(s)	0
 | 
						|
#define	calc_checksum(ml)	0
 | 
						|
#define	started_working_on(ml)	0
 | 
						|
#define	stopped_working_on(ml)	0
 | 
						|
#define	check_work_empty(s)	0
 | 
						|
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file log.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/*	Algorithms to manipulate the doubly-linked lists of free
 | 
						|
	chunks.
 | 
						|
*/
 | 
						|
 | 
						|
private link_free_chunk(mallink *ml), unlink_free_chunk(mallink *ml);
 | 
						|
private mallink *first_present(int class);
 | 
						|
private mallink *search_free_list(int class, size_t n);
 | 
						|
 | 
						|
#ifdef STORE
 | 
						|
#define in_store(ml)		((size_type)_phys_prev_of(ml) & STORE_BIT)
 | 
						|
#define set_store(ml, e) \
 | 
						|
	(_phys_prev_of(ml) = (mallink *) \
 | 
						|
		((e) ? (size_type) _phys_prev_of(ml) | STORE_BIT : \
 | 
						|
		       (size_type) _phys_prev_of(ml) & ~STORE_BIT))
 | 
						|
#endif
 | 
						|
#define	set_log_prev(ml,e)	(_log_prev_of(ml) = (e))
 | 
						|
#define	log_prev_of(ml)		(mallink *) (_log_prev_of(ml))
 | 
						|
 | 
						|
#define	set_log_next(ml,e)	(_log_next_of(ml) = (e))
 | 
						|
#define	log_next_of(ml)		(mallink *) (_log_next_of(ml))
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file phys.h
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/*	Algorithms to manipulate the doubly-linked list of physical
 | 
						|
	chunks.
 | 
						|
*/
 | 
						|
privatedata mallink *ml_last;
 | 
						|
 | 
						|
#define FREE_BIT		01
 | 
						|
#ifdef STORE
 | 
						|
#define STORE_BIT		02
 | 
						|
#define BITS			(FREE_BIT|STORE_BIT)
 | 
						|
#else
 | 
						|
#define BITS			(FREE_BIT)
 | 
						|
#endif
 | 
						|
 | 
						|
#define __bits(ml)		((int)((size_type)_phys_prev_of(ml) & BITS))
 | 
						|
#define	__free_of(ml)		((int)((size_type)_phys_prev_of(ml) & FREE_BIT))
 | 
						|
#define __phys_prev_of(ml)	((mallink *)((size_type)_phys_prev_of(ml) & ~BITS))
 | 
						|
#define prev_size_of(ml)	((char *)(ml) - \
 | 
						|
				 (char *)__phys_prev_of(ml) - \
 | 
						|
				 mallink_size() \
 | 
						|
				)
 | 
						|
#define	set_phys_prev(ml,e) \
 | 
						|
	(_phys_prev_of(ml) = (mallink *) ((char *)e + __bits(ml)))
 | 
						|
 | 
						|
#ifdef	CHECK
 | 
						|
private Error(const char *fmt, const char *s, mallink *ml);
 | 
						|
#define	phys_prev_of(ml)	(mallink *) \
 | 
						|
	(first_mallink(ml) ? \
 | 
						|
		(char *)Error("phys_prev_of first_mallink %p", "somewhere", ml) : \
 | 
						|
		(char *)__phys_prev_of(ml) \
 | 
						|
	)
 | 
						|
#else	/* ndef	CHECK */
 | 
						|
#define	phys_prev_of(ml)	__phys_prev_of(ml)
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
#define	first_mallink(ml)	(int) (__phys_prev_of(ml) == 0)
 | 
						|
#define	last_mallink(ml)	(int) ((ml) == ml_last)
 | 
						|
 | 
						|
/*	There is an ambiguity in the semantics of phys_next_of: sometimes
 | 
						|
	one wants it to return MAL_NULL if there is no next chunk, at
 | 
						|
	other times one wants the address of the virtual chunk at the
 | 
						|
	end of memory.  The present version returns the address of the
 | 
						|
	(virtual) chunk and relies on the user to test last_mallink(ml)
 | 
						|
	first.
 | 
						|
*/
 | 
						|
#define size_of(ml)		(_this_size_of(ml) - mallink_size())
 | 
						|
#define	set_phys_next(ml,e) \
 | 
						|
	(_this_size_of(ml) = (size_type)((char *)(e) - (char *)(ml)))
 | 
						|
#define	phys_next_of(ml)	(mallink *) ((char *)(ml) + _this_size_of(ml))
 | 
						|
 | 
						|
#define	set_free(ml,e) \
 | 
						|
	(_phys_prev_of(ml) = (mallink *) \
 | 
						|
		((e) ? (size_type) _phys_prev_of(ml) | FREE_BIT : \
 | 
						|
		       (size_type) _phys_prev_of(ml) & ~FREE_BIT))
 | 
						|
#define	free_of(ml)		(__free_of(ml))
 | 
						|
 | 
						|
#define coalesce_forw(ml,nxt)	( unlink_free_chunk(nxt), \
 | 
						|
				  combine_chunks((ml), (nxt)))
 | 
						|
 | 
						|
#define coalesce_backw(ml,prv)	( unlink_free_chunk(prv), \
 | 
						|
				  stopped_working_on(ml), \
 | 
						|
				  combine_chunks((prv), (ml)), \
 | 
						|
				  started_working_on(prv))
 | 
						|
 | 
						|
#ifdef	CHECK
 | 
						|
#define	set_print(ml,e)		(_print_of(ml) = (e))
 | 
						|
#define	print_of(ml)		(_print_of(ml))
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
private truncate(mallink *ml, size_t size);
 | 
						|
private combine_chunks(register mallink *ml1, register mallink *ml2);
 | 
						|
private mallink *create_chunk(void *p, size_t n);
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file mal.c
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
#include	<limits.h>
 | 
						|
#include	<stdlib.h>
 | 
						|
 | 
						|
/*	Malloc space is traversed by N doubly-linked lists of chunks, each
 | 
						|
	containing a couple of house-keeping data addressed as a
 | 
						|
	'mallink' and a piece of useful space, called the block.
 | 
						|
	The N lists are accessed through their starting pointers in
 | 
						|
	free_list[].  Free_list[n] points to a list of chunks between
 | 
						|
	2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means
 | 
						|
	that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE).
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef SYSTEM
 | 
						|
#include	<system.h>
 | 
						|
#define SBRK	sys_break
 | 
						|
#else
 | 
						|
#define SBRK	_sbrk
 | 
						|
#define	ILL_BREAK		(void *)(-1)	/* funny failure value */
 | 
						|
#endif
 | 
						|
extern void *SBRK(int incr);
 | 
						|
#ifdef STORE
 | 
						|
#define	MAX_STORE	32
 | 
						|
private do_free(mallink *ml), sell_out(void);
 | 
						|
privatedata mallink *store[MAX_STORE];
 | 
						|
#endif /* STORE */
 | 
						|
 | 
						|
void *privious_free= (void *)-1;
 | 
						|
void *
 | 
						|
malloc(register size_t n)
 | 
						|
{check_mallinks("malloc entry");{
 | 
						|
	register mallink *ml;
 | 
						|
	register int min_class;
 | 
						|
	void *tmp;
 | 
						|
 | 
						|
{ static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } }
 | 
						|
privious_free= (void *)-1;
 | 
						|
	if (n == 0) {
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
 | 
						|
#ifdef STORE
 | 
						|
	if (n <= MAX_STORE*MIN_SIZE)	{
 | 
						|
		/* look in the store first */
 | 
						|
		register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1];
 | 
						|
		
 | 
						|
		if (ml = *stp)	{
 | 
						|
			*stp = log_next_of(ml);
 | 
						|
			set_store(ml, 0);
 | 
						|
			check_mallinks("malloc fast exit");
 | 
						|
			assert(! in_store(ml));
 | 
						|
			tmp= block_of_mallink(ml);
 | 
						|
{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
 | 
						|
			return tmp;
 | 
						|
		}
 | 
						|
	}
 | 
						|
#endif /* STORE */
 | 
						|
 | 
						|
	check_work_empty("malloc, entry");
 | 
						|
 | 
						|
	/*	Acquire a chunk of at least size n if at all possible;
 | 
						|
		Try everything.
 | 
						|
	*/
 | 
						|
	{
 | 
						|
		/*	Inline substitution of "smallest".
 | 
						|
		*/
 | 
						|
		register size_t n1 = n;
 | 
						|
 | 
						|
		assert(n1 < (1L << LOG_MAX_SIZE));
 | 
						|
		min_class = 0;
 | 
						|
 | 
						|
		do {
 | 
						|
			n1 >>= 1;
 | 
						|
			min_class++;
 | 
						|
		} while (n1 >= MIN_SIZE);
 | 
						|
	}
 | 
						|
 | 
						|
	if (min_class >= MAX_FLIST)
 | 
						|
		return NULL;		/* we don't deal in blocks that big */
 | 
						|
	ml = first_present(min_class);
 | 
						|
	if (ml == MAL_NULL)	{
 | 
						|
		/*	Try and extend */
 | 
						|
		register void *p;
 | 
						|
#define	GRABSIZE	4096		/* Power of 2 */
 | 
						|
		register size_t req =
 | 
						|
			((MIN_SIZE<<min_class)+ mallink_size() + GRABSIZE - 1) &
 | 
						|
				~(GRABSIZE-1);
 | 
						|
	
 | 
						|
		if (!ml_last)	{
 | 
						|
			/* first align SBRK() */
 | 
						|
		
 | 
						|
			p = SBRK(0);
 | 
						|
			SBRK((int) (align((size_type) p) - (size_type) p));
 | 
						|
		}
 | 
						|
 | 
						|
		/* SBRK takes an int; sorry ... */
 | 
						|
		if ((int) req < 0) {
 | 
						|
			p = ILL_BREAK;
 | 
						|
		} else {
 | 
						|
			p = SBRK((int)req);
 | 
						|
		}
 | 
						|
		if (p == ILL_BREAK) {
 | 
						|
			req = n + mallink_size();
 | 
						|
			if ((int) req >= 0) p = SBRK((int)req);
 | 
						|
		}
 | 
						|
		if (p == ILL_BREAK)	{
 | 
						|
			/*	Now this is bad.  The system will not give us
 | 
						|
				more memory.  We can only liquidate our store
 | 
						|
				and hope it helps.
 | 
						|
			*/
 | 
						|
#ifdef STORE
 | 
						|
			sell_out();
 | 
						|
			ml = first_present(min_class);
 | 
						|
			if (ml == MAL_NULL)	{
 | 
						|
#endif /* STORE */
 | 
						|
				/* In this emergency we try to locate a suitable
 | 
						|
				   chunk in the free_list just below the safe
 | 
						|
				   one; some of these chunks may fit the job.
 | 
						|
				*/
 | 
						|
				ml = search_free_list(min_class - 1, n);
 | 
						|
				if (!ml)	/* really out of space */
 | 
						|
					return NULL;
 | 
						|
				started_working_on(ml);
 | 
						|
				unlink_free_chunk(ml);
 | 
						|
				check_mallinks("suitable_chunk, forced");
 | 
						|
#ifdef STORE
 | 
						|
			}
 | 
						|
			else started_working_on(ml);
 | 
						|
#endif /* STORE */
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			assert((size_type)p == align((size_type)p));
 | 
						|
			ml = create_chunk(p, req);
 | 
						|
		}
 | 
						|
		check_mallinks("suitable_chunk, extended");
 | 
						|
	}
 | 
						|
	else started_working_on(ml);
 | 
						|
 | 
						|
	/* we have a chunk */
 | 
						|
	set_free(ml, 0);
 | 
						|
	calc_checksum(ml);
 | 
						|
	check_mallinks("suitable_chunk, removed");
 | 
						|
	n += mallink_size();
 | 
						|
	if (n + MIN_SIZE <= size_of(ml)) {
 | 
						|
		truncate(ml, n);
 | 
						|
	}
 | 
						|
	stopped_working_on(ml);
 | 
						|
	check_mallinks("malloc exit");
 | 
						|
	check_work_empty("malloc exit");
 | 
						|
#ifdef STORE
 | 
						|
	assert(! in_store(ml));
 | 
						|
#endif
 | 
						|
	tmp= block_of_mallink(ml);
 | 
						|
{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } }
 | 
						|
	return tmp;
 | 
						|
}}
 | 
						|
 | 
						|
void
 | 
						|
free(void *addr)
 | 
						|
{check_mallinks("free entry");{
 | 
						|
	register mallink *ml;
 | 
						|
 | 
						|
printf("free 0x%x\n", addr);
 | 
						|
if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); }
 | 
						|
privious_free= addr;
 | 
						|
	if (addr == NULL) {
 | 
						|
		check_mallinks("free(0) very fast exit");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	ml = mallink_of_block(addr);
 | 
						|
#ifdef STORE
 | 
						|
 | 
						|
	if (free_of(ml) || in_store(ml))
 | 
						|
		return;				/* user frees free block */
 | 
						|
	if (size_of(ml) <= MAX_STORE*MIN_SIZE)	{
 | 
						|
		/* return to store */
 | 
						|
		mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
 | 
						|
		
 | 
						|
		set_log_next(ml, *stp);
 | 
						|
		*stp = ml;
 | 
						|
		set_store(ml, 1);
 | 
						|
		calc_checksum(ml);
 | 
						|
		check_mallinks("free fast exit");
 | 
						|
	}
 | 
						|
	else	{
 | 
						|
		do_free(ml);
 | 
						|
		check_mallinks("free exit");
 | 
						|
	}
 | 
						|
}}
 | 
						|
 | 
						|
private
 | 
						|
do_free(register mallink *ml)
 | 
						|
{{
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef STORE
 | 
						|
	if (free_of(ml))	return;
 | 
						|
#endif /* STORE */
 | 
						|
	started_working_on(ml);
 | 
						|
	set_free(ml, 1);
 | 
						|
	calc_checksum(ml);
 | 
						|
	if (! last_mallink(ml)) {
 | 
						|
		register mallink *next = phys_next_of(ml);
 | 
						|
 | 
						|
		if (free_of(next)) coalesce_forw(ml, next);
 | 
						|
	}
 | 
						|
 | 
						|
	if (! first_mallink(ml)) {
 | 
						|
		register mallink *prev = phys_prev_of(ml);
 | 
						|
 | 
						|
		if (free_of(prev)) {
 | 
						|
			coalesce_backw(ml, prev);
 | 
						|
			ml = prev;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	link_free_chunk(ml);
 | 
						|
	stopped_working_on(ml);
 | 
						|
	check_work_empty("free");
 | 
						|
 | 
						|
	/* Compile-time checks on param.h */
 | 
						|
	switch (0)	{
 | 
						|
	case MIN_SIZE < OFF_SET * sizeof(mallink):	break;
 | 
						|
	case 1:	break;
 | 
						|
	/*	If this statement does not compile due to duplicate case
 | 
						|
		entry, the minimum size block cannot hold the links for
 | 
						|
		the free blocks.  Either raise LOG_MIN_SIZE or switch
 | 
						|
		off NON_STANDARD.
 | 
						|
	*/
 | 
						|
	}
 | 
						|
	switch(0)	{
 | 
						|
	case sizeof(void *) != sizeof(size_type):	break;
 | 
						|
	case 1:	break;
 | 
						|
	/*	If this statement does not compile due to duplicate
 | 
						|
		case entry, size_type is not defined correctly.
 | 
						|
		Redefine and compile again.
 | 
						|
	*/
 | 
						|
	}
 | 
						|
}}
 | 
						|
 | 
						|
void *
 | 
						|
realloc(void *addr, register size_t n)
 | 
						|
{check_mallinks("realloc entry");{
 | 
						|
	register mallink *ml, *ph_next;
 | 
						|
	register size_type size;
 | 
						|
 | 
						|
printf("realloc 0x%x, %d\n", addr, n);
 | 
						|
	if (addr == NULL) {
 | 
						|
		/*	Behave like most Unix realloc's when handed a
 | 
						|
			null-pointer
 | 
						|
		*/
 | 
						|
		return malloc(n);
 | 
						|
	}
 | 
						|
	if (n == 0) {
 | 
						|
		free(addr);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	ml = mallink_of_block(addr);
 | 
						|
	if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
 | 
						|
#ifdef STORE
 | 
						|
	if (in_store(ml)) {
 | 
						|
		register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1];
 | 
						|
		mallink *stp1 = NULL;
 | 
						|
		while (ml != stp)	{
 | 
						|
			stp1 = stp;
 | 
						|
			stp = log_next_of(stp);
 | 
						|
		}
 | 
						|
		stp = log_next_of(stp);
 | 
						|
		if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp;
 | 
						|
		else set_log_next(stp1, stp);
 | 
						|
		set_store(ml, 0);
 | 
						|
		calc_checksum(ml);
 | 
						|
	}
 | 
						|
#endif
 | 
						|
	if (free_of(ml)) {
 | 
						|
		unlink_free_chunk(ml);
 | 
						|
		set_free(ml, 0);		/* user reallocs free block */
 | 
						|
	}
 | 
						|
	started_working_on(ml);
 | 
						|
	size = size_of(ml);
 | 
						|
	if (	/* we can simplify the problem by adding the next chunk: */
 | 
						|
		n > size &&
 | 
						|
		!last_mallink(ml) &&
 | 
						|
		(ph_next = phys_next_of(ml), free_of(ph_next)) &&
 | 
						|
		n <= size + mallink_size() + size_of(ph_next)
 | 
						|
	)	{
 | 
						|
		/* add in the physically next chunk */
 | 
						|
		unlink_free_chunk(ph_next);
 | 
						|
		combine_chunks(ml, ph_next);
 | 
						|
		size = size_of(ml);
 | 
						|
		check_mallinks("realloc, combining");
 | 
						|
	}
 | 
						|
	if (n > size)	{		/* this didn't help */
 | 
						|
		void *new;
 | 
						|
		register char *l1, *l2 = addr;
 | 
						|
 | 
						|
		stopped_working_on(ml);
 | 
						|
		if (!(new = l1 = malloc(n))) return NULL;	/* no way */
 | 
						|
		while (size--) *l1++ = *l2++;
 | 
						|
		free(addr);
 | 
						|
		check_work_empty("mv_realloc");
 | 
						|
#ifdef STORE
 | 
						|
		assert(! in_store(mallink_of_block(new)));
 | 
						|
#endif
 | 
						|
		return new;
 | 
						|
	}
 | 
						|
	/* it helped, but maybe too well */
 | 
						|
	n += mallink_size();
 | 
						|
	if (n + MIN_SIZE <= size_of(ml)) {
 | 
						|
		truncate(ml, n);
 | 
						|
	}
 | 
						|
	stopped_working_on(ml);
 | 
						|
	check_mallinks("realloc exit");
 | 
						|
	check_work_empty("realloc");
 | 
						|
#ifdef STORE
 | 
						|
	assert(! in_store(ml));
 | 
						|
#endif
 | 
						|
	return addr;
 | 
						|
}}
 | 
						|
 | 
						|
void *
 | 
						|
calloc(size_t nmemb, size_t size)
 | 
						|
{check_mallinks("calloc entry");{
 | 
						|
	long *l1, *l2;
 | 
						|
	size_t n;
 | 
						|
 | 
						|
printf("calloc\n");
 | 
						|
	if (size == 0) return NULL;
 | 
						|
	if (nmemb == 0) return NULL;
 | 
						|
 | 
						|
	/* Check for overflow on the multiplication. The peephole-optimizer
 | 
						|
	 * will eliminate all but one of the possibilities.
 | 
						|
	 */
 | 
						|
	if (sizeof(size_t) == sizeof(int)) {
 | 
						|
		if (UINT_MAX / size < nmemb) return NULL;
 | 
						|
	} else if (sizeof(size_t) == sizeof(long)) {
 | 
						|
		if (ULONG_MAX / size < nmemb) return NULL;
 | 
						|
	} else return NULL;		/* can't happen, can it ? */
 | 
						|
 | 
						|
	n = size * nmemb;
 | 
						|
	if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n);
 | 
						|
	if (n >= (1L << LOG_MAX_SIZE)) return NULL;
 | 
						|
	l1 = (long *) malloc(n);
 | 
						|
	l2 = l1 + (n / sizeof(long));	/* n is at least long aligned */
 | 
						|
	while ( l2 != l1 ) *--l2 = 0;
 | 
						|
	check_mallinks("calloc exit");
 | 
						|
	check_work_empty("calloc exit");
 | 
						|
	return (void *)l1;
 | 
						|
}}
 | 
						|
/*	Auxiliary routines */
 | 
						|
 | 
						|
#ifdef STORE
 | 
						|
private
 | 
						|
sell_out(void)	{
 | 
						|
	/*	Frees all block in store.
 | 
						|
	*/
 | 
						|
	register mallink **stp;
 | 
						|
	
 | 
						|
	for (stp = &store[0]; stp < &store[MAX_STORE]; stp++)	{
 | 
						|
		register mallink *ml = *stp;
 | 
						|
		
 | 
						|
		while (ml)	{
 | 
						|
			*stp = log_next_of(ml);
 | 
						|
			set_store(ml, 0);
 | 
						|
			do_free(ml);
 | 
						|
			ml = *stp;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
#endif /* STORE */
 | 
						|
 | 
						|
#ifdef	ASSERT
 | 
						|
private
 | 
						|
m_assert(const char *fn, int ln)
 | 
						|
{
 | 
						|
	char ch;
 | 
						|
	
 | 
						|
	while (*fn)
 | 
						|
		write(2, fn++, 1);
 | 
						|
	write(2, ": malloc assert failed in line ", 31);
 | 
						|
	ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100;
 | 
						|
	ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10;
 | 
						|
	ch = (ln / 1) + '0'; write(2, &ch, 1);
 | 
						|
	write(2, "\n", 1);
 | 
						|
	maldump(1);
 | 
						|
}
 | 
						|
#endif	/* ASSERT */
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file log.c
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
 | 
						|
/*	Logical manipulations.
 | 
						|
	The chunks are properly chained in the physical chain.
 | 
						|
*/
 | 
						|
 | 
						|
privatedata mallink *free_list[MAX_FLIST];
 | 
						|
 | 
						|
private
 | 
						|
link_free_chunk(register mallink *ml)
 | 
						|
{
 | 
						|
	/*	The free chunk ml is inserted in its proper logical
 | 
						|
		chain.
 | 
						|
	*/
 | 
						|
	register mallink **mlp = &free_list[-1];
 | 
						|
	register size_type n = size_of(ml);
 | 
						|
	register mallink *ml1;
 | 
						|
 | 
						|
	assert(n < (1L << LOG_MAX_SIZE));
 | 
						|
 | 
						|
	do {
 | 
						|
		n >>= 1;
 | 
						|
		mlp++;
 | 
						|
	}
 | 
						|
	while (n >= MIN_SIZE);
 | 
						|
 | 
						|
	ml1 = *mlp;
 | 
						|
	set_log_prev(ml, MAL_NULL);
 | 
						|
	set_log_next(ml, ml1);
 | 
						|
	calc_checksum(ml);
 | 
						|
	if (ml1) {
 | 
						|
		/* link backwards
 | 
						|
		*/
 | 
						|
		set_log_prev(ml1, ml);
 | 
						|
		calc_checksum(ml1);
 | 
						|
	}
 | 
						|
	*mlp = ml;
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
unlink_free_chunk(register mallink *ml)
 | 
						|
{
 | 
						|
	/*	Unlinks a free chunk from (the middle of) the
 | 
						|
		logical chain.
 | 
						|
	*/
 | 
						|
	register mallink *next = log_next_of(ml);
 | 
						|
	register mallink *prev = log_prev_of(ml);
 | 
						|
 | 
						|
	if (!prev)	{
 | 
						|
		/* it is the first in the chain */
 | 
						|
		register mallink **mlp = &free_list[-1];
 | 
						|
		register size_type n = size_of(ml);
 | 
						|
 | 
						|
		assert(n < (1L << LOG_MAX_SIZE));
 | 
						|
		do {
 | 
						|
			n >>= 1;
 | 
						|
			mlp++;
 | 
						|
		}
 | 
						|
		while (n >= MIN_SIZE);
 | 
						|
		*mlp = next;
 | 
						|
	}
 | 
						|
	else	{
 | 
						|
		set_log_next(prev, next);
 | 
						|
		calc_checksum(prev);
 | 
						|
	}
 | 
						|
	if (next) {
 | 
						|
		set_log_prev(next, prev);
 | 
						|
		calc_checksum(next);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
private mallink *
 | 
						|
search_free_list(int class, size_t n)
 | 
						|
{
 | 
						|
	/*	Searches the free_list[class] for a chunk of at least size n;
 | 
						|
		since it is searching a slightly undersized list,
 | 
						|
		such a block may not be there.
 | 
						|
	*/
 | 
						|
	register mallink *ml;
 | 
						|
	
 | 
						|
	for (ml = free_list[class]; ml; ml = log_next_of(ml))
 | 
						|
		if (size_of(ml) >= n)
 | 
						|
			return ml;
 | 
						|
	return MAL_NULL;		/* nothing found */
 | 
						|
}
 | 
						|
 | 
						|
private mallink *
 | 
						|
first_present(int class)
 | 
						|
{
 | 
						|
	/*	Find the index i in free_list[] such that:
 | 
						|
			i >= class && free_list[i] != MAL_NULL.
 | 
						|
		Return MAL_NULL if no such i exists;
 | 
						|
		Otherwise, return the first block of this list, after
 | 
						|
		unlinking it.
 | 
						|
	*/
 | 
						|
	register mallink **mlp, *ml;
 | 
						|
 | 
						|
	for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) {
 | 
						|
		if ((ml = *mlp) != MAL_NULL)	{
 | 
						|
	
 | 
						|
			*mlp = log_next_of(ml);	/* may be MAL_NULL */
 | 
						|
			if (*mlp) {
 | 
						|
				/* unhook backward link
 | 
						|
				*/
 | 
						|
				set_log_prev(*mlp, MAL_NULL);
 | 
						|
				calc_checksum(*mlp);
 | 
						|
			}
 | 
						|
			return ml;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return MAL_NULL;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef	CHECK
 | 
						|
private mallink *
 | 
						|
free_list_entry(int i)	{
 | 
						|
	/*	To allow maldump.c access to log.c's private data.
 | 
						|
	*/
 | 
						|
	return free_list[i];
 | 
						|
}
 | 
						|
#endif	/* CHECK */
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file phys.c
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
#include	<stdlib.h>
 | 
						|
 | 
						|
/*	Physical manipulations.
 | 
						|
	The blocks concerned are not in any logical chain.
 | 
						|
*/
 | 
						|
 | 
						|
private mallink *
 | 
						|
create_chunk(void *p, size_t n)
 | 
						|
{
 | 
						|
	/*	The newly acquired piece of memory at p, of length n,
 | 
						|
		is turned into a free chunk, properly chained in the
 | 
						|
		physical chain.
 | 
						|
		The address of the chunk is returned.
 | 
						|
	*/
 | 
						|
	register mallink *ml;
 | 
						|
	/*	All of malloc memory is followed by a virtual chunk, the
 | 
						|
		mallink of which starts mallink_size() bytes past the last
 | 
						|
		byte in memory.
 | 
						|
		Its use is prevented by testing for ml == ml_last first.
 | 
						|
	*/
 | 
						|
	register mallink *last = ml_last;
 | 
						|
	
 | 
						|
	assert(!last || p == (char *)phys_next_of(last) - mallink_size());
 | 
						|
	ml = (mallink *)((char *)p + mallink_size());	/* bump ml */
 | 
						|
	new_mallink(ml);
 | 
						|
	started_working_on(ml);
 | 
						|
	set_free(ml, 1);
 | 
						|
	set_phys_prev(ml, last);
 | 
						|
	ml_last = ml;
 | 
						|
 | 
						|
	set_phys_next(ml, (mallink *)((char *)ml + n));
 | 
						|
	calc_checksum(ml);
 | 
						|
	assert(size_of(ml) + mallink_size() == n);
 | 
						|
	if (last && free_of(last)) {
 | 
						|
		coalesce_backw(ml, last);
 | 
						|
		ml = last;
 | 
						|
	}
 | 
						|
	check_mallinks("create_chunk, phys. linked");
 | 
						|
	return ml;
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
truncate(register mallink *ml, size_t size)
 | 
						|
{
 | 
						|
	/*	The chunk ml is truncated.
 | 
						|
		The chunk at ml is split in two.
 | 
						|
		The remaining part is then freed.
 | 
						|
	*/
 | 
						|
	register mallink *new = (mallink *)((char *)ml + size);
 | 
						|
	register mallink *ph_next = phys_next_of(ml);
 | 
						|
 | 
						|
	new_mallink(new);
 | 
						|
	set_free(new, 1);
 | 
						|
	set_phys_prev(new, ml);
 | 
						|
	set_phys_next(new, ph_next);
 | 
						|
	calc_checksum(new);
 | 
						|
	if (! last_mallink(ml))	{
 | 
						|
		set_phys_prev(ph_next, new);
 | 
						|
		calc_checksum(ph_next);
 | 
						|
		if (free_of(ph_next)) coalesce_forw(new, ph_next);
 | 
						|
	}
 | 
						|
	else	ml_last = new;
 | 
						|
	set_phys_next(ml, new);
 | 
						|
	calc_checksum(ml);
 | 
						|
 | 
						|
	started_working_on(new);
 | 
						|
	link_free_chunk(new);
 | 
						|
	stopped_working_on(new);
 | 
						|
	check_mallinks("truncate");
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
combine_chunks(register mallink *ml1, register mallink *ml2)
 | 
						|
{
 | 
						|
	/*	The chunks ml1 and ml2 are combined.
 | 
						|
	*/
 | 
						|
	register mallink *ml3 = phys_next_of(ml2);
 | 
						|
 | 
						|
	set_phys_next(ml1, ml3);
 | 
						|
	calc_checksum(ml1);
 | 
						|
	if (!last_mallink(ml2))	{
 | 
						|
		set_phys_prev(ml3, ml1);
 | 
						|
		calc_checksum(ml3);
 | 
						|
	}
 | 
						|
	if (ml_last == ml2)
 | 
						|
		ml_last = ml1;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**********************************************************/
 | 
						|
/*
 | 
						|
/*		 This was file check.c
 | 
						|
/*
 | 
						|
/**********************************************************/
 | 
						|
 | 
						|
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
#include	<stdio.h>
 | 
						|
 | 
						|
#ifdef	CHECK			/* otherwise this whole file is skipped */
 | 
						|
 | 
						|
/* ??? check these later */
 | 
						|
private acquire_malout(void), check_ml_last(const char *s);
 | 
						|
private dump_all_mallinks(void), dump_free_list(int i);
 | 
						|
private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
 | 
						|
private working_on(mallink *ml);
 | 
						|
private size_type checksum(mallink *ml);
 | 
						|
static FILE *malout;
 | 
						|
 | 
						|
private mallink *free_list_entry(int i);
 | 
						|
 | 
						|
#define	for_free_list(i,p) \
 | 
						|
	for (p = free_list_entry(i); p; p = log_next_of(p))
 | 
						|
 | 
						|
#define	for_all_mallinks(ml)	/* backwards! */ \
 | 
						|
	for (ml = ml_last; ml; \
 | 
						|
		ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
 | 
						|
 | 
						|
/* Maldump */
 | 
						|
 | 
						|
static int pr_cnt = 0;
 | 
						|
 | 
						|
maldump(int n)	{
 | 
						|
	/*	Dump pertinent info in pseudo-readable format;
 | 
						|
		abort afterwards if n != 0.
 | 
						|
	*/
 | 
						|
	static int dumping = 0;
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	if (dumping)
 | 
						|
		return;
 | 
						|
	dumping++;
 | 
						|
	acquire_malout();
 | 
						|
	fprintf(malout,
 | 
						|
		">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
 | 
						|
	fprintf(malout, "    ml_last = %p\n", ml_last);
 | 
						|
	if (++pr_cnt == 100) pr_cnt = 0;
 | 
						|
	dump_all_mallinks();
 | 
						|
	fprintf(malout,
 | 
						|
		">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
 | 
						|
	if (++pr_cnt == 100) pr_cnt = 0;
 | 
						|
	for (i = 0; i < MAX_FLIST; i++)
 | 
						|
		dump_free_list(i);
 | 
						|
	fprintf(malout,
 | 
						|
		">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
 | 
						|
	fclose(malout);
 | 
						|
	dumping--;
 | 
						|
	if (n)
 | 
						|
		abort();
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
acquire_malout(void)	{
 | 
						|
	static char buf[BUFSIZ];
 | 
						|
	
 | 
						|
	if (!malout)	{
 | 
						|
		malout = freopen("mal.out", "w", stderr);	
 | 
						|
		setbuf(malout, buf);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
dump_all_mallinks(void)	{
 | 
						|
	mallink *ml;
 | 
						|
	
 | 
						|
	for_all_mallinks (ml)	{
 | 
						|
		if (print_loop(ml))
 | 
						|
			return;
 | 
						|
		dump_mallink((char *)0, ml);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
dump_free_list(int i)	{
 | 
						|
	mallink *ml = free_list_entry(i);
 | 
						|
	
 | 
						|
	if (!ml)
 | 
						|
		return;
 | 
						|
	fprintf(malout, "%2d: ", i);
 | 
						|
	for_free_list(i, ml)	{
 | 
						|
		if (print_loop(ml))
 | 
						|
			return;
 | 
						|
		fprintf(malout, "%p ", ml);
 | 
						|
	}
 | 
						|
	fprintf(malout, "<\n");
 | 
						|
}
 | 
						|
 | 
						|
private int
 | 
						|
print_loop(mallink *ml)	{
 | 
						|
	if (print_of(ml) == pr_cnt)	{
 | 
						|
		fprintf(malout, "... PRINT LOOP\n");
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	set_print(ml, pr_cnt);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
dump_mallink(const char *s, mallink *ml)	{
 | 
						|
	acquire_malout();
 | 
						|
	if (s)
 | 
						|
		fprintf(malout, "%s: ", s);
 | 
						|
	fprintf(malout, "@: %p;", ml);
 | 
						|
	if (ml && checksum_of(ml) != checksum(ml))
 | 
						|
		fprintf(malout, ">>>> CORRUPTED <<<<");
 | 
						|
	if (!ml)	{
 | 
						|
		fprintf(malout, "\n");
 | 
						|
		return;
 | 
						|
	}	
 | 
						|
	if (free_of(ml))	{
 | 
						|
		fprintf(malout, " l_p: %p;", _log_prev_of(ml));
 | 
						|
		fprintf(malout, " l_n: %p;", _log_next_of(ml));
 | 
						|
	}
 | 
						|
	fprintf(malout, " p_s: %p;", prev_size_of(ml));
 | 
						|
	fprintf(malout, " t_s: %p;", _this_size_of(ml));
 | 
						|
	fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
 | 
						|
	fprintf(malout, " fr: %d;", free_of(ml));
 | 
						|
	fprintf(malout, "\n");
 | 
						|
}
 | 
						|
 | 
						|
/*	Check_mallinks() checks the total data structure as accessible
 | 
						|
	through free_list[] and ml_last.  All check_sums should be OK,
 | 
						|
	except those held in the small array off_colour.  This is a
 | 
						|
	trick to allow to continue checking even when a few mallinks
 | 
						|
	are temporarily out of order.
 | 
						|
	Check_mallinks() tests for a lot of internal consistency.
 | 
						|
*/
 | 
						|
 | 
						|
/* Some arbitrary constants */
 | 
						|
#define	IN_ML_LAST	93
 | 
						|
#define	IN_FREE_LIST	57		/* and in ml_last */
 | 
						|
#define	CLEAR		21
 | 
						|
 | 
						|
#define	VRIJ		1
 | 
						|
#define	BEZET		2
 | 
						|
 | 
						|
private
 | 
						|
check_mallinks(const char *s)	{
 | 
						|
	mallink *ml;
 | 
						|
	size_type size;
 | 
						|
	int i;
 | 
						|
	char stat;
 | 
						|
	
 | 
						|
	check_ml_last(s);
 | 
						|
	stat = BEZET;
 | 
						|
	for_all_mallinks(ml)	{
 | 
						|
		if (checksum_of(ml) != checksum(ml))
 | 
						|
			Error("mallink info at %p corrupted", s, ml);
 | 
						|
		if (working_on(ml))	{
 | 
						|
			stat = BEZET;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if (	!last_mallink(ml) &&
 | 
						|
			phys_prev_of(phys_next_of(ml)) != ml
 | 
						|
		)
 | 
						|
			Error("upward chain bad at %p", s, ml);
 | 
						|
		if (	!first_mallink(ml) &&
 | 
						|
			phys_next_of(phys_prev_of(ml)) != ml
 | 
						|
		)
 | 
						|
			Error("downward chain bad at %p", s, ml);
 | 
						|
		if (free_of(ml))	{
 | 
						|
			if (stat == VRIJ)
 | 
						|
				Error("free mallink at %p follows free mallink",
 | 
						|
								s, ml);
 | 
						|
			stat = VRIJ;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			stat = BEZET;
 | 
						|
		set_mark(ml, IN_ML_LAST);
 | 
						|
	}
 | 
						|
	
 | 
						|
	for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2)	{
 | 
						|
		for_free_list(i, ml)	{
 | 
						|
			if (working_on(ml))
 | 
						|
				continue;
 | 
						|
			if (!free_of(ml))
 | 
						|
				Error("occupied mallink %p occurs in free_list", s, ml);
 | 
						|
			switch (mark_of(ml))	{
 | 
						|
			case IN_ML_LAST:
 | 
						|
				set_mark(ml, IN_FREE_LIST);
 | 
						|
				break;
 | 
						|
			case IN_FREE_LIST:
 | 
						|
				Error("mallink %p occurs in 2 free_lists",
 | 
						|
								s, ml);
 | 
						|
			default:
 | 
						|
				Error("unknown mallink %p in free_list",
 | 
						|
								s, ml);
 | 
						|
			}
 | 
						|
			if (size_of(ml) < size)
 | 
						|
				Error("size of mallink %p too small", s, ml);
 | 
						|
			if (size_of(ml) >= 2*size)
 | 
						|
				Error("size of mallink %p too large", s, ml);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for_all_mallinks (ml)	{
 | 
						|
		if (working_on(ml))
 | 
						|
			continue;
 | 
						|
		if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
 | 
						|
			Error("free mallink %p is in no free_list", s, ml);
 | 
						|
		set_mark(ml, CLEAR);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
check_ml_last(const char *s)	{
 | 
						|
	if (ml_last && _this_size_of(ml_last) == 0)
 | 
						|
		Error("size of ml_last == 0, at %p", s, ml_last);
 | 
						|
}
 | 
						|
 | 
						|
private size_type
 | 
						|
checksum(mallink *ml)	{
 | 
						|
	size_type sum = 0;
 | 
						|
	
 | 
						|
	if (free_of(ml))	{
 | 
						|
		sum += (size_type)_log_prev_of(ml);
 | 
						|
		sum += (size_type)_log_next_of(ml);
 | 
						|
	}
 | 
						|
	sum += (size_type)prev_size_of(ml);
 | 
						|
	sum += (size_type)_this_size_of(ml);
 | 
						|
	return sum;
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
calc_checksum(mallink *ml)	{
 | 
						|
	set_checksum(ml, checksum(ml));
 | 
						|
}
 | 
						|
 | 
						|
#define	N_COLOUR	10
 | 
						|
static mallink *off_colour[N_COLOUR];
 | 
						|
 | 
						|
private
 | 
						|
started_working_on(mallink *ml)	{
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < N_COLOUR; i++)
 | 
						|
		if (off_colour[i] == MAL_NULL)	{
 | 
						|
			off_colour[i] = ml;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	Error("out of off_colour array at %p", "started_working_on", ml);
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
stopped_working_on(mallink *ml)	{
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < N_COLOUR; i++)
 | 
						|
		if (off_colour[i] == ml)	{
 | 
						|
			off_colour[i] = MAL_NULL;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	Error("stopped working on mallink %p", "stopped_working_on", ml);
 | 
						|
}
 | 
						|
 | 
						|
private int
 | 
						|
working_on(mallink *ml)	{
 | 
						|
	int i;
 | 
						|
	
 | 
						|
	for (i = 0; i < N_COLOUR; i++)
 | 
						|
		if (off_colour[i] == ml)
 | 
						|
			return 1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
private
 | 
						|
check_work_empty(const char *s)	{
 | 
						|
	int i;
 | 
						|
	int cnt = 0;
 | 
						|
	
 | 
						|
	for (i = 0; i < N_COLOUR; i++)
 | 
						|
		if (off_colour[i] != MAL_NULL)
 | 
						|
			cnt++;
 | 
						|
	if (cnt != 0)
 | 
						|
		Error("off_colour not empty", s, MAL_NULL);
 | 
						|
}
 | 
						|
 | 
						|
private int
 | 
						|
Error(const char *fmt, const char *s, mallink *ml)	{
 | 
						|
	static int already_called = 0;
 | 
						|
 | 
						|
	if (already_called++) return 0;
 | 
						|
	setbuf(stdout, (char *) 0);
 | 
						|
	printf("%s: ", s);
 | 
						|
	printf(fmt, (long)ml);
 | 
						|
	printf("\n");
 | 
						|
	acquire_malout();
 | 
						|
	fprintf(malout, "%s: ", s);
 | 
						|
	fprintf(malout, fmt, (long)ml);
 | 
						|
	fprintf(malout, "\n");
 | 
						|
	fflush(stdout);
 | 
						|
	maldump(1);
 | 
						|
	return 0;			/* to satisfy lint */
 | 
						|
}
 | 
						|
 | 
						|
#endif	/* CHECK */
 | 
						|
 |