148 lines
3.2 KiB
C
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
|