/*
 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
 *                         University Research and Technology
 *                         Corporation.  All rights reserved.
 * Copyright (c) 2004-2007 The University of Tennessee and The University
 *                         of Tennessee Research Foundation.  All rights
 *                         reserved.
 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, 
 *                         University of Stuttgart.  All rights reserved.
 * Copyright (c) 2004-2005 The Regents of the University of California.
 *                         All rights reserved.
 * Copyright (c) 2006      Cisco Systems, Inc.  All rights reserved.
 * $COPYRIGHT$
 * 
 * Additional copyrights may follow
 * 
 * $HEADER$
 */
/**
 * @file
 */
#ifndef MCA_PML_BASE_SEND_REQUEST_H
#define MCA_PML_BASE_SEND_REQUEST_H

#include "ompi_config.h"
#include "ompi/mca/pml/pml.h"
#include "ompi/mca/pml/base/pml_base_request.h"
#include "opal/datatype/opal_convertor.h"
#include "ompi/peruse/peruse-internal.h"

BEGIN_C_DECLS

/**
 * Base type for send requests 
 */
struct mca_pml_base_send_request_t {
    mca_pml_base_request_t req_base;         /**< base request type - common data structure for use by wait/test */
    void *req_addr;                          /**< pointer to send buffer - may not be application buffer */
    size_t req_bytes_packed;                 /**< packed size of a message given the datatype and count */
    mca_pml_base_send_mode_t req_send_mode;  /**< type of send */
};
typedef struct mca_pml_base_send_request_t mca_pml_base_send_request_t;

OMPI_DECLSPEC OBJ_CLASS_DECLARATION( mca_pml_base_send_request_t );

/**
 * Initialize a send request with call parameters.
 *
 * @param request (IN)         Send request
 * @param addr (IN)            User buffer
 * @param count (IN)           Number of elements of indicated datatype.
 * @param datatype (IN)        User defined datatype
 * @param peer (IN)            Destination rank
 * @param tag (IN)             User defined tag
 * @param comm (IN)            Communicator
 * @param mode (IN)            Send mode (STANDARD,BUFFERED,SYNCHRONOUS,READY)
 * @param persistent (IN)      Is request persistent.
 * @param convertor_flags (IN) Flags to pass to convertor
 *
 * Perform a any one-time initialization. Note that per-use initialization
 * is done in the send request start routine.
 */

#define MCA_PML_BASE_SEND_REQUEST_INIT( request,                          \
                                        addr,                             \
                                        count,                            \
                                        datatype,                         \
                                        peer,                             \
                                        tag,                              \
                                        comm,                             \
                                        mode,                             \
                                        persistent,                       \
                                        convertor_flags)                  \
   {                                                                      \
      /* increment reference counts */                                    \
      OBJ_RETAIN(comm);                                                   \
                                                                          \
      OMPI_REQUEST_INIT(&(request)->req_base.req_ompi, persistent);       \
      (request)->req_base.req_ompi.req_mpi_object.comm = comm;            \
      (request)->req_addr = addr;                                         \
      (request)->req_send_mode = mode;                                    \
      (request)->req_base.req_addr = addr;                                \
      (request)->req_base.req_count = count;                              \
      (request)->req_base.req_datatype = datatype;                        \
      (request)->req_base.req_peer = (int32_t)peer;                       \
      (request)->req_base.req_tag = (int32_t)tag;                         \
      (request)->req_base.req_comm = comm;                                \
      /* (request)->req_base.req_proc is set on request allocation */     \
      (request)->req_base.req_pml_complete = OPAL_INT_TO_BOOL(persistent); \
      (request)->req_base.req_free_called = false;                        \
      (request)->req_base.req_ompi.req_status._cancelled = 0;             \
      (request)->req_bytes_packed = 0;                                    \
                                                                          \
      /* initialize datatype convertor for this request */                \
      if( count > 0 ) {                                                   \
          OBJ_RETAIN(datatype);                                           \
         /* We will create a convertor specialized for the        */      \
         /* remote architecture and prepared with the datatype.   */      \
         opal_convertor_copy_and_prepare_for_send(                        \
                            (request)->req_base.req_proc->proc_convertor, \
                            &((request)->req_base.req_datatype->super),   \
                            (request)->req_base.req_count,                \
                            (request)->req_base.req_addr,                 \
                            convertor_flags,                              \
                            &(request)->req_base.req_convertor );         \
         opal_convertor_get_packed_size( &(request)->req_base.req_convertor, \
                                         &((request)->req_bytes_packed) );\
      }                                                                   \
   }

/**
 * Mark the request as started from the PML base point of view.
 *
 *  @param request (IN)    The send request.
 */

#define MCA_PML_BASE_SEND_START( request )                    \
    do {                                                      \
        (request)->req_pml_complete = false;                  \
        (request)->req_ompi.req_complete = false;             \
        (request)->req_ompi.req_state = OMPI_REQUEST_ACTIVE;  \
        (request)->req_ompi.req_status._cancelled = 0;        \
    } while (0)

/**
 *  Release the ref counts on the communicator and datatype.
 *
 *  @param request (IN)    The send request.
 */

#define MCA_PML_BASE_SEND_REQUEST_FINI( request )                         \
    do {                                                                  \
        OMPI_REQUEST_FINI(&(request)->req_base.req_ompi);                 \
        OBJ_RELEASE((request)->req_base.req_comm);                        \
        if( 0 != (request)->req_base.req_count )                          \
            OBJ_RELEASE((request)->req_base.req_datatype);                \
        opal_convertor_cleanup( &((request)->req_base.req_convertor) );   \
    } while (0)


END_C_DECLS

#endif