
/*
 *           PVM 3.2:  Parallel Virtual Machine System 3.2
 *               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 3.2 was funded in part by the U.S. Department of Energy, the
 * National Science Foundation and the State of Tennessee.
 */

/*
 *	waitc.c
 *
 *	Wait context descriptors.
 *
$Log: waitc.c,v $
 * Revision 1.1  1993/08/30  23:26:52  manchek
 * Initial revision
 *
 */

#include <stdio.h>
#ifdef IMA_TITN
#include <bsd/sys/types.h>
#else
#include <sys/types.h>
#endif
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include "global.h"
#include "protoglarp.h"
#include "pvmalloc.h"
#include "mesg.h"
#include "host.h"
#include "waitc.h"
#include "listmac.h"
#include "bfunc.h"

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

extern void pvmbailout();
char *dmname();

extern struct htab *hosts;			/* from pvmd.c */
extern int myhostpart;				/* from pvmd.c */
extern int tidlmask;				/* from pvmd.c */

struct waitc *waitlist = 0;


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

static char rcsid[] = "$Id: waitc.c,v 1.1 1993/08/30 23:26:52 manchek Exp $";
static char pvmtxt[512];				/* scratch for error log */
static char *waitnames[] = {
	"addhost", "spawn", "hoststart", "task",
	"delhost", "htupd", "pstat", "taskx",
	"mstat", "db", "hostf", "hosta"
};


static char *
waitkind(kind)
	int kind;
{
	if (kind < 1 || kind > sizeof(waitnames)/sizeof(waitnames[0]))
		return "???";
	return waitnames[kind - 1];
}


/*****************
 **  Interface  **
 **             **
 *****************/

/*	wait_init()
*
*	Call this boy before any other wait stuff.
*/

void
wait_init()
{
	if (!waitlist) {
		waitlist = TALLOC(1, struct waitc, "wait");
		BZERO((char*)waitlist, sizeof(struct waitc));
		waitlist->wa_link = waitlist;
		waitlist->wa_rlink = waitlist;
	}
}


/*	wait_new()
*
*	Create new wait context of given kind with no peers.  Add to
*	active list.
*/

struct waitc *
wait_new(kind)
	int kind;
{
	static int lastwid = 0;		/* last wid assigned */

	int startwid;				/* to detect when we've tried all */
	int wid;
	struct waitc *wp, *wp2;

	/*
	* find a unique wid by incrementing lastwid and stepping through
	* waitlist until we find a vacant slot.
	*/

	if (++lastwid > tidlmask)
		lastwid = 1;
	startwid = lastwid;
	wp = waitlist;

	while (1) {
		wid = myhostpart + lastwid;
		while (wp->wa_wid < wid)
			if ((wp = wp->wa_link) == waitlist)
				break;

		if (wp->wa_wid != wid)
			break;

		if (++lastwid > tidlmask) {
			lastwid = 1;
			wp = waitlist;
		}
		if (lastwid == startwid) {
			pvmlogerror("wait_new() out of wids???\n");
			pvmbailout(0);		/* XXX this is kinda harsh */
		}
	}

	/*
	* initialze new w context and add to list
	*/

	if (!(wp2 = TALLOC(1, struct waitc, "wait"))) {
		pvmlogerror("wait_new() can't get memory\n");
		pvmbailout(0);
	}
	wp2->wa_wid = wid;
	wp2->wa_kind = kind;
	wp2->wa_peer = wp2->wa_rpeer = wp2;

	wp2->wa_on = wp2->wa_tid = wp2->wa_dep = 0;
	wp2->wa_mesg = 0;
	wp2->wa_spec = 0;

	LISTPUTBEFORE(wp, wp2, wa_link, wa_rlink);
	return wp2;
}


/*	wait_find()
*
*	Find a wait context in active list by id.  Returns pointer
*	or 0 if not found.
*/

struct waitc *
wait_find(wid)
	int wid;
{
	struct waitc *wp;

	for (wp = waitlist->wa_link; wp != waitlist; wp = wp->wa_link)
		if (wp->wa_wid == wid)
			return wp;
	return (struct waitc*)0;
}


/*	wait_delete()
*
*	Remove a wait context from the active list, disassociate from
*	any peers and destroy it.
*/

void
wait_delete(wp)
	struct waitc *wp;
{
	if (wp->wa_mesg)
		mesg_unref(wp->wa_mesg);

	if (wp->wa_link) {
		LISTDELETE(wp, wa_link, wa_rlink);
	}
	if (wp->wa_peer) {
		LISTDELETE(wp, wa_peer, wa_rpeer);
	}
	PVM_FREE(wp);
}


/*	wait_get()
*
*	Find the wait context in waitlist for a given message.
*	If hp != 0, check that message came from correct host.
*	If kind != 0, check that message is correct kind.
*/

struct waitc *
wait_get(hp, mp, kind)
	struct hostd *hp;
	struct mesg *mp;
	int kind;
{
	struct waitc *wp;

	if (!mp->m_wid)
		return 0;
	if (!(wp = wait_find(mp->m_wid))) {
		sprintf(pvmtxt, "waitc_get() cod %s from t%x wid %d not found\n",
				dmname(mp->m_cod), mp->m_src, mp->m_wid);
		pvmlogerror(pvmtxt);
		return 0;
	}
	if (hp && hp->hd_hostpart != wp->wa_on) {
		sprintf(pvmtxt, "waitc_get() cod %s from t%x wid %d wrong host\n",
				dmname(mp->m_cod), mp->m_src, mp->m_wid);
		pvmlogerror(pvmtxt);
		return 0;
	}
	if (kind && kind != wp->wa_kind) {
		sprintf(pvmtxt, "waitc_get() cod %s from t%x wid %d wrong kind: %s\n",
				dmname(mp->m_cod), mp->m_src, mp->m_wid, waitkind(wp->wa_kind));
		pvmlogerror(pvmtxt);
		return 0;
	}
	return wp;
}


void
wait_dump(wp)
	struct waitc *wp;
{
	struct hostd *hp;
	struct waitc *wp2;
	char *p = pvmtxt;

	sprintf(p, " wid %d kind %s on ", wp->wa_wid, waitkind(wp->wa_kind));
	p += strlen(p);
	if (!TIDISTASK(wp->wa_on) && (hp = tidtohost(hosts, wp->wa_on)))
		sprintf(p, "%s", hp->hd_name);
	else
		sprintf(p, "t%x", wp->wa_on);
	p += strlen(p);
	sprintf(p, " tid t%x dep %d peer {",
		wp->wa_tid, wp->wa_dep);
	for (wp2 = wp->wa_peer; wp2 != wp; wp2 = wp2->wa_peer) {
		p += strlen(p);
		sprintf(p, " %d", wp2->wa_wid);
	}
	strcat(p, " }\n");
	pvmlogerror(pvmtxt);
}


void
wait_dumpall()
{
	struct waitc *wp;

	pvmlogerror("wait_dumpall()\n");
	for (wp = waitlist->wa_link; wp != waitlist; wp = wp->wa_link)
		wait_dump(wp);
}


