ptl_send.c 18.9 KB
Newer Older
1
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2
3
4
5
6
/*
 *  (C) 2012 by Argonne National Laboratory.
 *      See COPYRIGHT in top-level directory.
 */

7
#include "ptl_impl.h"
8
#include "rptl.h"
9

10
11
12
13
14
15
#undef FUNCNAME
#define FUNCNAME big_meappend
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
static void big_meappend(void *buf, ptl_size_t left_to_send, MPIDI_VC_t *vc, ptl_match_bits_t match_bits, MPID_Request *sreq)
{
16
    int i, ret, was_incomplete;
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    MPID_nem_ptl_vc_area *vc_ptl;
    ptl_me_t me;

    vc_ptl = VC_PTL(vc);

    me.start = buf;
    me.ct_handle = PTL_CT_NONE;
    me.uid = PTL_UID_ANY;
    me.options = ( PTL_ME_OP_PUT | PTL_ME_OP_GET | PTL_ME_USE_ONCE | PTL_ME_IS_ACCESSIBLE | PTL_ME_EVENT_LINK_DISABLE |
                   PTL_ME_EVENT_UNLINK_DISABLE );
    me.match_id = vc_ptl->id;
    me.match_bits = match_bits;
    me.ignore_bits = 0;
    me.min_free = 0;

    /* allocate enough handles to cover all get operations */
    REQ_PTL(sreq)->get_me_p = MPIU_Malloc(sizeof(ptl_handle_me_t) *
                                        ((left_to_send / MPIDI_nem_ptl_ni_limits.max_msg_size) + 1));

    /* queue up as many entries as necessary to describe the entire message */
    for (i = 0; left_to_send > 0; i++) {
        /* send up to the maximum allowed by the portals interface */
        if (left_to_send > MPIDI_nem_ptl_ni_limits.max_msg_size)
            me.length = MPIDI_nem_ptl_ni_limits.max_msg_size;
41
        else
42
43
            me.length = left_to_send;

44
45
        ret = MPID_nem_ptl_me_append(MPIDI_nem_ptl_ni, MPIDI_nem_ptl_get_pt, &me, PTL_PRIORITY_LIST, sreq,
                                     &REQ_PTL(sreq)->get_me_p[i]);
46
47
        DBG_MSG_MEAPPEND("CTL", vc->pg_rank, me, sreq);
        MPIU_Assert(ret == 0);
48
49
50
51
        /* increment the cc for each get operation */
        MPIDI_CH3U_Request_increment_cc(sreq, &was_incomplete);
        MPIU_Assert(was_incomplete);
        REQ_PTL(sreq)->num_gets++;
52
53
54
55
56
57
58

        /* account for what has been sent */
        me.start = (char *)me.start + me.length;
        left_to_send -= me.length;
    }
}

