/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1997 The Ohio State University
 *	RBD/GDB
 *
 *	$Id: recv.c,v 6.19 1999/11/12 05:19:31 jsquyres Exp $
 *
 *	Function:	- receive a message
 *	Accepts:	- buffer
 *			- count
 *			- datatype
 *			- source
 *			- tag
 *			- communicator
 *			- status (out)
 *	Returns: 	- MPI_SUCCESS or error code
 */

#include <blktype.h>
#include <mpi.h>
#include <mpisys.h>
#include <mpitrace.h>
#include <rpisys.h>
#if LAM_WANT_IMPI
#include <impi.h>
#endif
#include <debug.h>

/*
 * state variable, has to be public.  Ugh. (in irecv.c)
 */
extern int lam_in_impi_irecv;

/*
 * private variables
 */
static int fl_debug = 0;


int
MPI_Recv(buf, count, dtype, src, tag, comm, stat)

void			*buf;
int			count;
MPI_Datatype		dtype;
int			src;
int			tag;
MPI_Comm		comm;
MPI_Status		*stat;

{
	int		err;
	int		staterr;		/* error in status */
	struct _req	req_storage;
	MPI_Request	req;
	int		fl_trace;		/* do tracing? */
	double		startt = 0.0;		/* start time */
	double		finisht;		/* finish time */

	lam_initerr_m();
	lam_setfunc_m(BLKMPIRECV);

	if ((tag < 0 && tag != MPI_ANY_TAG) || tag > LAM_MAXTAG) {
		return(lam_errfunc(comm, BLKMPIRECV,
				lam_mkerr(MPI_ERR_TAG, 0)));
	}
/*
 * Check the bozo MPI_PROC_NULL case.  I'm not even tracing this.
 */
	if (src == MPI_PROC_NULL) {
		if (stat != MPI_STATUS_IGNORE) {
			stat->MPI_ERROR = MPI_SUCCESS;
			stat->MPI_SOURCE = MPI_PROC_NULL;
			stat->MPI_TAG = MPI_ANY_TAG;
			stat->st_length = 0;
		}

		lam_resetfunc_m(BLKMPIRECV);
		return(MPI_SUCCESS);
	}

	if ((fl_trace = LAM_TRACE_TOP())) {
		startt = MPI_Wtime();
		_kio.ki_blktime = 0.0;
	}

#if LAM_WANT_IMPI
/*
 * If we could possibly be receiving from the impid, there's a lot of
 * special things that need to happen.  All that special code has been
 * put into MPI_Irecv, so we just call MPI_Irecv() and MPI_Wait().
 */
	if (LAM_IS_IMPI(comm) &&
	    lam_impid_proc != 0 &&
	    (LAM_GPSCMP(&(comm->c_group->g_procs[src]->p_gps),
			&(lam_impid_proc->p_gps)) == 0 ||
	     src == MPI_ANY_SOURCE)) {
	  MPI_Status status;
	  MPI_Request req;

	  /* All the code for the IMPI special case receive is in
             MPI_Irecv, so just relay the request to there, and then
             MPI_Wait on it */

	  DBUG("IMPI SPECIAL CASE RECEIVE from rank %d\n", src);
	  MPI_Irecv(buf, count, dtype, src, tag, comm, &req);
	  DBUG("IMPI SPECIAL CASE RECEIVE: Calling MPI_Wait\n");
	  MPI_Wait(&req, &status);

	  if (stat != MPI_STATUS_IGNORE)
	    *stat = status;

	  /* Check for error */

	  if (status.MPI_ERROR != MPI_SUCCESS)
	    return(lam_errfunc(comm, BLKMPIRECV, status.MPI_ERROR));

	  DBUG("IMPI SPECIAL CASE RECEIVE: All done; returning\n");
	  lam_resetfunc_m(BLKMPIRECV);
	  return (MPI_SUCCESS);
	}
#endif
	DBUG("NOT AN IMPI PROXY IRECEIVE\n");

#ifdef SHORTCIRCUIT
	if (lam_c2c && lam_rq_nactv == 0) {
		if (comm == MPI_COMM_NULL) {
			return(lam_mkerr(MPI_ERR_COMM, 0));
		}

		if (src != MPI_ANY_SOURCE && (LAM_IS_INTER(comm)
				|| src != comm->c_group->g_myrank)) {

		        int seqnum;

			err = _rpi_c2c_fastrecv(buf, count, dtype,
						src, &tag, comm, stat, &seqnum);

			if (fl_trace) {
			    finisht = MPI_Wtime();

			    lam_tr_msg(TRTINPUT, startt,
				LAM_S2US(finisht - startt - _kio.ki_blktime),
				LAM_S2US(_kio.ki_blktime), src, tag, comm,
				dtype, count, src, tag, seqnum, LAM_RQIRECV);
			}

			if (err != MPI_SUCCESS)
			  return lam_errfunc(comm, BLKMPIRECV, err);

			lam_resetfunc_m(BLKMPIRECV);
			return (MPI_SUCCESS);
		}
	}
#endif
	LAM_ZERO_ME(req_storage);
	req = &req_storage;
	err = _mpi_req_build(buf, count, dtype, 
				src, tag, comm, LAM_RQIRECV, &req);
	if (err != MPI_SUCCESS) return(lam_errfunc(comm, BLKMPIRECV, err));

	req->rq_marks |= (LAM_RQFBLKTYPE | LAM_RQFMAND);

	err = _mpi_req_start(req);
	if (err != MPI_SUCCESS) return(lam_errfunc(comm, BLKMPIRECV, err));

	_mpi_req_add_m(req);
	_mpi_req_blkclr_m();
	_mpi_req_blkset_m(req);

	err = _mpi_req_advance();
	if (err != MPI_SUCCESS) return(lam_errfunc(comm, BLKMPIRECV, err));
	
	_mpi_req_rem_m(req);

	err = _mpi_req_end(req);
	if (err != MPI_SUCCESS) return(lam_errfunc(comm, BLKMPIRECV, err));

	staterr = req->rq_status.MPI_ERROR;
	if (stat != MPI_STATUS_IGNORE) {
		*stat = req->rq_status;
	}
/*
 * Generate a run time trace.
 */
	if (fl_trace) {
		finisht = MPI_Wtime();
		
		lam_tr_msg(TRTINPUT, startt,
			LAM_S2US(finisht - startt - _kio.ki_blktime),
			LAM_S2US(_kio.ki_blktime), src, tag, comm,
			dtype, count, req->rq_status.MPI_SOURCE,
			req->rq_status.MPI_TAG, req->rq_seq, LAM_RQIRECV);
	}

	err = _mpi_req_destroy(&req);
	if (err != MPI_SUCCESS) {
		return(lam_errfunc(comm, BLKMPIRECV, err));
	}

	if (staterr != MPI_SUCCESS) {
		return(lam_errfunc(comm, BLKMPIRECV, staterr));
	}

	lam_resetfunc_m(BLKMPIRECV);
	return(MPI_SUCCESS);
}
