1 /* -*- Mode: C; c-basic-offset:4 ; -*- */ 2 /* 3 * (C) 2001 by Argonne National Laboratory. 4 * See COPYRIGHT in top-level directory. 5 */ 6 #ifndef MPIMEM_H_INCLUDED 7 #define MPIMEM_H_INCLUDED 8 9 /* Make sure that we have the definitions for the malloc routines and size_t */ 10 #include <stdio.h> 11 #include <stdlib.h> 12 /* strdup is often declared in string.h, so if we plan to redefine strdup, 13 we need to include string first. That is done below, only in the 14 case where we redefine strdup */ 15 16 #if defined(__cplusplus) 17 extern "C" { 18 #endif 19 20 #include "mpichconf.h" 21 #include "mpl.h" 22 23 /* ensure that we weren't included out of order */ 24 #include "mpibase.h" 25 26 /* ------------------------------------------------------------------------- */ 27 /* mpimem.h */ 28 /* ------------------------------------------------------------------------- */ 29 /* Memory allocation */ 30 /* style: allow:malloc:2 sig:0 */ 31 /* style: allow:free:2 sig:0 */ 32 /* style: allow:strdup:2 sig:0 */ 33 /* style: allow:calloc:2 sig:0 */ 34 /* style: allow:realloc:1 sig:0 */ 35 /* style: allow:alloca:1 sig:0 */ 36 /* style: define:__strdup:1 sig:0 */ 37 /* style: define:strdup:1 sig:0 */ 38 /* style: allow:fprintf:5 sig:0 */ /* For handle debugging ONLY */ 39 /* style: allow:snprintf:1 sig:0 */ 40 41 /*D 42 Memory - Memory Management Routines 43 44 Rules for memory management: 45 46 MPICH explicity prohibits the appearence of 'malloc', 'free', 47 'calloc', 'realloc', or 'strdup' in any code implementing a device or 48 MPI call (of course, users may use any of these calls in their code). 49 Instead, you must use 'MPIU_Malloc' etc.; if these are defined 50 as 'malloc', that is allowed, but an explicit use of 'malloc' instead of 51 'MPIU_Malloc' in the source code is not allowed. This restriction is 52 made to simplify the use of portable tools to test for memory leaks, 53 overwrites, and other consistency checks. 54 55 Most memory should be allocated at the time that 'MPID_Init' is 56 called and released with 'MPID_Finalize' is called. If at all possible, 57 no other MPID routine should fail because memory could not be allocated 58 (for example, because the user has allocated large arrays after 'MPI_Init'). 59 60 The implementation of the MPI routines will strive to avoid memory allocation 61 as well; however, operations such as 'MPI_Type_index' that create a new 62 data type that reflects data that must be copied from an array of arbitrary 63 size will have to allocate memory (and can fail; note that there is an 64 MPI error class for out-of-memory). 65 66 Question: 67 Do we want to have an aligned allocation routine? E.g., one that 68 aligns memory on a cache-line. 69 D*/ 70 71 /* Define the string copy and duplication functions */ 72 /* Safer string routines */ 73 int MPIU_Strncpy( char *outstr, const char *instr, size_t maxlen ); 74 75 int MPIU_Strnapp( char *, const char *, size_t ); 76 char *MPIU_Strdup( const char * ); 77 78 /* ---------------------------------------------------------------------- */ 79 /* FIXME - The string routines do not belong in the memory header file */ 80 /* FIXME - The string error code such be MPICH2-usable error codes */ 81 #define MPIU_STR_SUCCESS 0 82 #define MPIU_STR_FAIL -1 83 #define MPIU_STR_NOMEM 1 84 85 /* FIXME: TRUE/FALSE definitions should either not be used or be 86 used consistently. These also do not belong in the mpimem header file. */ 87 #define MPIU_TRUE 1 88 #define MPIU_FALSE 0 89 90 /* FIXME: Global types like this need to be discussed and agreed to */ 91 typedef int MPIU_BOOL; 92 93 /* FIXME: These should be scoped to only the routines that need them */ 94 #ifdef USE_HUMAN_READABLE_TOKENS 95 96 #define MPIU_STR_QUOTE_CHAR '\"' 97 #define MPIU_STR_QUOTE_STR "\"" 98 #define MPIU_STR_DELIM_CHAR '=' 99 #define MPIU_STR_DELIM_STR "=" 100 #define MPIU_STR_ESCAPE_CHAR '\\' 101 #define MPIU_STR_HIDE_CHAR '*' 102 #define MPIU_STR_SEPAR_CHAR ' ' 103 #define MPIU_STR_SEPAR_STR " " 104 105 #else 106 107 #define MPIU_STR_QUOTE_CHAR '\"' 108 #define MPIU_STR_QUOTE_STR "\"" 109 #define MPIU_STR_DELIM_CHAR '#' 110 #define MPIU_STR_DELIM_STR "#" 111 #define MPIU_STR_ESCAPE_CHAR '\\' 112 #define MPIU_STR_HIDE_CHAR '*' 113 #define MPIU_STR_SEPAR_CHAR '$' 114 #define MPIU_STR_SEPAR_STR "$" 115 116 #endif 117 118 int MPIU_Str_get_string_arg(const char *str, const char *key, char *val, 119 int maxlen); 120 int MPIU_Str_get_binary_arg(const char *str, const char *key, char *buffer, 121 int maxlen, int *out_length); 122 int MPIU_Str_get_int_arg(const char *str, const char *key, int *val_ptr); 123 int MPIU_Str_add_string_arg(char **str_ptr, int *maxlen_ptr, const char *key, 124 const char *val); 125 int MPIU_Str_add_binary_arg(char **str_ptr, int *maxlen_ptr, const char *key, 126 const char *buffer, int length); 127 int MPIU_Str_add_int_arg(char **str_ptr, int *maxlen_ptr, const char *key, 128 int val); 129 MPIU_BOOL MPIU_Str_hide_string_arg(char *str, const char *key); 130 int MPIU_Str_add_string(char **str_ptr, int *maxlen_ptr, const char *val); 131 int MPIU_Str_get_string(char **str_ptr, char *val, int maxlen); 132 133 /* ------------------------------------------------------------------------- */ 134 135 void MPIU_trinit(int); 136 void *MPIU_trmalloc(unsigned int, int, const char []); 137 void MPIU_trfree(void *, int, const char []); 138 int MPIU_trvalid(const char []); 139 void MPIU_trspace(int *, int *); 140 void MPIU_trid(int); 141 void MPIU_trlevel(int); 142 void MPIU_trDebugLevel(int); 143 void *MPIU_trcalloc(unsigned int, unsigned int, int, const char []); 144 void *MPIU_trrealloc(void *, int, int, const char[]); 145 void *MPIU_trstrdup(const char *, int, const char[]); 146 void MPIU_TrSetMaxMem(int); 147 void MPIU_trdump(FILE *, int); 148 149 #ifdef USE_MEMORY_TRACING 150 /*M 151 MPIU_Malloc - Allocate memory 152 153 Synopsis: 154 .vb 155 void *MPIU_Malloc( size_t len ) 156 .ve 157 158 Input Parameter: 159 . len - Length of memory to allocate in bytes 160 161 Return Value: 162 Pointer to allocated memory, or null if memory could not be allocated. 163 164 Notes: 165 This routine will often be implemented as the simple macro 166 .vb 167 #define MPIU_Malloc(n) malloc(n) 168 .ve 169 However, it can also be defined as 170 .vb 171 #define MPIU_Malloc(n) MPIU_trmalloc(n,__FILE__,__LINE__) 172 .ve 173 where 'MPIU_trmalloc' is a tracing version of 'malloc' that is included with 174 MPICH. 175 176 Module: 177 Utility 178 M*/ 179 #define MPIU_Malloc(a) MPIU_trmalloc((unsigned)(a),__LINE__,__FILE__) 180 181 /*M 182 MPIU_Calloc - Allocate memory that is initialized to zero. 183 184 Synopsis: 185 .vb 186 void *MPIU_Calloc( size_t nelm, size_t elsize ) 187 .ve 188 189 Input Parameters: 190 + nelm - Number of elements to allocate 191 - elsize - Size of each element. 192 193 Notes: 194 Like 'MPIU_Malloc' and 'MPIU_Free', this will often be implemented as a 195 macro but may use 'MPIU_trcalloc' to provide a tracing version. 196 197 Module: 198 Utility 199 M*/ 200 #define MPIU_Calloc(a,b) \ 201 MPIU_trcalloc((unsigned)(a),(unsigned)(b),__LINE__,__FILE__) 202 203 /*M 204 MPIU_Free - Free memory 205 206 Synopsis: 207 .vb 208 void MPIU_Free( void *ptr ) 209 .ve 210 211 Input Parameter: 212 . ptr - Pointer to memory to be freed. This memory must have been allocated 213 with 'MPIU_Malloc'. 214 215 Notes: 216 This routine will often be implemented as the simple macro 217 .vb 218 #define MPIU_Free(n) free(n) 219 .ve 220 However, it can also be defined as 221 .vb 222 #define MPIU_Free(n) MPIU_trfree(n,__FILE__,__LINE__) 223 .ve 224 where 'MPIU_trfree' is a tracing version of 'free' that is included with 225 MPICH. 226 227 Module: 228 Utility 229 M*/ 230 #define MPIU_Free(a) MPIU_trfree(a,__LINE__,__FILE__) 231 232 #define MPIU_Strdup(a) MPIU_trstrdup(a,__LINE__,__FILE__) 233 234 #define MPIU_Realloc(a,b) MPIU_trrealloc((a),(b),__LINE__,__FILE__) 235 236 /* Define these as invalid C to catch their use in the code */ 237 #define malloc(a) 'Error use MPIU_Malloc' ::: 238 #define calloc(a,b) 'Error use MPIU_Calloc' ::: 239 #define free(a) 'Error use MPIU_Free' ::: 240 #define realloc(a) 'Error use MPIU_Realloc' ::: 241 #if defined(strdup) || defined(__strdup) 242 #undef strdup 243 #endif 244 /* We include string.h first, so that if it contains a definition of 245 strdup, we won't have an obscure failure when a file include string.h 246 later in the compilation process. */ 247 #include <string.h> 248 249 /* The ::: should cause the compiler to choke; the string 250 will give the explanation */ 251 #undef strdup /* in case strdup is a macro */ 252 #define strdup(a) 'Error use MPIU_Strdup' ::: 253 254 #else /* USE_MEMORY_TRACING */ 255 /* No memory tracing; just use native functions */ 256 #define MPIU_Malloc(a) malloc((size_t)(a)) 257 #define MPIU_Calloc(a,b) calloc((size_t)(a),(size_t)(b)) 258 #define MPIU_Free(a) free((void *)(a)) 259 #define MPIU_Realloc(a,b) realloc((void *)(a),(size_t)(b)) 260 261 #ifdef HAVE_STRDUP 262 /* Watch for the case where strdup is defined as a macro by a header include */ 263 # if defined(NEEDS_STRDUP_DECL) && !defined(strdup) 264 extern char *strdup( const char * ); 265 # endif 266 #define MPIU_Strdup(a) strdup(a) 267 #else 268 /* Don't define MPIU_Strdup, provide it in safestr.c */ 269 #endif /* HAVE_STRDUP */ 270 271 #endif /* USE_MEMORY_TRACING */ 272 273 274 /* Memory allocation macros. See document. */ 275 276 /* You can redefine this to indicate whether memory allocation errors 277 are fatal. Recoverable by default */ 278 #define MPIU_CHKMEM_ISFATAL MPIR_ERR_RECOVERABLE 279 280 /* Standard macro for generating error codes. */ 281 #ifdef HAVE_ERROR_CHECKING 282 #define MPIU_CHKMEM_SETERR(rc_,nbytes_,name_) \ 283 rc_=MPIR_Err_create_code( MPI_SUCCESS, \ 284 MPIU_CHKMEM_ISFATAL, FCNAME, __LINE__, \ 285 MPI_ERR_OTHER, "**nomem2", "**nomem2 %d %s", nbytes_, name_ ) 286 #else 287 #define MPIU_CHKMEM_SETERR(rc_,nbytes_,name_) rc_=MPI_ERR_OTHER 288 #endif 289 290 /* CHKPMEM_REGISTER is used for memory allocated within another routine */ 291 292 /* Memory used and freed within the current scopy (alloca if feasible) */ 293 /* Configure with --enable-alloca to set USE_ALLOCA */ 294 #if defined(HAVE_ALLOCA) && defined(USE_ALLOCA) 295 #ifdef HAVE_ALLOCA_H 296 #include <alloca.h> 297 #endif 298 /* Define decl with a dummy definition to allow us to put a semi-colon 299 after the macro without causing the declaration block to end (restriction 300 imposed by C) */ 301 #define MPIU_CHKLMEM_DECL(n_) int dummy_ 302 #define MPIU_CHKLMEM_FREEALL() 303 #define MPIU_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 304 {pointer_ = (type_)alloca(nbytes_); \ 305 if (!(pointer_) && (nbytes_ > 0)) { \ 306 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 307 stmt_;\ 308 }} 309 #else 310 #define MPIU_CHKLMEM_DECL(n_) \ 311 void *(mpiu_chklmem_stk_[n_]) = {0};\ 312 int mpiu_chklmem_stk_sp_=0;\ 313 MPIU_AssertDeclValue(const int mpiu_chklmem_stk_sz_,n_) 314 315 #define MPIU_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 316 {pointer_ = (type_)MPIU_Malloc(nbytes_); \ 317 if (pointer_) { \ 318 MPIU_Assert(mpiu_chklmem_stk_sp_<mpiu_chklmem_stk_sz_);\ 319 mpiu_chklmem_stk_[mpiu_chklmem_stk_sp_++] = pointer_;\ 320 } else if (nbytes_ > 0) { \ 321 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 322 stmt_;\ 323 }} 324 #define MPIU_CHKLMEM_FREEALL() \ 325 do { while (mpiu_chklmem_stk_sp_ > 0) {\ 326 MPIU_Free( mpiu_chklmem_stk_[--mpiu_chklmem_stk_sp_] ); } } while(0) 327 #endif /* HAVE_ALLOCA */ 328 #define MPIU_CHKLMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_) \ 329 MPIU_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) 330 #define MPIU_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) \ 331 MPIU_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,goto fn_fail) 332 333 /* In some cases, we need to allocate large amounts of memory. This can 334 be a problem if alloca is used, as the available stack space may be small. 335 This is the same approach for the temporary memory as is used when alloca 336 is not available. */ 337 #define MPIU_CHKLBIGMEM_DECL(n_) \ 338 void *(mpiu_chklbigmem_stk_[n_]);\ 339 int mpiu_chklbigmem_stk_sp_=0;\ 340 MPIU_AssertDeclValue(const int mpiu_chklbigmem_stk_sz_,n_) 341 342 #define MPIU_CHKLBIGMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 343 {pointer_ = (type_)MPIU_Malloc(nbytes_); \ 344 if (pointer_) { \ 345 MPIU_Assert(mpiu_chklbigmem_stk_sp_<mpiu_chklbigmem_stk_sz_);\ 346 mpiu_chklbigmem_stk_[mpiu_chklbigmem_stk_sp_++] = pointer_;\ 347 } else if (nbytes_ > 0) { \ 348 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 349 stmt_;\ 350 }} 351 #define MPIU_CHKLBIGMEM_FREEALL() \ 352 { while (mpiu_chklbigmem_stk_sp_ > 0) {\ 353 MPIU_Free( mpiu_chklbigmem_stk_[--mpiu_chklbigmem_stk_sp_] ); } } 354 355 #define MPIU_CHKLBIGMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_) \ 356 MPIU_CHKLBIGMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) 357 #define MPIU_CHKLBIGMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) \ 358 MPIU_CHKLBIGMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,goto fn_fail) 359 360 /* Persistent memory that we may want to recover if something goes wrong */ 361 #define MPIU_CHKPMEM_DECL(n_) \ 362 void *(mpiu_chkpmem_stk_[n_]);\ 363 int mpiu_chkpmem_stk_sp_=0;\ 364 MPIU_AssertDeclValue(const int mpiu_chkpmem_stk_sz_,n_) 365 #define MPIU_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 366 {pointer_ = (type_)MPIU_Malloc(nbytes_); \ 367 if (pointer_) { \ 368 MPIU_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_);\ 369 mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;\ 370 } else if (nbytes_ > 0) { \ 371 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 372 stmt_;\ 373 }} 374 #define MPIU_CHKPMEM_REGISTER(pointer_) \ 375 {MPIU_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_);\ 376 mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;} 377 #define MPIU_CHKPMEM_REAP() \ 378 { while (mpiu_chkpmem_stk_sp_ > 0) {\ 379 MPIU_Free( mpiu_chkpmem_stk_[--mpiu_chkpmem_stk_sp_] ); } } 380 #define MPIU_CHKPMEM_COMMIT() \ 381 mpiu_chkpmem_stk_sp_ = 0 382 #define MPIU_CHKPMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_) \ 383 MPIU_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) 384 #define MPIU_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) \ 385 MPIU_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,goto fn_fail) 386 387 /* now the CALLOC version for zeroed memory */ 388 #define MPIU_CHKPMEM_CALLOC(pointer_,type_,nbytes_,rc_,name_) \ 389 MPIU_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) 390 #define MPIU_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_) \ 391 MPIU_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,goto fn_fail) 392 #define MPIU_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 393 do { \ 394 pointer_ = (type_)MPIU_Calloc(1, (nbytes_)); \ 395 if (pointer_) { \ 396 MPIU_Assert(mpiu_chkpmem_stk_sp_<mpiu_chkpmem_stk_sz_); \ 397 mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_; \ 398 } \ 399 else if (nbytes_ > 0) { \ 400 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 401 stmt_; \ 402 } \ 403 } while (0) 404 405 /* A special version for routines that only allocate one item */ 406 #define MPIU_CHKPMEM_MALLOC1(pointer_,type_,nbytes_,rc_,name_,stmt_) \ 407 {pointer_ = (type_)MPIU_Malloc(nbytes_); \ 408 if (!(pointer_) && (nbytes_ > 0)) { \ 409 MPIU_CHKMEM_SETERR(rc_,nbytes_,name_); \ 410 stmt_;\ 411 }} 412 413 /* Provides a easy way to use realloc safely and avoid the temptation to use 414 * realloc unsafely (direct ptr assignment). Zero-size reallocs returning NULL 415 * are handled and are not considered an error. */ 416 #define MPIU_REALLOC_OR_FREE_AND_JUMP(ptr_,size_,rc_) do { \ 417 void *realloc_tmp_ = MPIU_Realloc((ptr_), (size_)); \ 418 if ((size_) && !realloc_tmp_) { \ 419 MPIU_Free(ptr_); \ 420 MPIU_ERR_SETANDJUMP2(rc_,MPIU_CHKMEM_ISFATAL,"**nomem2","**nomem2 %d %s",(size_),MPIU_QUOTE(ptr_)); \ 421 } \ 422 (ptr_) = realloc_tmp_; \ 423 } while (0) 424 /* this version does not free ptr_ */ 425 #define MPIU_REALLOC_ORJUMP(ptr_,size_,rc_) do { \ 426 void *realloc_tmp_ = MPIU_Realloc((ptr_), (size_)); \ 427 if (size_) \ 428 MPIU_ERR_CHKANDJUMP2(!realloc_tmp_,rc_,MPIU_CHKMEM_ISFATAL,"**nomem2","**nomem2 %d %s",(size_),MPIU_QUOTE(ptr_)); \ 429 (ptr_) = realloc_tmp_; \ 430 } while (0) 431 432 /* Define attribute as empty if it has no definition */ 433 #ifndef ATTRIBUTE 434 #define ATTRIBUTE(a) 435 #endif 436 437 #if defined(HAVE_STRNCASECMP) 438 # define MPIU_Strncasecmp strncasecmp 439 #elif defined(HAVE_STRNICMP) 440 # define MPIU_Strncasecmp strnicmp 441 #else 442 /* FIXME: Provide a fallback function ? */ 443 # error "No function defined for case-insensitive strncmp" 444 #endif 445 446 #define MPIU_Snprintf MPL_snprintf 447 448 /* MPIU_Basename(path, basename) 449 This function finds the basename in a path (ala "man 1 basename"). 450 *basename will point to an element in path. 451 More formally: This function sets basename to the character just after the last '/' in path. 452 */ 453 void MPIU_Basename(char *path, char **basename); 454 455 /* Evaluates to a boolean expression, true if the given byte ranges overlap, 456 * false otherwise. That is, true iff [a_,a_+a_len_) overlaps with [b_,b_+b_len_) */ 457 #define MPIU_MEM_RANGES_OVERLAP(a_,a_len_,b_,b_len_) \ 458 ( ((char *)(a_) >= (char *)(b_) && ((char *)(a_) < ((char *)(b_) + (b_len_)))) || \ 459 ((char *)(b_) >= (char *)(a_) && ((char *)(b_) < ((char *)(a_) + (a_len_)))) ) 460 #if (!defined(NDEBUG) && defined(HAVE_ERROR_CHECKING)) 461 462 #ifndef TRUE 463 #define TRUE 1 464 #endif 465 #ifndef FALSE 466 #define FALSE 0 467 #endif 468 469 /* May be used to perform sanity and range checking on memcpy and mempcy-like 470 function calls. This macro will bail out much like an MPIU_Assert if any of 471 the checks fail. */ 472 #define MPIU_MEM_CHECK_MEMCPY(dst_,src_,len_) \ 473 do { \ 474 if (len_) { \ 475 MPIU_Assert((dst_) != NULL); \ 476 MPIU_Assert((src_) != NULL); \ 477 MPL_VG_CHECK_MEM_IS_ADDRESSABLE((dst_),(len_)); \ 478 MPL_VG_CHECK_MEM_IS_ADDRESSABLE((src_),(len_)); \ 479 if (MPIU_MEM_RANGES_OVERLAP((dst_),(len_),(src_),(len_))) { \ 480 MPIU_Assert_fmt_msg(FALSE,("memcpy argument memory ranges overlap, dst_=%p src_=%p len_=%ld\n", \ 481 (dst_), (src_), (long)(len_))); \ 482 } \ 483 } \ 484 } while (0) 485 #else 486 #define MPIU_MEM_CHECK_MEMCPY(dst_,src_,len_) do {} while(0) 487 #endif 488 489 /* valgrind macros are now provided by MPL (via mpl.h included in mpiimpl.h) */ 490 491 /* ------------------------------------------------------------------------- */ 492 /* end of mpimem.h */ 493 /* ------------------------------------------------------------------------- */ 494 495 #if defined(__cplusplus) 496 } 497 #endif 498 #endif 499