59
#undef FUNCNAME
60
#define FUNCNAME handler_send
61
62
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
63
static int handler_send(const ptl_event_t *e)
64
65
66
{
    int mpi_errno = MPI_SUCCESS;
    MPID_Request *const sreq = e->user_ptr;
67
68
69
    int i, ret, incomplete;

    MPIDI_STATE_DECL(MPID_STATE_HANDLER_SEND);
70

71
    MPIDI_FUNC_ENTER(MPID_STATE_HANDLER_SEND);
72

73
    MPIU_Assert(e->type == PTL_EVENT_SEND || e->type == PTL_EVENT_GET);
74

75
76
77
78
79
80
    /* if we are done, release all resources and complete the request */
    if (sreq->cc == 1) {
        if (REQ_PTL(sreq)->md != PTL_INVALID_HANDLE) {
            ret = PtlMDRelease(REQ_PTL(sreq)->md);
            MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlmdrelease", "**ptlmdrelease %s", MPID_nem_ptl_strerror(ret));
        }
81

82
83
84
        for (i = 0; i < MPID_NEM_PTL_NUM_CHUNK_BUFFERS; ++i)
            if (REQ_PTL(sreq)->chunk_buffer[i])
                MPIU_Free(REQ_PTL(sreq)->chunk_buffer[i]);
85

86
87
        if (REQ_PTL(sreq)->get_me_p)
            MPIU_Free(REQ_PTL(sreq)->get_me_p);
88
    
89
90
91
        MPIDI_CH3U_Request_complete(sreq);
    } else {
        MPIDI_CH3U_Request_decrement_cc(sreq, &incomplete);
92
93
94
    }

 fn_exit:
95
    MPIDI_FUNC_EXIT(MPID_STATE_HANDLER_SEND);
96
97
98
99
100
    return mpi_errno;
 fn_fail:
    goto fn_exit;
}

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* Send message for either isend or issend */
#undef FUNCNAME
#define FUNCNAME send_msg
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
static int send_msg(ptl_hdr_data_t ssend_flag, struct MPIDI_VC *vc, const void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPID_Comm *comm, int context_offset, struct MPID_Request **request)
{
    int mpi_errno = MPI_SUCCESS;
    MPID_nem_ptl_vc_area *const vc_ptl = VC_PTL(vc);
    int ret;
    MPIDI_msg_sz_t data_sz;
    int dt_contig;
    MPI_Aint dt_true_lb;
    MPID_Datatype *dt_ptr;
    MPID_Request *sreq = NULL;
117
118
119
120
    ptl_me_t me;
    int initial_iov_count, remaining_iov_count;
    ptl_md_t md;
    MPI_Aint last;
121
122
123
124
125
    MPIU_CHKPMEM_DECL(2);
    MPIDI_STATE_DECL(MPID_STATE_SEND_MSG);

    MPIDI_FUNC_ENTER(MPID_STATE_SEND_MSG);

126
    MPID_nem_ptl_request_create_sreq(sreq, mpi_errno, comm);
127
    sreq->dev.match.parts.rank = dest;
128
129
    sreq->dev.match.parts.tag = tag;
    sreq->dev.match.parts.context_id = comm->context_id + context_offset;
130
131

    if (!vc_ptl->id_initialized) {
132
        mpi_errno = MPID_nem_ptl_init_id(vc);
133
134
        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
    }
135

136
    MPIDI_Datatype_get_info(count, datatype, dt_contig, data_sz, dt_ptr, dt_true_lb);
137
    MPIU_DBG_MSG_FMT(CH3_CHANNEL, VERBOSE, (MPIU_DBG_FDEST, "count=%d datatype=%#x contig=%d data_sz=%lu", count, datatype, dt_contig, data_sz));
138

139
    if (data_sz <= PTL_LARGE_THRESHOLD) {
140
141
        /* Small message.  Send all data eagerly */
        if (dt_contig) {
142
            MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "Small contig message");
143
            REQ_PTL(sreq)->event_handler = handler_send;
144
            MPIU_DBG_MSG_P(CH3_CHANNEL, VERBOSE, "&REQ_PTL(sreq)->event_handler = %p", &(REQ_PTL(sreq)->event_handler));
145
            ret = MPID_nem_ptl_rptl_put(MPIDI_nem_ptl_global_md, (ptl_size_t)((char *)buf + dt_true_lb), data_sz, PTL_NO_ACK_REQ, vc_ptl->id, vc_ptl->pt,
146
                         NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), 0, sreq,
147
                                        NPTL_HEADER(ssend_flag, data_sz));
148
            MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
149
            DBG_MSG_PUT("global", data_sz, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag, data_sz));
150
151
152
            MPIU_DBG_MSG_D(CH3_CHANNEL, VERBOSE, "id.nid = %#x", vc_ptl->id.phys.nid);
            MPIU_DBG_MSG_D(CH3_CHANNEL, VERBOSE, "id.pid = %#x", vc_ptl->id.phys.pid);
            MPIU_DBG_MSG_P(CH3_CHANNEL, VERBOSE, "sreq = %p", sreq);
