/*
 *
 * 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.
 *
 *
 *	$Id: rpi.c2c.h,v 1.2 1999/08/09 12:50:36 lamteam Exp $
 *
 *	Function:	- client-to-client RPI implementation
 *			- constants and templates
 */

#ifndef _RPI_C2C_H
#define _RPI_C2C_H

#include <lam_config.h>
#include <all_list.h>
#include <mpi.h>
#include <mpisys.h>
#include <portable.h>
#include <t_types.h>

/*
 * client-to-client envelope
 */
struct c2c_envl {
	int4		ce_len;			/* message length */
	int4		ce_tag;			/* message tag (16 bits) */
	int4		ce_flags;		/* flags */
#define C2CLONG		0x01			/* long protocol */
#define C2CACK		0x02			/* ACK message */
#define C2C2ND		0x04			/* 2nd message chunk */
#define C2CSSEND	0x08			/* synchronous send */
#define C2CBOX		0x10			/* long using postbox */
	int4		ce_rank;		/* peer rank */
	int4		ce_cid;			/* message context ID */
	int4		ce_seq;			/* sequence number */
};

typedef struct c2c_envl *envp_t;

#define ENVSIZE		((int) sizeof(struct c2c_envl))

/*
 * client-to-client specific request data
 */
struct c2c_req {
	int		cq_state;		/* state of request */
#define	C2CDONE		1			/* all data transfer done */
#define C2CWRITE	2			/* writing to socket */
#define C2CREAD		3			/* reading from socket */
#define C2CSENDSELF	4			/* sending to self */
	int4		cq_peer;		/* matched peer */
	struct c2c_envl cq_env;			/* envelope (synch + state) */	
	struct c2c_envl cq_outenv;		/* byte-ordered outgoing env. */
	int		cq_nenvout;		/* # env. bytes left to write */
	int		cq_nmsgout;		/* # msg. bytes left to write */
	char		*cq_envbuf;		/* envelope buffer pointer*/
	char		*cq_msgbuf;		/* message buffer pointer */
	int		cq_bufoff;		/* offset of shared buffer */
	int		cq_bufsize;		/* size of shared buffer */
	int		(*cq_adv)();		/* advance function */
};

/*
 * context ID hash table entry
 */
struct cbuf_cid {
	int4		cb_cid;			/* context ID */
	MPI_Comm	cb_comm;		/* communicator */
	LIST		*cb_envs;		/* envelope list */
};

/*
 * message/envelope entry
 */
struct cbuf_msg {
	struct c2c_proc *cm_proc;		/* source process */
	struct c2c_envl	cm_env;			/* envelope */
	char		*cm_buf;		/* short message data */
	MPI_Request	cm_req;			/* send req if sender == self */
};

/*
 * internal macros
 */
#define commdead_m(r)	\
	(((r)->rq_comm->c_flags & (LAM_CLDEAD | LAM_CRDEAD))	\
	? _c2c_comm_dead(r) : 0)

/*
 * data conversion for client-to-client envelopes
 */
#if WORDS_BIGENDIAN

#define tcp_set_out_envelope_m(r) \
	{ \
		(r).cq_nenvout = sizeof(struct c2c_envl); \
		(r).cq_envbuf = (char *) &((r).cq_env); \
	}

#else	/* not WORDS_BIGENDIAN */

#define tcp_set_out_envelope_m(r) \
	if (lam_homog) { \
		(r).cq_nenvout = sizeof(struct c2c_envl); \
		(r).cq_envbuf = (char *) &((r).cq_env); \
	} \
	else { \
		(r).cq_nenvout = sizeof(struct c2c_envl); \
		(r).cq_outenv = (r).cq_env; \
		mltoti4((int4 *) &((r).cq_outenv), \
				sizeof(struct c2c_envl) / sizeof(int4)); \
		(r).cq_envbuf = (char *) &((r).cq_outenv); \
	}

#endif	/* not WORDS_BIGENDIAN */

#ifdef __cplusplus
extern "C" {
#endif

extern int	_c2c_comm_dead __ARGS((MPI_Request));
extern int	_c2c_envl_cmp __ARGS((struct c2c_envl *, struct c2c_envl *));
extern void	_c2c_fill_mpi_status __ARGS((MPI_Request, int, int, int));
extern void	_c2c_fill_wildcards __ARGS((MPI_Request, struct c2c_envl *));

extern int	_cbuf_init __ARGS((void));
extern void	_cbuf_delete __ARGS((struct cbuf_msg *));
extern void	_cbuf_end __ARGS((void));
extern void	*_cbuf_append __ARGS((struct cbuf_msg *));
extern struct cbuf_msg
		*_cbuf_find __ARGS((struct c2c_envl *));

extern int	_tcp_advmultiple __ARGS((void));
extern int	_tcp_adv1 __ARGS((void));
extern int	_tcp_proc_read_env __ARGS((struct c2c_proc *));
extern int	_tcp_req_write_long __ARGS((struct c2c_proc *, MPI_Request));
extern int	_tcp_req_write_short __ARGS((struct c2c_proc *, MPI_Request));
extern int	_tcp_req_write_synch __ARGS((struct c2c_proc *, MPI_Request));
extern int	_tcp_req_read __ARGS((struct c2c_proc *, MPI_Request));
extern int	_tcp_req_probe __ARGS((struct c2c_proc *, MPI_Request));
extern int	_tcp_buffered_adv __ARGS((MPI_Request, struct cbuf_msg *));

extern int	_shm_advance __ARGS((void));
extern int	_shm_proc_read_env __ARGS((struct c2c_proc *));
extern int	_shm_req_send_long __ARGS((struct c2c_proc *, MPI_Request));
extern int	_shm_req_send_short __ARGS((struct c2c_proc *, MPI_Request));
extern int	_shm_req_send_synch __ARGS((struct c2c_proc *, MPI_Request));
extern int	_shmtcp_req_probe __ARGS((struct c2c_proc *, MPI_Request));
extern int	_shmtcp_req_read __ARGS((struct c2c_proc *, MPI_Request));
extern int	_shm_buffered_adv __ARGS((MPI_Request, struct cbuf_msg *));

extern int	_tcp_fastsend __ARGS((char *, int, struct c2c_proc *,
					int, int, MPI_Comm));
extern int	_tcp_fastrecv __ARGS((char *, int *, struct c2c_proc *,
					int, int *, MPI_Comm, int *));
    
extern int	_shm_fastsend __ARGS((char *, int, struct c2c_proc *,
					int, int, MPI_Comm));
extern int	_shm_fastrecv __ARGS((char *, int *, struct c2c_proc *,
					int, int *, MPI_Comm, int *));

#ifdef __cplusplus
}
#endif

#endif /* _RPI_C2C_H */
