
/*
 *         PVM version 3.3:  Parallel Virtual Machine System
 *               University of Tennessee, Knoxville TN.
 *           Oak Ridge National Laboratory, Oak Ridge TN.
 *                   Emory University, Atlanta GA.
 *      Authors:  A. L. Beguelin, J. J. Dongarra, G. A. Geist,
 *    W. C. Jiang, R. J. Manchek, B. K. Moore, and V. S. Sunderam
 *                   (C) 1992 All Rights Reserved
 *
 *                              NOTICE
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted
 * provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * Neither the Institutions (Emory University, Oak Ridge National
 * Laboratory, and University of Tennessee) nor the Authors make any
 * representations about the suitability of this software for any
 * purpose.  This software is provided ``as is'' without express or
 * implied warranty.
 *
 * PVM version 3 was funded in part by the U.S. Department of Energy,
 * the National Science Foundation and the State of Tennessee.
 */

/*
 *	pvmumbuf.c
 *
 *	Libpvm message descriptors
 *
$Log: pvmumbuf.c,v $
 * Revision 1.3  1994/06/04  21:46:24  manchek
 * ripped out old cruft
 *
 * Revision 1.2  1994/06/03  20:38:26  manchek
 * version 3.3.0
 *
 * Revision 1.1  1993/08/30  23:26:51  manchek
 * Initial revision
 *
 */

#include <stdio.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <pvm3.h>
#include "pvmalloc.h"
#include "pvmfrag.h"
#include "pvmumbuf.h"
#include "listmac.h"
#include "bfunc.h"


/***************
 **  Globals  **
 **           **
 ***************/

struct mhp *pvmmidh = 0;			/* heap of all msgs */
int pvmmidhsiz = 0;					/* length of pvmmidh */


/***************
 **  Private  **
 **           **
 ***************/

static char rcsid[] = "$Id: pvmumbuf.c,v 1.3 1994/06/04 21:46:24 manchek Exp $";
static char pvmtxt[512];			/* scratch for error log */
static int pvmmidhfree = 0;			/* head of midh free list */


/*	mid_new()
*
*	Allocate a message id for a new message.
*	Returns mid (>0) or PvmNoMem if can't get memory.
*/

int
mid_new()
{
	static int nxtmidhsiz;
	int mid;
	int ns;

	/* check free list empty */

	if (!pvmmidhfree) {

	/* extend midh array */

		if (pvmmidhsiz) {
			ns = nxtmidhsiz;
			nxtmidhsiz += pvmmidhsiz;
			pvmmidh = TREALLOC(pvmmidh, ns, struct mhp);
		} else {
			nxtmidhsiz = 13;
			ns = 8;
			pvmmidh = TALLOC(ns, struct mhp, "mid");
		}
		if (!pvmmidh)
			return PvmNoMem;

	/* put new entries on free list */

		while (pvmmidhsiz < ns) {
			pvmmidh[pvmmidhsiz].m_umb = 0;
			pvmmidh[pvmmidhsiz].m_free = pvmmidhfree;
			pvmmidhfree = pvmmidhsiz++;
		}
	}

	/* take next if from free list */

	mid = pvmmidhfree;
	pvmmidhfree = pvmmidh[pvmmidhfree].m_free;
	return mid;
}


/*	mid_free()
*
*	Return a message id to the free list.
*/

void
mid_free(mid)
	int mid;
{
	if (mid <= 0 || mid >= pvmmidhsiz || !pvmmidh[mid].m_umb)
		return;
	pvmmidh[mid].m_umb = 0;
	pvmmidh[mid].m_free = pvmmidhfree;
	pvmmidhfree = mid;
}


/*	umbuf_new()
*
*	Create a new empty message.
*	Return the mid or PvmNoMem if malloc fails.
*/

int
umbuf_new()
{
	struct umbuf *up;

	if (!(up = TALLOC(1, struct umbuf, "umb")))
		goto nomem;

	BZERO((char*)up, sizeof(struct umbuf));
	if ((up->ub_mid = mid_new()) < 0)
		goto nomem;
	pvmmidh[up->ub_mid].m_umb = up;
	up->ub_frag = fr_new(0);
	return up->ub_mid;

nomem:
	if (up)
		PVM_FREE(up);
	return PvmNoMem;
}


/*	umbuf_free()
*
*	Free a message and all its resources.  Unlink it from any list
*	and recycle its mid.
*	Returns 0 if okay, else PvmNoSuchBuf if id bogus.
*/

int
umbuf_free(mid)
	int mid;
{
	struct umbuf *up;

	if (mid < 0)
		return PvmBadParam;
	if (!mid)
		return 0;
	if (mid >= pvmmidhsiz || !pvmmidh[mid].m_umb)
		return PvmNoSuchBuf;

	up = pvmmidh[mid].m_umb;
	if (up->ub_link && up->ub_rlink) {
		LISTDELETE(up, ub_link, ub_rlink);
	}
	fr_unref(up->ub_frag);
	mid_free(up->ub_mid);
	PVM_FREE(up);
	return 0;
}


/*	midtobuf()
*
*	Return pointer to message buffer given int message id.
*/

struct umbuf*
midtobuf(mid)
	int mid;
{
	return ((mid > 0 && mid < pvmmidhsiz) ? pvmmidh[mid].m_umb : 0);
}


umbuf_dump(mid, lvl)
	int mid;
	int lvl;	/* 0 - summary, 1 - frag lengths, 2 - frag data */
{
	struct umbuf *up;
	struct frag *fp;

	if (mid <= 0) {
		sprintf(pvmtxt, "umbuf_dump() BadParam\n");
		pvmlogerror(pvmtxt);
		return PvmBadParam;
	}
	if (mid >= pvmmidhsiz || !pvmmidh[mid].m_umb) {
		sprintf(pvmtxt, "umbuf_dump() NoSuchBuf\n");
		pvmlogerror(pvmtxt);
		return PvmNoSuchBuf;
	}

	up = pvmmidh[mid].m_umb;
	if (up->ub_flag & UB_PACK)
		setublen(up);
	sprintf(pvmtxt, "umbuf_dump() mid=%d 0x%x src=t%x enc=%d cod=%d len=%d\n",
			mid, up, up->ub_src, up->ub_enc, up->ub_cod, up->ub_len);
	pvmlogerror(pvmtxt);
	if (lvl > 0) {
		for (fp = up->ub_frag->fr_link; fp != up->ub_frag; fp = fp->fr_link) {
			sprintf(pvmtxt, " frag=0x%x max=%d ofs=%d len=%d\n",
				fp, fp->fr_max, fp->fr_dat - fp->fr_buf, fp->fr_len);
			pvmlogerror(pvmtxt);
			if (lvl > 1)
				pvmhdump(fp->fr_dat, fp->fr_len, "  ");
		}
	}
	return 0;
}


umbuf_list(lvl)
	int lvl;
{
	int i;
	struct umbuf *up;
	struct frag *fp;
	int rlen;

	for (i = 1; i < pvmmidhsiz; i++)
		if (up = pvmmidh[i].m_umb)
			umbuf_dump(i, lvl);
}


int
setublen(up)
	struct umbuf *up;
{
	struct frag *fp, *fp2;
	int l = 0;

	fp = fp2 = up->ub_frag;
	while ((fp = fp->fr_link) != fp2)
		l += fp->fr_len;
	return up->ub_len = l;
}