153
            MPIU_DBG_MSG_D(CH3_CHANNEL, VERBOSE, "vc_ptl->pt = %d", vc_ptl->pt);
154
155
            MPIU_DBG_MSG_P(CH3_CHANNEL, VERBOSE, "REQ_PTL(sreq)->event_handler = %p", REQ_PTL(sreq)->event_handler);
           goto fn_exit;
156
157
158
        }
        
        /* noncontig data */
159
        MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "Small noncontig message");
160
161
162
        sreq->dev.segment_ptr = MPID_Segment_alloc();
        MPIU_ERR_CHKANDJUMP1(sreq->dev.segment_ptr == NULL, mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPID_Segment_alloc");
        MPID_Segment_init(buf, count, datatype, sreq->dev.segment_ptr, 0);
163
        sreq->dev.segment_first = 0;
164
        sreq->dev.segment_size = data_sz;
165

166
167
168
        last = sreq->dev.segment_size;
        sreq->dev.iov_count = MPID_IOV_LIMIT;
        MPID_Segment_pack_vector(sreq->dev.segment_ptr, sreq->dev.segment_first, &last, sreq->dev.iov, &sreq->dev.iov_count);
169

170
171
        if (last == sreq->dev.segment_size) {
            /* IOV is able to describe entire message */
172
            MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "    entire message fits in IOV");
173
174
175
            md.start = sreq->dev.iov;
            md.length = sreq->dev.iov_count;
            md.options = PTL_IOVEC;
176
            md.eq_handle = MPIDI_nem_ptl_origin_eq;
177
178
            md.ct_handle = PTL_CT_NONE;
            ret = PtlMDBind(MPIDI_nem_ptl_ni, &md, &REQ_PTL(sreq)->md);
179
            MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlmdbind", "**ptlmdbind %s", MPID_nem_ptl_strerror(ret));
180
                
181
            REQ_PTL(sreq)->event_handler = handler_send;
182
            ret = MPID_nem_ptl_rptl_put(REQ_PTL(sreq)->md, 0, data_sz, PTL_NO_ACK_REQ, vc_ptl->id, vc_ptl->pt,
183
                         NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), 0, sreq,
184
                                        NPTL_HEADER(ssend_flag, data_sz));
185
            MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
186
            DBG_MSG_PUT("sreq", data_sz, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag, data_sz));
187
188
189
190
            goto fn_exit;
        }
        
        /* IOV is not long enough to describe entire message */
191
        MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "    IOV too long: using bounce buffer");
192
        MPIU_CHKPMEM_MALLOC(REQ_PTL(sreq)->chunk_buffer[0], void *, data_sz, mpi_errno, "chunk_buffer");
193
194
        MPID_Segment_init(buf, count, datatype, sreq->dev.segment_ptr, 0);
        sreq->dev.segment_first = 0;
195
196
197
        last = data_sz;
        MPID_Segment_pack(sreq->dev.segment_ptr, sreq->dev.segment_first, &last, REQ_PTL(sreq)->chunk_buffer[0]);
        MPIU_Assert(last == sreq->dev.segment_size);
198
        REQ_PTL(sreq)->event_handler = handler_send;
199
        ret = MPID_nem_ptl_rptl_put(MPIDI_nem_ptl_global_md, (ptl_size_t)REQ_PTL(sreq)->chunk_buffer[0], data_sz, PTL_NO_ACK_REQ,
200
                     vc_ptl->id, vc_ptl->pt, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), 0, sreq,
201
                                    NPTL_HEADER(ssend_flag, data_sz));
202
        MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
203
        DBG_MSG_PUT("global", data_sz, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag, data_sz));
204
205
206
207
208
209
        goto fn_exit;
    }
        
    /* Large message.  Send first chunk of data and let receiver get the rest */
    if (dt_contig) {
        /* create ME for buffer so receiver can issue a GET for the data */
210
        MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "Large contig message");
