1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  *  (C) 2001 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6 
7 #include "mpiimpl.h"
8 #include "mpibsend.h"
9 #include "bsendutil.h"
10 
11 /*
12  * Miscellaneous comments
13  * By storing total_size along with "size available for messages", we
14  * avoid any complexities associated with alignment, since we must
15  * ensure that each KPIR_Bsend_data_t structure is properly aligned
16  * (i.e., we can't simply do (sizeof(MPIR_Bsend_data_t) + size) to get
17  * total_size).
18  *
19  * Function Summary
20  *   MPIR_Bsend_attach - Performs the work of MPI_Buffer_attach
21  *   MPIR_Bsend_detach - Performs the work of MPI_Buffer_detach
22  *   MPIR_Bsend_isend  - Essentially performs an MPI_Ibsend.  Returns
23  *                an MPID_Request that is also stored internally in the
24  *                corresponding MPIR_Bsend_data_t entry
25  *   MPIR_Bsend_free_segment - Free a buffer that is no longer needed,
26  *                merging with adjacent segments
27  *   MPIR_Bsend_check_active - Check for completion of any pending sends
28  *                for bsends (all bsends, both MPI_Ibsend and MPI_Bsend,
29  *                are internally converted into Isends on the data
30  *                in the Bsend buffer)
31  *   MPIR_Bsend_retry_pending - Routine for future use to handle the
32  *                case where an Isend cannot be initiated.
33  *   MPIR_Bsend_find_buffer - Find a buffer in the bsend buffer large
34  *                enough for the message.  However, does not acquire that
35  *                buffer (see MPIR_Bsend_take_buffer)
36  *   MPIR_Bsend_take_buffer - Find and acquire a buffer for a message
37  *   MPIR_Bsend_finalize - Finalize handler when Bsend routines are used
38  *   MPIR_Bsend_dump - Debugging routine to print the contents of the control
39  *                information in the bsend buffer (the MPIR_Bsend_data_t entries)
40  */
41 
42 #ifdef USE_DBG_LOGGING
43 static void MPIR_Bsend_dump( void );
44 #endif
45 
46 #define BSENDDATA_HEADER_TRUE_SIZE (sizeof(MPIR_Bsend_data_t) - sizeof(double))
47 
48 /* BsendBuffer is the structure that describes the overall Bsend buffer */
49 /*
50  * We use separate buffer and origbuffer because we may need to align
51  * the buffer (we *could* always memcopy the header to an aligned region,
52  * but it is simpler to just align it internally.  This does increase the
53  * BSEND_OVERHEAD, but that is already relatively large.  We could instead
54  * make sure that the initial header was set at an aligned location (
55  * taking advantage of the "alignpad"), but this would require more changes.
56  */
57 static struct BsendBuffer {
58     void               *buffer;        /* Pointer to the begining of the user-
59 					  provided buffer */
60     int                buffer_size;    /* Size of the user-provided buffer */
61     void               *origbuffer;    /* Pointer to the buffer provided by
62 					  the user */
63     int                origbuffer_size; /* Size of the buffer as provided
64 					    by the user */
65     MPIR_Bsend_data_t  *avail;         /* Pointer to the first available block
66 					  of space */
67     MPIR_Bsend_data_t  *pending;       /* Pointer to the first message that
68 					  could not be sent because of a
69 					  resource limit (e.g., no requests
70 					  available) */
71     MPIR_Bsend_data_t  *active;        /* Pointer to the first active (sending)
72 					  message */
73 } BsendBuffer = { 0, 0, 0, 0, 0, 0, 0 };
74 
75 static int initialized = 0;   /* keep track of the first call to any
76 				 bsend routine */
77 
78 /* Forward references */
79 static void MPIR_Bsend_retry_pending( void );
80 static int MPIR_Bsend_check_active ( void );
81 static MPIR_Bsend_data_t *MPIR_Bsend_find_buffer( int );
82 static void MPIR_Bsend_take_buffer( MPIR_Bsend_data_t *, int );
83 static int MPIR_Bsend_finalize( void * );
84 
85 /*
86  * Attach a buffer.  This checks for the error conditions and then
87  * initialized the avail buffer.
88  */
89 #undef FUNCNAME
90 #define FUNCNAME MPIR_Bsend_attach
91 #undef FCNAME
92 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Bsend_attach(void * buffer,int buffer_size)93 int MPIR_Bsend_attach( void *buffer, int buffer_size )
94 {
95     MPIR_Bsend_data_t *p;
96     size_t offset, align_sz;
97 
98 #   ifdef HAVE_ERROR_CHECKING
99     {
100         MPID_BEGIN_ERROR_CHECKS;
101         {
102 	    if (BsendBuffer.buffer) {
103 		return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
104                          "MPIR_Bsend_attach", __LINE__, MPI_ERR_BUFFER,
105 					     "**bufexists", 0 );
106 	    }
107 	    if (buffer_size < MPI_BSEND_OVERHEAD) {
108 		/* MPI_ERR_OTHER is another valid choice for this error,
109 		 but the Intel test wants MPI_ERR_BUFFER, and it seems
110 		 to violate the principle of least surprise to not use
111 		 MPI_ERR_BUFFER for errors with the Buffer */
112 		return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
113 		    "MPIR_Bsend_attach", __LINE__, MPI_ERR_BUFFER,
114 		    "**bsendbufsmall",
115                     "**bsendbufsmall %d %d", buffer_size, MPI_BSEND_OVERHEAD );
116 	    }
117 	}
118 	MPID_END_ERROR_CHECKS;
119     }
120 #   endif /* HAVE_ERROR_CHECKING */
121 
122     if (!initialized) {
123 	initialized = 1;
124 	MPIR_Add_finalize( MPIR_Bsend_finalize, (void *)0, 10 );
125     }
126 
127     BsendBuffer.origbuffer	= buffer;
128     BsendBuffer.origbuffer_size	= buffer_size;
129     BsendBuffer.buffer		= buffer;
130     BsendBuffer.buffer_size	= buffer_size;
131 
132     /* Make sure that the buffer that we use is aligned to align_sz.  Some other
133        code assumes pointer-alignment, and some code assumes double alignment.
134        Further, GCC 4.5.1 generates bad code on 32-bit platforms when this is
135        only 4-byte aligned (see #1149). */
136     align_sz = MPIR_MAX(sizeof(void *), sizeof(double));
137     offset = ((size_t)buffer) % align_sz;
138     if (offset) {
139         offset = align_sz - offset;
140 	buffer = (char *)buffer + offset;
141 	BsendBuffer.buffer      = buffer;
142 	BsendBuffer.buffer_size -= offset;
143     }
144     BsendBuffer.avail		= buffer;
145     BsendBuffer.pending		= 0;
146     BsendBuffer.active		= 0;
147 
148     /* Set the first block */
149     p		  = (MPIR_Bsend_data_t *)buffer;
150     p->size	  = buffer_size - BSENDDATA_HEADER_TRUE_SIZE;
151     p->total_size = buffer_size;
152     p->next	  = p->prev = NULL;
153     p->msg.msgbuf = (char *)p + BSENDDATA_HEADER_TRUE_SIZE;
154 
155     return MPI_SUCCESS;
156 }
157 
158 /*
159  * Detach a buffer.  This routine must wait until any pending bsends
160  * are complete.
161  */
162 #undef FUNCNAME
163 #define FUNCNAME MPIR_Bsend_detach
164 #undef FCNAME
165 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Bsend_detach(void * bufferp,int * size)166 int MPIR_Bsend_detach( void *bufferp, int *size )
167 {
168     if (BsendBuffer.pending) {
169 	/* FIXME: Process pending bsend requests in detach */
170 	return MPIR_Err_create_code( MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
171             "MPIR_Bsend_detach", __LINE__, MPI_ERR_OTHER, "**bsendpending", 0 );
172     }
173     if (BsendBuffer.active) {
174 	/* Loop through each active element and wait on it */
175 	MPIR_Bsend_data_t *p = BsendBuffer.active;
176 
177 	while (p) {
178 	    MPI_Request r = p->request->handle;
179 	    MPIR_Wait_impl( &r, MPI_STATUS_IGNORE );
180 	    p = p->next;
181 	}
182     }
183 
184 /* Note that this works even when the buffer does not exist */
185     *(void **) bufferp  = BsendBuffer.origbuffer;
186     *size = BsendBuffer.origbuffer_size;
187     BsendBuffer.origbuffer = NULL;
188     BsendBuffer.origbuffer_size = 0;
189     BsendBuffer.buffer  = 0;
190     BsendBuffer.buffer_size  = 0;
191     BsendBuffer.avail   = 0;
192     BsendBuffer.active  = 0;
193     BsendBuffer.pending = 0;
194 
195     return MPI_SUCCESS;
196 }
197 
198 /*
199  * Initiate an ibsend.  We'll used this for Bsend as well.
200  */
201 #undef FUNCNAME
202 #define FUNCNAME MPIR_Bsend_isend
203 #undef FCNAME
204 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Bsend_isend(const void * buf,int count,MPI_Datatype dtype,int dest,int tag,MPID_Comm * comm_ptr,MPIR_Bsend_kind_t kind,MPID_Request ** request)205 int MPIR_Bsend_isend(const void *buf, int count, MPI_Datatype dtype,
206                      int dest, int tag, MPID_Comm *comm_ptr,
207                      MPIR_Bsend_kind_t kind, MPID_Request **request )
208 {
209     int mpi_errno = MPI_SUCCESS;
210     MPIR_Bsend_data_t *p;
211     MPIR_Bsend_msg_t *msg;
212     int packsize, pass;
213 
214     /* Find a free segment and copy the data into it.  If we could
215        have, we would already have used tBsend to send the message with
216        no copying.
217 
218        We may want to decide here whether we need to pack at all
219        or if we can just use (a MPIU_Memcpy) of the buffer.
220     */
221 
222 
223     /* We check the active buffer first.  This helps avoid storage
224        fragmentation */
225     mpi_errno = MPIR_Bsend_check_active();
226     if (mpi_errno) MPIU_ERR_POP(mpi_errno);
227 
228     if (dtype != MPI_PACKED)
229         MPIR_Pack_size_impl( count, dtype, &packsize );
230     else
231         packsize = count;
232 
233     MPIU_DBG_MSG_D(BSEND,TYPICAL,"looking for buffer of size %d", packsize);
234     /*
235      * Use two passes.  Each pass is the same; between the two passes,
236      * attempt to complete any active requests, and start any pending
237      * ones.  If the message can be initiated in the first pass,
238      * do not perform the second pass.
239      */
240     for (pass = 0; pass < 2; pass++) {
241 
242 	p = MPIR_Bsend_find_buffer( packsize );
243 	if (p) {
244 	    MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
245                      "found buffer of size %d with address %p",packsize,p));
246 	    /* Found a segment */
247 
248 	    msg = &p->msg;
249 
250 	    /* Pack the data into the buffer */
251 	    /* We may want to optimize for the special case of
252 	       either primative or contiguous types, and just
253 	       use MPIU_Memcpy and the provided datatype */
254 	    msg->count = 0;
255             if (dtype != MPI_PACKED)
256             {
257                 mpi_errno = MPIR_Pack_impl( buf, count, dtype, p->msg.msgbuf, packsize, &p->msg.count);
258                 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
259             }
260             else
261             {
262                 MPIU_Memcpy(p->msg.msgbuf, buf, count);
263                 p->msg.count = count;
264             }
265 	    /* Try to send the message.  We must use MPID_Isend
266 	       because this call must not block */
267 	    mpi_errno = MPID_Isend(msg->msgbuf, msg->count, MPI_PACKED,
268 				   dest, tag, comm_ptr,
269 				   MPID_CONTEXT_INTRA_PT2PT, &p->request );
270             MPIU_ERR_CHKINTERNAL(mpi_errno, mpi_errno, "Bsend internal error: isend returned err");
271             /* If the error is "request not available", we should
272                put this on the pending list.  This will depend on
273                how we signal failure to send. */
274 
275 	    if (p->request) {
276 		MPIU_DBG_MSG_FMT(BSEND,TYPICAL,
277 		    (MPIU_DBG_FDEST,"saving request %p in %p",p->request,p));
278 		/* An optimization is to check to see if the
279 		   data has already been sent.  The original code
280 		   to do this was commented out and probably did not match
281 		   the current request internals */
282 		MPIR_Bsend_take_buffer( p, p->msg.count );
283 		p->kind  = kind;
284 		*request = p->request;
285 	    }
286 	    break;
287 	}
288 	/* If we found a buffer or we're in the seccond pass, then break.
289 	    Note that the test on phere is redundant, as the code breaks
290 	    out of the loop in the test above if a block p is found. */
291 	if (p || pass == 1) break;
292 	MPIU_DBG_MSG(BSEND,TYPICAL,"Could not find storage, checking active");
293 	/* Try to complete some pending bsends */
294 	MPIR_Bsend_check_active( );
295 	/* Give priority to any pending operations */
296 	MPIR_Bsend_retry_pending( );
297     }
298 
299     if (!p) {
300 	/* Return error for no buffer space found */
301 	/* Generate a traceback of the allocated space, explaining why
302 	   packsize could not be found */
303 	MPIU_DBG_MSG(BSEND,TYPICAL,"Could not find space; dumping arena" );
304 	MPIU_DBG_STMT(BSEND,TYPICAL,MPIR_Bsend_dump());
305         MPIU_ERR_SETANDJUMP2(mpi_errno, MPI_ERR_BUFFER, "**bufbsend", "**bufbsend %d %d", packsize, BsendBuffer.buffer_size);
306     }
307 
308  fn_exit:
309     return mpi_errno;
310  fn_fail:
311     goto fn_exit;
312 }
313 
314 /*
315  * The following routines are used to manage the allocation of bsend segments
316  * in the user buffer.  These routines handle, for example, merging segments
317  * when an active segment that is adjacent to a free segment becomes free.
318  *
319  */
320 
321 /* Add block p to the free list. Merge into adjacent blocks.  Used only
322    within the check_active */
323 
324 #undef FUNCNAME
325 #define FUNCNAME MPIR_Bsend_free_segment
326 #undef FCNAME
327 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Bsend_free_segment(MPIR_Bsend_data_t * p)328 static void MPIR_Bsend_free_segment( MPIR_Bsend_data_t *p )
329 {
330     MPIR_Bsend_data_t *prev = p->prev, *avail = BsendBuffer.avail, *avail_prev;
331 
332     MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
333                  "Freeing bsend segment at %p of size %d, next at %p",
334 		 p,p->size, ((char *)p)+p->total_size));
335 
336     MPIU_DBG_MSG_D(BSEND,TYPICAL,
337 	     "At the begining of free_segment with size %d:", p->total_size );
338     MPIU_DBG_STMT(BSEND,TYPICAL,MPIR_Bsend_dump());
339 
340     /* Remove the segment from the active list */
341     if (prev) {
342 	MPIU_DBG_MSG(BSEND,TYPICAL,"free segment is within active list");
343 	prev->next = p->next;
344     }
345     else {
346 	/* p was at the head of the active list */
347 	MPIU_DBG_MSG(BSEND,TYPICAL,"free segment is head of active list");
348 	BsendBuffer.active = p->next;
349 	/* The next test sets the prev pointer to null */
350     }
351     if (p->next) {
352 	p->next->prev = prev;
353     }
354 
355     MPIU_DBG_STMT(BSEND,VERBOSE,MPIR_Bsend_dump());
356 
357     /* Merge into the avail list */
358     /* Find avail_prev, avail, such that p is between them.
359        either may be null if p is at either end of the list */
360     avail_prev = 0;
361     while (avail) {
362 	if (avail > p) {
363 	    break;
364 	}
365 	avail_prev = avail;
366 	avail      = avail->next;
367     }
368 
369     /* Try to merge p with the next block */
370     if (avail) {
371 	if ((char *)p + p->total_size == (char *)avail) {
372 	    p->total_size += avail->total_size;
373 	    p->size       = p->total_size - BSENDDATA_HEADER_TRUE_SIZE;
374 	    p->next = avail->next;
375 	    if (avail->next) avail->next->prev = p;
376 	    avail = 0;
377 	}
378 	else {
379 	    p->next = avail;
380 	    avail->prev = p;
381 	}
382     }
383     else {
384 	p->next = 0;
385     }
386     /* Try to merge p with the previous block */
387     if (avail_prev) {
388 	if ((char *)avail_prev + avail_prev->total_size == (char *)p) {
389 	    avail_prev->total_size += p->total_size;
390 	    avail_prev->size       = avail_prev->total_size - BSENDDATA_HEADER_TRUE_SIZE;
391 	    avail_prev->next = p->next;
392 	    if (p->next) p->next->prev = avail_prev;
393 	}
394 	else {
395 	    avail_prev->next = p;
396 	    p->prev          = avail_prev;
397 	}
398     }
399     else {
400 	/* p is the new head of the list */
401 	BsendBuffer.avail = p;
402 	p->prev           = 0;
403     }
404 
405     MPIU_DBG_MSG(BSEND,TYPICAL,"At the end of free_segment:" );
406     MPIU_DBG_STMT(BSEND,TYPICAL,MPIR_Bsend_dump());
407 }
408 
409 /*
410  * The following routine tests for completion of active sends and
411  * frees the related storage
412  *
413  * To make it easier to identify the source of the request, we keep
414  * track of the type of MPI routine (ibsend, bsend, or bsend_init/start)
415  * that created the bsend entry.
416  */
417 #undef FUNCNAME
418 #define FUNCNAME MPIR_Bsend_check_active
419 #undef FCNAME
420 #define FCNAME MPIDI_QUOTE(FUNCNAME)
MPIR_Bsend_check_active(void)421 static int MPIR_Bsend_check_active( void )
422 {
423     int mpi_errno = MPI_SUCCESS;
424     MPIR_Bsend_data_t *active = BsendBuffer.active, *next_active;
425 
426     MPIU_DBG_MSG_P(BSEND,TYPICAL,"Checking active starting at %p", active);
427     while (active) {
428 	MPI_Request r = active->request->handle;
429 	int         flag;
430 
431 	next_active = active->next;
432 
433 	if (active->kind == IBSEND) {
434 	    /* We handle ibsend specially to allow for the user
435 	       to attempt and cancel the request. Also, to allow
436 	       for a cancel attempt (which must be attempted before
437 	       a successful test or wait), we only start
438 	       testing when the user has successfully released
439 	       the request (it is a grequest, the free call will do it) */
440 	    flag = 0;
441             /* XXX DJG FIXME-MT should we be checking this? */
442 	    if (MPIU_Object_get_ref(active->request) == 1) {
443 		mpi_errno = MPIR_Test_impl(&r, &flag, MPI_STATUS_IGNORE );
444                 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
445 	    } else {
446 		/* We need to invoke the progress engine in case we
447 		 need to advance other, incomplete communication.  */
448 		MPID_Progress_state progress_state;
449 		MPID_Progress_start(&progress_state);
450 		mpi_errno = MPID_Progress_test( );
451 		MPID_Progress_end(&progress_state);
452                 if (mpi_errno) MPIU_ERR_POP(mpi_errno);
453 	    }
454 	} else {
455 	    mpi_errno = MPIR_Test_impl( &r, &flag, MPI_STATUS_IGNORE );
456             if (mpi_errno) MPIU_ERR_POP(mpi_errno);
457 	}
458 	if (flag) {
459 	    /* We're done.  Remove this segment */
460 	    MPIU_DBG_MSG_P(BSEND,TYPICAL,"Removing segment %p", active);
461 	    MPIR_Bsend_free_segment( active );
462 	}
463 	active = next_active;
464 	MPIU_DBG_MSG_P(BSEND,TYPICAL,"Next active is %p",active);
465     }
466 
467  fn_exit:
468     return mpi_errno;
469  fn_fail:
470     goto fn_exit;
471 }
472 
473 /*
474  * FIXME : For each pending item (that is, items that we couldn't even start
475  * sending), try to get them going.
476  */
MPIR_Bsend_retry_pending(void)477 static void MPIR_Bsend_retry_pending( void )
478 {
479     MPIR_Bsend_data_t *pending = BsendBuffer.pending, *next_pending;
480 
481     while (pending) {
482 	next_pending = pending->next;
483 	/* Retry sending this item */
484 	/* FIXME: Unimplemented retry of pending bsend operations */
485 	pending = next_pending;
486     }
487 }
488 
489 /*
490  * Find a slot in the avail buffer that can hold size bytes.  Does *not*
491  * remove the slot from the avail buffer (see MPIR_Bsend_take_buffer)
492  */
MPIR_Bsend_find_buffer(int size)493 static MPIR_Bsend_data_t *MPIR_Bsend_find_buffer( int size )
494 {
495     MPIR_Bsend_data_t *p = BsendBuffer.avail;
496 
497     while (p) {
498 	if (p->size >= size) {
499 	    return p;
500 	}
501 	p = p->next;
502     }
503     return 0;
504 }
505 
506 /* This is the minimum number of bytes that a segment must be able to
507    hold. */
508 #define MIN_BUFFER_BLOCK 8
509 /*
510  * Carve off size bytes from buffer p and leave the remainder
511  * on the avail list.  Handle the head/tail cases.
512  * If there isn't enough left of p, remove the entire segment from
513  * the avail list.
514  */
MPIR_Bsend_take_buffer(MPIR_Bsend_data_t * p,int size)515 static void MPIR_Bsend_take_buffer( MPIR_Bsend_data_t *p, int size  )
516 {
517     MPIR_Bsend_data_t *prev;
518     int         alloc_size;
519 
520     /* Compute the remaining size.  This must include any padding
521        that must be added to make the new block properly aligned */
522     alloc_size = size;
523     if (alloc_size & 0x7)
524 	alloc_size += (8 - (alloc_size & 0x7));
525     /* alloc_size is the amount of space (out of size) that we will
526        allocate for this buffer. */
527 
528     MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
529 			    "Taking %d bytes from a block with %d bytes\n",
530 				    alloc_size, p->total_size ));
531 
532     /* Is there enough space left to create a new block? */
533     if (alloc_size + (int)BSENDDATA_HEADER_TRUE_SIZE + MIN_BUFFER_BLOCK <= p->size) {
534 	/* Yes, the available space (p->size) is large enough to
535 	   carve out a new block */
536 	MPIR_Bsend_data_t *newp;
537 
538 	MPIU_DBG_MSG_P(BSEND,TYPICAL,"Breaking block into used and allocated at %p", p );
539 	newp = (MPIR_Bsend_data_t *)( (char *)p + BSENDDATA_HEADER_TRUE_SIZE +
540 				alloc_size );
541 	newp->total_size = p->total_size - alloc_size -
542 	    BSENDDATA_HEADER_TRUE_SIZE;
543 	newp->size = newp->total_size - BSENDDATA_HEADER_TRUE_SIZE;
544 	newp->msg.msgbuf = (char *)newp + BSENDDATA_HEADER_TRUE_SIZE;
545 
546 	/* Insert this new block after p (we'll remove p from the avail list
547 	   next) */
548 	newp->next = p->next;
549 	newp->prev = p;
550 	if (p->next) {
551 	    p->next->prev = newp;
552 	}
553 	p->next       = newp;
554 	p->total_size = (char *)newp - (char*)p;
555 	p->size       = p->total_size - BSENDDATA_HEADER_TRUE_SIZE;
556 
557 	MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
558 		   "broken blocks p (%d) and new (%d)\n",
559 		    p->total_size, newp->total_size ));
560     }
561 
562     /* Remove p from the avail list and add it to the active list */
563     prev = p->prev;
564     if (prev) {
565 	prev->next = p->next;
566     }
567     else {
568 	BsendBuffer.avail = p->next;
569     }
570 
571     if (p->next) {
572 	p->next->prev = p->prev;
573     }
574 
575     if (BsendBuffer.active) {
576 	BsendBuffer.active->prev = p;
577     }
578     p->next	       = BsendBuffer.active;
579     p->prev	       = 0;
580     BsendBuffer.active = p;
581 
582     MPIU_DBG_MSG_P(BSEND,VERBOSE,"segment %p now head of active",p);
583     MPIU_DBG_MSG(BSEND,TYPICAL,"At end of take buffer" );
584     MPIU_DBG_STMT(BSEND,TYPICAL,MPIR_Bsend_dump());
585 }
586 
MPIR_Bsend_finalize(void * p ATTRIBUTE ((unused)))587 static int MPIR_Bsend_finalize( void *p ATTRIBUTE((unused)) )
588 {
589     void *b;
590     int  s;
591 
592     MPIU_UNREFERENCED_ARG(p);
593 
594     if (BsendBuffer.buffer) {
595 	/* Use detach to complete any communication */
596 	MPIR_Bsend_detach( &b, &s );
597     }
598     return 0;
599 }
600 
601 /*
602  * These routines are defined only if debug logging is enabled
603  */
604 #ifdef USE_DBG_LOGGING
MPIR_Bsend_dump(void)605 static void MPIR_Bsend_dump( void )
606 {
607     MPIR_Bsend_data_t *a = BsendBuffer.avail;
608 
609     MPIU_DBG_MSG_D(BSEND,TYPICAL,"Total size is %d",BsendBuffer.buffer_size );
610     MPIU_DBG_MSG(BSEND,TYPICAL,"Avail list is:" );
611     while (a) {
612 	MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
613 				"[%p] totalsize = %d(%x)", a, a->total_size,
614 					a->total_size ));
615 	if (a == a->next) {
616 	    MPIU_DBG_MSG(BSEND,TYPICAL,
617 			 "@@@Corrupt list; avail block points at itself" );
618 	    break;
619 	}
620 	a = a->next;
621     }
622 
623     MPIU_DBG_MSG(BSEND,TYPICAL,"Active list is:" );
624     a = BsendBuffer.active;
625     while (a) {
626 	MPIU_DBG_MSG_FMT(BSEND,TYPICAL,(MPIU_DBG_FDEST,
627 				"[%p] totalsize = %d(%x)", a, a->total_size,
628 					a->total_size ));
629 	if (a == a->next) {
630 	    MPIU_DBG_MSG(BSEND,TYPICAL,
631 			 "@@@Corrupt list; active block points at itself" );
632 	    break;
633 	}
634 	a = a->next;
635     }
636     MPIU_DBG_MSG(BSEND,TYPICAL,"end of list" );
637 }
638 #endif
639