ack/util/ass/asscm.c
2019-03-17 22:46:32 +08:00

148 lines
3.2 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*
*/
/* Core management for the EM assembler.
two routines:
getarea(size)
returns a pointer to a free area of 'size' bytes.
freearea(ptr,size)
free's the area of 'size' bytes pointed to by ptr
Free blocks are linked together and kept sorted.
Adjacent free blocks are collapsed.
Free blocks with a size smaller then the administration cannot
exist.
The algorithm is first fit.
*/
#include "ass00.h"
#include "assex.h"
#include "asscm.h"
#ifdef MEMUSE
static unsigned m_used = 0;
static unsigned m_free = 0;
#endif
struct freeblock
{
struct freeblock *f_next;
unsigned f_size;
};
static struct freeblock freexx[2] =
{
{ freexx, 0 },
{ freexx + 1, 0 } };
#define freehead freexx[1]
#define CHUNK 2048 /* Smallest chunk to be gotten from UNIX */
area_t getarea(unsigned int size)
{
register struct freeblock *c_ptr, *l_ptr;
register char *ptr;
unsigned rqsize;
size = ((size + (sizeof(int) - 1)) / sizeof(int)) * sizeof(int);
#ifdef MEMUSE
m_used += size;
m_free -= size;
#endif
for (;;)
{
for (l_ptr = &freehead, c_ptr= freehead.f_next;
c_ptr!= &freehead; c_ptr = c_ptr->f_next )
{
if ( size==c_ptr->f_size )
{
l_ptr->f_next= c_ptr->f_next;
return (area_t) c_ptr;
}
if ( size+sizeof freehead <= c_ptr->f_size )
{
c_ptr->f_size -= size;
return (area_t) ((char *) c_ptr + c_ptr->f_size);
}
l_ptr = c_ptr;
}
rqsize = size<CHUNK ? CHUNK : size;
for(;;)
{
ptr = malloc( rqsize );
if ( ptr ) break; /* request succesfull */
rqsize /= 2;
rqsize -= rqsize%sizeof (int);
if ( rqsize < sizeof freehead )
{
fatal("Out of memory");
}
}
freearea((area_t)ptr,rqsize);
#ifdef MEMUSE
m_used += rqsize;
#endif
}
/* NOTREACHED */
}
void freearea(register area_t ptr, unsigned int size)
{
register struct freeblock *c_ptr, *l_ptr;
size = ((size + (sizeof(int) - 1)) / sizeof(int)) * sizeof(int);
#ifdef MEMUSE
m_free += size;
m_used -= size;
#endif
for (l_ptr = &freehead, c_ptr=freehead.f_next;
c_ptr!= &freehead; c_ptr= c_ptr->f_next )
{
if ( (area_t)c_ptr>ptr ) break;
l_ptr= c_ptr;
}
/* now insert between l_ptr and c_ptr */
/* Beware they may both point to freehead */
#ifdef MEMUSE
if (((char *) l_ptr) + l_ptr->f_size > (char *) ptr
&& (char *) l_ptr <= (char *) ptr)
fatal("Double freed");
if (((char *) ptr) + size > (char *) c_ptr
&& (char *) ptr <= (char *) c_ptr)
fatal("Frreed double");
#endif
/* Is the block before this one adjacent ? */
if (((char *) l_ptr) + l_ptr->f_size == (char *) ptr)
{
l_ptr->f_size += size;
/* yes */
}
else
{
/* No, create an entry */
((struct freeblock *) ptr)->f_next = c_ptr;
((struct freeblock *) ptr)->f_size = size;
l_ptr->f_next = (struct freeblock *) ptr;
l_ptr = (struct freeblock *) ptr;
}
/* Are the two entries adjacent ? */
if ((char *) l_ptr + l_ptr->f_size == (char *) c_ptr)
{
/* the two entries are adjacent */
l_ptr->f_next = c_ptr->f_next;
l_ptr->f_size += c_ptr->f_size;
}
}
#ifdef MEMUSE
void memuse(void)
{
printf("Free %7u, Used %7u, Total %7u\n", m_free, m_used, m_free + m_used);
}
#endif