211
212
        big_meappend((char *)buf + dt_true_lb + PTL_LARGE_THRESHOLD, data_sz - PTL_LARGE_THRESHOLD, vc,
                     NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), sreq);
213
        REQ_PTL(sreq)->large = TRUE;
214

215
        REQ_PTL(sreq)->event_handler = handler_send;
216
        ret = MPID_nem_ptl_rptl_put(MPIDI_nem_ptl_global_md, (ptl_size_t)((char *)buf + dt_true_lb), PTL_LARGE_THRESHOLD, PTL_NO_ACK_REQ, vc_ptl->id, vc_ptl->pt,
217
                     NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), 0, sreq,
218
                                    NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
219
        MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
220
        DBG_MSG_PUT("global", PTL_LARGE_THRESHOLD, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
221
222
223
224
        goto fn_exit;
    }
    
    /* Large noncontig data */
225
    MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "Large noncontig message");
226
227
228
    sreq->dev.segment_ptr = MPID_Segment_alloc();
    MPIU_ERR_CHKANDJUMP1(sreq->dev.segment_ptr == NULL, mpi_errno, MPI_ERR_OTHER, "**nomem", "**nomem %s", "MPID_Segment_alloc");
    MPID_Segment_init(buf, count, datatype, sreq->dev.segment_ptr, 0);
229
    sreq->dev.segment_first = 0;
230
231
232
233
234
235
236
237
238
239
240
    sreq->dev.segment_size = data_sz;

    last = PTL_LARGE_THRESHOLD;
    sreq->dev.iov_count = MPID_IOV_LIMIT;
    MPID_Segment_pack_vector(sreq->dev.segment_ptr, sreq->dev.segment_first, &last, sreq->dev.iov, &sreq->dev.iov_count);

    initial_iov_count = sreq->dev.iov_count;
    sreq->dev.segment_first = last;

    if (last == PTL_LARGE_THRESHOLD) {
        /* first chunk of message fits into IOV */
241
        MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "    first chunk fits in IOV");
242
243
244
        if (initial_iov_count < MPID_IOV_LIMIT) {
            /* There may be space for the rest of the message in this IOV */
            sreq->dev.iov_count = MPID_IOV_LIMIT - sreq->dev.iov_count;
245
            last = sreq->dev.segment_size;
246
247
248
                    
            MPID_Segment_pack_vector(sreq->dev.segment_ptr, sreq->dev.segment_first, &last,
                                     &sreq->dev.iov[initial_iov_count], &sreq->dev.iov_count);
249
            remaining_iov_count = sreq->dev.iov_count;
250

251
            if (last == sreq->dev.segment_size && last <= MPIDI_nem_ptl_ni_limits.max_msg_size + PTL_LARGE_THRESHOLD) {
252
                /* Entire message fit in one IOV */
253
254
                int was_incomplete;

255
                MPIU_DBG_MSG(CH3_CHANNEL, VERBOSE, "    rest of message fits in one IOV");
256
257
                /* Create ME for remaining data */
                me.start = &sreq->dev.iov[initial_iov_count];
258
                me.length = remaining_iov_count;
259
260
                me.ct_handle = PTL_CT_NONE;
                me.uid = PTL_UID_ANY;
261
                me.options = ( PTL_ME_OP_PUT | PTL_ME_OP_GET | PTL_ME_USE_ONCE | PTL_ME_IS_ACCESSIBLE | PTL_ME_EVENT_LINK_DISABLE |
262
263
                               PTL_ME_EVENT_UNLINK_DISABLE | PTL_IOVEC );
                me.match_id = vc_ptl->id;
264
                me.match_bits = NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank);
265
266
                me.ignore_bits = 0;
                me.min_free = 0;
267
268

                MPIU_CHKPMEM_MALLOC(REQ_PTL(sreq)->get_me_p, ptl_handle_me_t *, sizeof(ptl_handle_me_t), mpi_errno, "get_me_p");
269

270
271
                ret = MPID_nem_ptl_me_append(MPIDI_nem_ptl_ni, MPIDI_nem_ptl_get_pt, &me, PTL_PRIORITY_LIST, sreq,
                                             &REQ_PTL(sreq)->get_me_p[0]);
272
                MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlmeappend", "**ptlmeappend %s", MPID_nem_ptl_strerror(ret));
273
                DBG_MSG_MEAPPEND("CTL", vc->pg_rank, me, sreq);
274
275
276
277
                /* increment the cc for the get operation */
                MPIDI_CH3U_Request_increment_cc(sreq, &was_incomplete);
                MPIU_Assert(was_incomplete);
                REQ_PTL(sreq)->num_gets = 1;
278
279

                /* Create MD for first chunk */
280
                md.start = sreq->dev.iov;
281
                md.length = initial_iov_count;
282
                md.options = PTL_IOVEC;
283
                md.eq_handle = MPIDI_nem_ptl_origin_eq;
284
285
                md.ct_handle = PTL_CT_NONE;
                ret = PtlMDBind(MPIDI_nem_ptl_ni, &md, &REQ_PTL(sreq)->md);
286
                MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlmdbind", "**ptlmdbind %s", MPID_nem_ptl_strerror(ret));
287
288

                REQ_PTL(sreq)->large = TRUE;
289

290
                REQ_PTL(sreq)->event_handler = handler_send;
291
                ret = MPID_nem_ptl_rptl_put(REQ_PTL(sreq)->md, 0, PTL_LARGE_THRESHOLD, PTL_NO_ACK_REQ, vc_ptl->id, vc_ptl->pt,
292
                             NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), 0, sreq,
293
                                            NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
294
                MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
295
                DBG_MSG_PUT("req", PTL_LARGE_THRESHOLD, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
296
                goto fn_exit;
297
298
            }
        }
