/*****************************************************************************/
/* "NetPIPE" -- Network Protocol Independent Performance Evaluator.          */
/* Copyright 1997, 1998 Iowa State University Research Foundation, Inc.      */
/*                                                                           */
/* This program is free software; you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by      */
/* the Free Software Foundation.  You should have received a copy of the     */
/* GNU General Public License along with this program; if not, write to the  */
/* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.   */
/*                                                                           */
/*     * PVM.c              ---- PVM calls source                            */
/*****************************************************************************/
#include    "netpipe.h"
#include    <pvm3.h>

/**********************************************************************/
/* Set up the communcations system.                                   */
/*    In pvm, this means to join the parallel machine                 */
/**********************************************************************/
int Setup(ArgStruct * p)
{
	p->prot.mytid = pvm_mytid();
#ifdef DEBUG
	printf("My task id is %d \n", p->prot.mytid);
#endif
}

/**********************************************************************/
/* Establish a link with the other processor                          */
/*    In pvm, this means to send a simple message, but to keep the    */
/*    communication line open.  Since the assumption is that we are   */
/*    starting it by hand on the other machine, we don't know what    */
/*    the other task id is.                                           */
/**********************************************************************/
int Establish(ArgStruct * p)
{
	/* Task information for the entire parallel machine (if trans) */
	int tasks_status;
	struct pvmtaskinfo *taskp;
	int ntasks;

	/* Received buffer (if receiver)  */
	int buffer_id;

	/*
	   If we are the transmitting side, go find the other one and send
	   it a message containing our tid. If we are the receiving side,
	   just wait for a message.
	 */
	if (p->tr) {
#ifdef DEBUG
		printf("this is the transmitter\n");
#endif
		tasks_status = pvm_tasks(0, &ntasks, &taskp);
		if (ntasks != 2) {
			printf
			    ("Error, too many processes in parallel machine \n");
			printf("Start a clean machine.  n=%d\n", ntasks);
			exit(-1);
		}

		/* Since there are two tasks, one is ours the other is the receiver */
		p->prot.othertid = -1;
		if (taskp[0].ti_tid == p->prot.mytid) {
			p->prot.othertid = taskp[1].ti_tid;
		}
		if (taskp[1].ti_tid == p->prot.mytid) {
			p->prot.othertid = taskp[0].ti_tid;
		}
		if (p->prot.othertid == -1) {
			printf("Error, cannot find other (receiving) task \n");
			printf("Id's:  %d %d  \n", taskp[0].ti_tid,
			       taskp[1].ti_tid);
		}

		/* Send the receiver a message.  Tell pvm to keep the channel open */

#ifdef DEBUG
		printf("The receiver tid is %d \n", p->prot.othertid);
#endif
		pvm_setopt(PvmRoute, PvmRouteDirect);
		pvm_initsend(PVMDATA);
		pvm_pkint(&p->prot.mytid, 1, 1);
		pvm_send(p->prot.othertid, 1);
	} else {
#ifdef DEBUG
		printf("This is the receiver \n");
#endif

		/* Receive any message from any task */
		buffer_id = pvm_recv(-1, -1);

		if (buffer_id < 0) {
			printf("Error on receive in receiver\n");
			exit(-1);
		}
		pvm_upkint(&p->prot.othertid, 1, 1);
	}
}

/**********************************************************************/
/* Prepare to receive                                                 */
/*    In pvm, you cannot set up a reception buffer ahead of time      */
/**********************************************************************/
void PrepareToReceive(ArgStruct * p)
{
}

/**********************************************************************/
/* Synchronize                                                        */
/*     In pvm, this is not necessary                                  */
/**********************************************************************/
void Sync(ArgStruct * p)
{
}

/**********************************************************************/
/* Send a buffer full of information                                  */
/*    In pvm, we use pvm_pkbyte and then send it.                     */
/**********************************************************************/
void SendData(ArgStruct * p)
{
#ifdef DEBUG
	printf(" In send \n");
#endif
	pvm_initsend(PVMDATA);
	pvm_pkbyte(p->buff, p->bufflen, 1);
	pvm_send(p->prot.othertid, 1);
#ifdef DEBUG
	printf(" message sent.  Size=%d\n", p->bufflen);
#endif
}

/**********************************************************************/
/* Receive a buffer full of information                               */
/**********************************************************************/
void RecvData(ArgStruct * p)
{
#ifdef DEBUG
	printf(" In receive \n");
#endif
	pvm_recv(-1, -1);
	pvm_upkbyte(p->buff, p->bufflen, 1);
#ifdef DEBUG
	printf(" message received .  Size=%d \n", p->bufflen);
#endif
}

/**********************************************************************/
/* Send elapsed time to the other process                             */
/**********************************************************************/
void SendTime(ArgStruct * p, double *t)
{
	pvm_initsend(PVMDATA);
	pvm_pkdouble(t, 1, 1);
	pvm_send(p->prot.othertid, 1);
}

/**********************************************************************/
/* Receive elapsed time from the other process                        */
/**********************************************************************/
void RecvTime(ArgStruct * p, double *t)
{
	pvm_recv(-1, -1);
	pvm_upkdouble(t, 1, 1);
}

/**********************************************************************/
/* Send repeat count to the other process                             */
/**********************************************************************/
void SendRepeat(ArgStruct * p, int rpt)
{
	pvm_initsend(PVMDATA);
	pvm_pkint(&rpt, 1, 1);
	pvm_send(p->prot.othertid, 1);
}

/**********************************************************************/
/* Receiver repeat count from other process                           */
/**********************************************************************/
void RecvRepeat(ArgStruct * p, int *rpt)
{
	pvm_recv(-1, -1);
	pvm_upkint(rpt, 1, 1);
}

/**********************************************************************/
/* Close down the connection.
/**********************************************************************/
int CleanUp(ArgStruct * p)
{
}
