
/* Copyright 1984 by the Massachusetts Institute of Technology */

/* The memory management is extremely simple.  Since it is not necessary
 * to ever free memory, a trivial allocator and no memory freer is needed.
 */

/*
 *------------------------------------------------------------------
 *
 * $Source: /mit/cgw/src/sys/src/RCS/mem.c,v $
 * $Revision: 1.2 $
 * $Date: 89/11/13 22:18:53 $
 * $State: Exp $
 * $Author: jon $
 * $Locker: jon $
 *
 * $Log:	mem.c,v $
 * Revision 1.2  89/11/13  22:18:53  jon
 * increase the amount of memory allocated to buffers.
 * 
 *------------------------------------------------------------------
 */

#ifndef lint
static char *rcsid_mem_c = "$Header: /mit/cgw/src/sys/src/RCS/mem.c,v 1.2 89/11/13 22:18:53 jon Exp Locker: jon $";
#endif	lint

#include	<types.h>
#include	"../include/sys.h"
 
ext byte	END_OF_MEMORY;
ext unsl	himem;		/* contains the last address of real memory */
byte		*end_mem;
int	FRMEM;		/* this should go away soon */

#define NULL 0


/* Defs for alloc(). */
struct header {			/* free block header */
    struct header *ptr;		/* next free block */
    unsl size;			/* size of this free block */
};

struct header base;		/* empty base to get started */
struct header *allocp;		/* last allocated block */


/* initialize memory allocation */
mem_init()
{
/*    printf("MEMINIT:\n"); */
    end_mem = &END_OF_MEMORY;
    FRMEM = 65536*8;

    /* init for alloc() */
    base.ptr = allocp = &base;
}

/* allocate size bytes */
byte *mem_alloc(size)
reg int	size;
{
    reg byte	*hold;

    hold = end_mem;
    size = even(size);
    if (end_mem + size >= himem)
      return (NULL);
    end_mem += size;
    FRMEM -= size;
    return hold;
}



/* Added this memory allocator because it turned out I eventually did
 * want to free memory sometimes.  It is just the alloc() and free()
 * straight from K&R.  I should probably pick up the malloc that GNU
 * has.  It looks to be much faster than this one.
 */
byte *alloc(nbytes)
unsl nbytes;
{
    struct header *morecore();
    reg struct header *p, *q;
    reg int nunits;

    nunits = 1 + (nbytes + sizeof(struct header) - 1) / sizeof(struct header);
    q = allocp;
    for (p = q->ptr; ; q = p, p = p->ptr) {
	if (p->size >= nunits) { /* big enough */
	    if (p->size == nunits) /* exactly */
	      q->ptr = p->ptr;
	    else {		/* allocate tail end */
		p->size -= nunits;
		p += p->size;
		p->size = nunits;
	    }
	    allocp = q;
	    return ((byte *)(p+1));
	}
	if (p == allocp)	/* wrapped around free list */
	  if ((p = morecore(nunits)) == NULL)
	    return (NULL);	/* none left */
    }
}

#define NALLOC 1024		/* #units to allocate at once */

struct header *morecore(nu)
unsl nu;
{
    reg byte *cp;
    reg struct header *up;
    reg unsl rnu;

    rnu = NALLOC * ((nu + NALLOC - 1) / NALLOC);
    cp = mem_alloc(rnu * sizeof(struct header));
    if (cp == NULL)
      return (NULL);
    up = (struct header *)cp;
    up->size = rnu;
    free((byte *)(up + 1));
    return (allocp);
}

free(ap)
byte *ap;
{
    reg struct header *p, *q;

    p = (struct header *)ap - 1; /* point to header */
    for (q = allocp; !(p > q && p < q->ptr); q = q->ptr)
      if (q >= q->ptr && (p > q || p < q->ptr))
	break;			/* at one end or other */

    if (p + p->size == q->ptr) { /* join to upper nbr */
	p->size += q->ptr->size;
	p->ptr = q->ptr->ptr;
    }
    else {
	p->ptr = q->ptr;
    }

    if (q + q->size == p) {	/* join to lower nbr */
	q->size += p->size;
	q->ptr = p->ptr;
    }
    else {
	q->ptr = p;
    }
    allocp = q;
}