299
300
301
        /* First chunk of message fits, but the rest doesn't */
        /* Don't handle this case separately */
    }
302

303
304
    /* allocate a temporary buffer and copy all the data to send */
    MPIU_CHKPMEM_MALLOC(REQ_PTL(sreq)->chunk_buffer[0], void *, data_sz, mpi_errno, "tmpbuf");
305

306
307
308
    last = data_sz;
    MPID_Segment_pack(sreq->dev.segment_ptr, 0, &last, REQ_PTL(sreq)->chunk_buffer[0]);
    MPIU_Assert(last == data_sz);
309

310
311
    big_meappend((char *)REQ_PTL(sreq)->chunk_buffer[0] + PTL_LARGE_THRESHOLD, data_sz - PTL_LARGE_THRESHOLD, vc,
                 NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), sreq);
312
    REQ_PTL(sreq)->large = TRUE;
313

314
    REQ_PTL(sreq)->event_handler = handler_send;
315
    ret = MPID_nem_ptl_rptl_put(MPIDI_nem_ptl_global_md, (ptl_size_t)REQ_PTL(sreq)->chunk_buffer[0], PTL_LARGE_THRESHOLD,
316
                                PTL_NO_ACK_REQ, vc_ptl->id, vc_ptl->pt, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank),
317
                                0, sreq, NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
318
    MPIU_ERR_CHKANDJUMP1(ret, mpi_errno, MPI_ERR_OTHER, "**ptlput", "**ptlput %s", MPID_nem_ptl_strerror(ret));
319
    DBG_MSG_PUT("global", PTL_LARGE_THRESHOLD, vc->pg_rank, NPTL_MATCH(tag, comm->context_id + context_offset, comm->rank), NPTL_HEADER(ssend_flag | NPTL_LARGE, data_sz));
320
    
321
322
323
324
325
326
327
 fn_exit:
    *request = sreq;
    MPIU_CHKPMEM_COMMIT();
    MPIDI_FUNC_EXIT(MPID_STATE_SEND_MSG);
    return mpi_errno;
 fn_fail:
    if (sreq) {
328
        MPID_Request_release(sreq);
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
        sreq = NULL;
    }
    MPIU_CHKPMEM_REAP();
    goto fn_exit;
}

