/* * Copyright (c) 2004-2005 The Trustees of Indiana University. * All rights reserved. * Copyright (c) 2004-2005 The Trustees of the University of Tennessee. * 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$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file */ #ifndef MCA_PTL_TCP_SEND_FRAG_H #define MCA_PTL_TCP_SEND_FRAG_H #include "ompi_config.h" #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include "include/sys/atomic.h" #include "mca/ptl/base/ptl_base_sendreq.h" #include "mca/ptl/base/ptl_base_sendfrag.h" #include "ptl_tcp.h" #include "ptl_tcp_recvfrag.h" #if defined(c_plusplus) || defined(__cplusplus) extern "C" { #endif extern opal_class_t mca_ptl_tcp_send_frag_t_class; struct mca_ptl_base_peer_t; /** * TCP send fragment derived type. */ struct mca_ptl_tcp_send_frag_t { mca_ptl_base_send_frag_t frag_send; /**< base send fragment descriptor */ int32_t free_after; /**< keep trace of which vectors we have to free */ struct iovec *frag_vec_ptr; /**< pointer into iovec array */ size_t frag_vec_cnt; /**< number of iovec structs left to process */ struct iovec frag_vec[2]; /**< array of iovecs for send */ struct iovec frag_saved_vec; /**< save the initial values from the current iovec */ volatile int frag_progressed; /**< for threaded case - has request status been updated */ }; typedef struct mca_ptl_tcp_send_frag_t mca_ptl_tcp_send_frag_t; #define MCA_PTL_TCP_SEND_FRAG_ALLOC(item, rc) \ OMPI_FREE_LIST_GET(&mca_ptl_tcp_component.tcp_send_frags, item, rc); bool mca_ptl_tcp_send_frag_handler(mca_ptl_tcp_send_frag_t*, int sd); /** * Initialize a fragment descriptor. * * frag (IN) Fragment * peer (IN) PTL peer addressing information * request (IN) Send request * offset (IN) Current offset into packed buffer * size (IN/OUT) Requested size / actual size returned * flags (IN) */ int mca_ptl_tcp_send_frag_init( mca_ptl_tcp_send_frag_t*, struct mca_ptl_base_peer_t*, struct mca_ptl_base_send_request_t*, size_t offset, size_t* size, int flags); /** * For fragments that require an acknowledgment, this routine will be called * twice, once when the send completes, and again when the acknowledgment is * returned. Only the last caller should update the request status, so we * add a lock w/ the frag_progressed flag. */ static inline void mca_ptl_tcp_send_frag_progress(mca_ptl_tcp_send_frag_t* frag) { mca_ptl_base_send_request_t* request = frag->frag_send.frag_request; bool frag_ack; /* if this is an ack - simply return to pool */ if(request == NULL) { mca_ptl_tcp_send_frag_return(frag->frag_send.frag_base.frag_owner, frag); return; } /* Done when: * (1) ack is not required and send completes * (2) ack is received and send has completed */ frag_ack = (frag->frag_send.frag_base.frag_header. hdr_common.hdr_flags & MCA_PTL_FLAGS_ACK) ? true : false; if(frag_ack == false || opal_atomic_add_32(&frag->frag_progressed,1) == 2) { /* update request status */ frag->frag_send.frag_base.frag_owner->ptl_send_progress( frag->frag_send.frag_base.frag_owner, request, frag->frag_send.frag_base.frag_size); /* the first fragment is allocated with the request, * all others need to be returned to free list */ if (request->req_cached == false || frag->frag_send.frag_base.frag_header.hdr_common.hdr_type == MCA_PTL_HDR_TYPE_FRAG) { mca_ptl_tcp_send_frag_return(frag->frag_send.frag_base.frag_owner, frag); } } } static inline void mca_ptl_tcp_send_frag_init_ack( mca_ptl_tcp_send_frag_t* ack, struct mca_ptl_base_module_t* ptl, struct mca_ptl_base_peer_t* ptl_peer, mca_ptl_tcp_recv_frag_t* frag) { mca_ptl_base_header_t* hdr = &ack->frag_send.frag_base.frag_header; mca_ptl_base_recv_request_t* request = frag->frag_recv.frag_request; hdr->hdr_common.hdr_type = MCA_PTL_HDR_TYPE_ACK; hdr->hdr_common.hdr_flags = 0; hdr->hdr_ack.hdr_src_ptr = frag->frag_recv.frag_base.frag_header.hdr_rndv.hdr_src_ptr; hdr->hdr_ack.hdr_dst_match.lval = 0; /* for VALGRIND/PURIFY - REPLACE WITH MACRO */ hdr->hdr_ack.hdr_dst_match.pval = request; hdr->hdr_ack.hdr_dst_addr.lval = 0; /* for VALGRIND/PURIFY - REPLACE WITH MACRO */ hdr->hdr_ack.hdr_dst_addr.pval = request->req_recv.req_base.req_addr; hdr->hdr_ack.hdr_dst_size = request->req_recv.req_bytes_packed; ack->frag_send.frag_request = 0; ack->frag_send.frag_base.frag_peer = ptl_peer; ack->frag_send.frag_base.frag_owner = ptl; ack->frag_send.frag_base.frag_addr = NULL; ack->frag_send.frag_base.frag_size = 0; ack->frag_vec_ptr = ack->frag_vec; ack->frag_vec[0].iov_base = (ompi_iov_base_ptr_t)hdr; ack->frag_vec[0].iov_len = sizeof(mca_ptl_base_header_t); ack->frag_vec_cnt = 1; ack->free_after = 0; } #if defined(c_plusplus) || defined(__cplusplus) } #endif #endif