#define NULL 0
ENV

/* xx_mem is a memory allocation routine.  It is called in three
   ways:
	if typ == 0, then n is the number of bytes to claim as
	    globally-shared memory (from which routines can
	    ask for shared memory).  In this case the routine
	    returns the address of the allocated block (NULL,
	    if an allocation failure occurs).

	else if typ == 1, then n is taken to be the amount
	    of shared memory requested.  In this case, the
	    routine returns the address of a block of at least
	    n charecters in length.

	else if typ == 2, then the routine is being asked
	    to return the address of the globally-
	    shared block of memory.  

The view of shared memory supported by xx_mem is that a single
massive chunk of memory is acquired (and handed out by 
xx_mem(1,...) calls).
*/

struct mem_blk {
    char *next;
    int l_mem;
	LOCKDEC(MEM)
    slock_t mlock;
};

char *xx_mem(typ,n)
int typ,n;
{
char *shmalloc();
static struct mem_blk *glob_mem =  (struct mem_blk *) NULL;
static int l_mem = 0;
char *rc;
int i;
char *c;

    switch (typ)
    {
    case 0:  /* initialize */
	/* pad & malloc */
	if ((c = shmalloc((n+sizeof(struct mem_blk)))) == NULL)
	{
	    printf("*** malloc failed during shared memory initialization ***\n");
	    printf("shmalloc failed asking for %d\n",
		    (n+sizeof(struct mem_blk)));
	    exit(3);
	}
	else
	{

	    glob_mem = (struct mem_blk *) c;
	    glob_mem->next = c + sizeof(struct mem_blk);
	    glob_mem->l_mem = n;
	    rc = glob_mem->next;
		/*
	    glob_mem->MEM.lock = &(glob_mem->mlock);
		*/
	    s_init_lock(&(glob_mem->MEM.lock));
	}
	break;

    case 1:
	i = (n + 7) & (~007);
	LOCK(glob_mem->MEM)
	if (glob_mem->l_mem < i)
	{
	    printf("*** global allocation failure ***\n");
	    printf("*** attempted %d bytes, %d left\n",
		   i,glob_mem->l_mem);
	    rc = NULL;
	    UNLOCK(glob_mem->MEM)
	    exit(3);
	}
	else
	{
	    rc = glob_mem->next;
	    glob_mem->next += i; 
	    glob_mem->l_mem -= i; 
	    /* B
	    printf("allocated %d bytes of shared memory\n",i);
	    printf("at %d\n",rc);
	    E */
	}
	UNLOCK(glob_mem->MEM)
	break;

    case 2:
	rc = (char *) glob_mem;
	break;

    default:
	printf("*** illegal call to xx_mem *** typ=%d\n",typ);
    }
    return(rc);
}