#undef FUNCNAME
#define FUNCNAME MPID_nem_ptl_isend
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
int MPID_nem_ptl_isend(struct MPIDI_VC *vc, const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
                       MPID_Comm *comm, int context_offset, struct MPID_Request **request)
{
    int mpi_errno = MPI_SUCCESS;
    MPIDI_STATE_DECL(MPID_STATE_MPID_NEM_PTL_ISEND);

    MPIDI_FUNC_ENTER(MPID_STATE_MPID_NEM_PTL_ISEND);

    mpi_errno = send_msg(0, vc, buf, count, datatype, dest, tag, comm, context_offset, request);

    MPIDI_FUNC_EXIT(MPID_STATE_MPID_NEM_PTL_ISEND);
    return mpi_errno;
}


#undef FUNCNAME
#define FUNCNAME MPID_nem_ptl_issend
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
int MPID_nem_ptl_issend(struct MPIDI_VC *vc, const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
                        MPID_Comm *comm, int context_offset, struct MPID_Request **request)
{
    int mpi_errno = MPI_SUCCESS;
    MPIDI_STATE_DECL(MPID_STATE_MPID_NEM_PTL_ISSEND);

    MPIDI_FUNC_ENTER(MPID_STATE_MPID_NEM_PTL_ISSEND);

    mpi_errno = send_msg(NPTL_SSEND, vc, buf, count, datatype, dest, tag, comm, context_offset, request);

    MPIDI_FUNC_EXIT(MPID_STATE_MPID_NEM_PTL_ISSEND);
    return mpi_errno;
}
371
372
373
374
375
376
377
378

#undef FUNCNAME
#define FUNCNAME MPID_nem_ptl_cancel_send
#undef FCNAME
#define FCNAME MPIU_QUOTE(FUNCNAME)
int MPID_nem_ptl_cancel_send(struct MPIDI_VC *vc,  struct MPID_Request *sreq)
{
    int mpi_errno = MPI_SUCCESS;
379
380
381
382
    MPID_PKT_DECL_CAST(upkt, MPIDI_nem_ptl_pkt_cancel_send_req_t, csr_pkt);
    MPID_Request *csr_sreq;
    int was_incomplete;

383
384
385
386
    MPIDI_STATE_DECL(MPID_STATE_MPID_NEM_PTL_CANCEL_SEND);

    MPIDI_FUNC_ENTER(MPID_STATE_MPID_NEM_PTL_CANCEL_SEND);

387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
    /* The completion counter and reference count are incremented to keep
       the request around long enough to receive a
       response regardless of what the user does (free the request before
       waiting, etc.). */
    MPIDI_CH3U_Request_increment_cc(sreq, &was_incomplete);
    if (!was_incomplete) {
        /* The reference count is incremented only if the request was
           complete before the increment. */
        MPIR_Request_add_ref(sreq);
    }

    csr_pkt->type = MPIDI_NEM_PKT_NETMOD;
    csr_pkt->subtype = MPIDI_NEM_PTL_PKT_CANCEL_SEND_REQ;
    csr_pkt->match.parts.rank = sreq->dev.match.parts.rank;
    csr_pkt->match.parts.tag = sreq->dev.match.parts.tag;
    csr_pkt->match.parts.context_id = sreq->dev.match.parts.context_id;
    csr_pkt->sender_req_id = sreq->handle;

    MPID_nem_ptl_iStartContigMsg(vc, csr_pkt, sizeof(*csr_pkt), NULL,
                                 0, &csr_sreq);

    if (csr_sreq != NULL)
        MPID_Request_release(csr_sreq);
410
411
412
413
414
415
416

 fn_exit:
    MPIDI_FUNC_EXIT(MPID_STATE_MPID_NEM_PTL_CANCEL_SEND);
    return mpi_errno;
 fn_fail:
    goto fn_exit;
}