Blame src/include/mpir_mem.h

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#ifndef MPIR_MEM_H_INCLUDED
Packit Service c5cf8c
#define MPIR_MEM_H_INCLUDED
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpichconf.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* Make sure that we have the definitions for the malloc routines and size_t */
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
/* strdup is often declared in string.h, so if we plan to redefine strdup,
Packit Service c5cf8c
   we need to include string first.  That is done below, only in the
Packit Service c5cf8c
   case where we redefine strdup */
Packit Service c5cf8c
Packit Service c5cf8c
#if defined(__cplusplus)
Packit Service c5cf8c
extern "C" {
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpl.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* Define attribute as empty if it has no definition */
Packit Service c5cf8c
#ifndef ATTRIBUTE
Packit Service c5cf8c
#define ATTRIBUTE(a)
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
#if defined (MPL_USE_DBG_LOGGING)
Packit Service c5cf8c
    extern MPL_dbg_class MPIR_DBG_STRING;
Packit Service c5cf8c
#endif                          /* MPL_USE_DBG_LOGGING */
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/* mpir_mem.h */
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/* Memory allocation */
Packit Service c5cf8c
/* style: allow:malloc:2 sig:0 */
Packit Service c5cf8c
/* style: allow:free:2 sig:0 */
Packit Service c5cf8c
/* style: allow:strdup:2 sig:0 */
Packit Service c5cf8c
/* style: allow:calloc:2 sig:0 */
Packit Service c5cf8c
/* style: allow:realloc:1 sig:0 */
Packit Service c5cf8c
/* style: allow:alloca:1 sig:0 */
Packit Service c5cf8c
/* style: define:__strdup:1 sig:0 */
Packit Service c5cf8c
/* style: define:strdup:1 sig:0 */
Packit Service c5cf8c
    /* style: allow:fprintf:5 sig:0 *//* For handle debugging ONLY */
Packit Service c5cf8c
/* style: allow:snprintf:1 sig:0 */
Packit Service c5cf8c
Packit Service c5cf8c
/*D
Packit Service c5cf8c
  Memory - Memory Management Routines
Packit Service c5cf8c
Packit Service c5cf8c
  Rules for memory management:
Packit Service c5cf8c
Packit Service c5cf8c
  MPICH explicity prohibits the appearence of 'malloc', 'free',
Packit Service c5cf8c
  'calloc', 'realloc', or 'strdup' in any code implementing a device or
Packit Service c5cf8c
  MPI call (of course, users may use any of these calls in their code).
Packit Service c5cf8c
  Instead, you must use 'MPL_malloc' etc.; if these are defined
Packit Service c5cf8c
  as 'malloc', that is allowed, but an explicit use of 'malloc' instead of
Packit Service c5cf8c
  'MPL_malloc' in the source code is not allowed.  This restriction is
Packit Service c5cf8c
  made to simplify the use of portable tools to test for memory leaks,
Packit Service c5cf8c
  overwrites, and other consistency checks.
Packit Service c5cf8c
Packit Service c5cf8c
  Most memory should be allocated at the time that 'MPID_Init' is
Packit Service c5cf8c
  called and released with 'MPID_Finalize' is called.  If at all possible,
Packit Service c5cf8c
  no other routine should fail because memory could not be allocated
Packit Service c5cf8c
  (for example, because the user has allocated large arrays after 'MPI_Init').
Packit Service c5cf8c
Packit Service c5cf8c
  The implementation of the MPI routines will strive to avoid memory allocation
Packit Service c5cf8c
  as well; however, operations such as 'MPI_Type_index' that create a new
Packit Service c5cf8c
  data type that reflects data that must be copied from an array of arbitrary
Packit Service c5cf8c
  size will have to allocate memory (and can fail; note that there is an
Packit Service c5cf8c
  MPI error class for out-of-memory).
Packit Service c5cf8c
Packit Service c5cf8c
  Question:
Packit Service c5cf8c
  Do we want to have an aligned allocation routine?  E.g., one that
Packit Service c5cf8c
  aligns memory on a cache-line.
Packit Service c5cf8c
  D*/
Packit Service c5cf8c
Packit Service c5cf8c
/* Define the string copy and duplication functions */
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
Packit Service c5cf8c
#define MPIR_Memcpy(dst, src, len)              \
Packit Service c5cf8c
    do {                                        \
Packit Service c5cf8c
        CHECK_MEMCPY((dst),(src),(len));        \
Packit Service c5cf8c
        memcpy((dst), (src), (len));            \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef USE_MEMORY_TRACING
Packit Service c5cf8c
Packit Service c5cf8c
/* Define these as invalid C to catch their use in the code */
Packit Service c5cf8c
#define malloc(a)         'Error use MPL_malloc' :::
Packit Service c5cf8c
#define calloc(a,b)       'Error use MPL_calloc' :::
Packit Service c5cf8c
#define free(a)           'Error use MPL_free'   :::
Packit Service c5cf8c
#define realloc(a)        'Error use MPL_realloc' :::
Packit Service c5cf8c
/* These two functions can't be guarded because we use #include <sys/mman.h>
Packit Service c5cf8c
 * throughout the code to be able to use other symbols in that header file.
Packit Service c5cf8c
 * Because we include that header directly, we bypass this guard and cause
Packit Service c5cf8c
 * compile problems.
Packit Service c5cf8c
 * #define mmap(a,b,c,d,e,f) 'Error use MPL_mmap'   :::
Packit Service c5cf8c
 * #define munmap(a,b)       'Error use MPL_munmap' :::
Packit Service c5cf8c
 */
Packit Service c5cf8c
#if defined(strdup) || defined(__strdup)
Packit Service c5cf8c
#undef strdup
Packit Service c5cf8c
#endif                          /* defined(strdup) || defined(__strdup) */
Packit Service c5cf8c
    /* The ::: should cause the compiler to choke; the string
Packit Service c5cf8c
     * will give the explanation */
Packit Service c5cf8c
#undef strdup                   /* in case strdup is a macro */
Packit Service c5cf8c
#define strdup(a)         'Error use MPL_strdup' :::
Packit Service c5cf8c
Packit Service c5cf8c
#endif                          /* USE_MEMORY_TRACING */
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/* Memory allocation macros. See document. */
Packit Service c5cf8c
Packit Service c5cf8c
/* Standard macro for generating error codes.  We set the error to be
Packit Service c5cf8c
 * recoverable by default, but this can be changed. */
Packit Service c5cf8c
#ifdef HAVE_ERROR_CHECKING
Packit Service c5cf8c
#define MPIR_CHKMEM_SETERR(rc_,nbytes_,name_)                           \
Packit Service c5cf8c
    rc_=MPIR_Err_create_code(MPI_SUCCESS,                               \
Packit Service c5cf8c
                             MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,    \
Packit Service c5cf8c
                             MPI_ERR_OTHER, "**nomem2", "**nomem2 %d %s", nbytes_, name_)
Packit Service c5cf8c
#else                           /* HAVE_ERROR_CHECKING */
Packit Service c5cf8c
#define MPIR_CHKMEM_SETERR(rc_,nbytes_,name_) rc_=MPI_ERR_OTHER
Packit Service c5cf8c
#endif                          /* HAVE_ERROR_CHECKING */
Packit Service c5cf8c
Packit Service c5cf8c
    /* CHKPMEM_REGISTER is used for memory allocated within another routine */
Packit Service c5cf8c
Packit Service c5cf8c
/* Memory used and freed within the current scope (alloca if feasible) */
Packit Service c5cf8c
/* Configure with --enable-alloca to set USE_ALLOCA */
Packit Service c5cf8c
#if defined(HAVE_ALLOCA) && defined(USE_ALLOCA)
Packit Service c5cf8c
#ifdef HAVE_ALLOCA_H
Packit Service c5cf8c
#include <alloca.h>
Packit Service c5cf8c
#endif                          /* HAVE_ALLOCA_H */
Packit Service c5cf8c
/* Define decl with a dummy definition to allow us to put a semi-colon
Packit Service c5cf8c
   after the macro without causing the declaration block to end (restriction
Packit Service c5cf8c
   imposed by C) */
Packit Service c5cf8c
#define MPIR_CHKLMEM_DECL(n_) int dummy_ ATTRIBUTE((unused))
Packit Service c5cf8c
#define MPIR_CHKLMEM_FREEALL()
Packit Service c5cf8c
#define MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        pointer_ = (type_)alloca(nbytes_);                              \
Packit Service c5cf8c
        if (!(pointer_) && (nbytes_ > 0)) {                             \
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
Packit Service c5cf8c
            stmt_;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
#else                           /* defined(HAVE_ALLOCA) && defined(USE_ALLOCA) */
Packit Service c5cf8c
#define MPIR_CHKLMEM_DECL(n_)                                   \
Packit Service c5cf8c
    void *(mpiu_chklmem_stk_[n_]) = { NULL };                   \
Packit Service c5cf8c
    int mpiu_chklmem_stk_sp_=0;                                 \
Packit Service c5cf8c
    MPIR_AssertDeclValue(const int mpiu_chklmem_stk_sz_,n_)
Packit Service c5cf8c
Packit Service c5cf8c
#define MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
Packit Service c5cf8c
        if (pointer_) {                                                 \
Packit Service c5cf8c
            MPIR_Assert(mpiu_chklmem_stk_sp_
Packit Service c5cf8c
            mpiu_chklmem_stk_[mpiu_chklmem_stk_sp_++] = pointer_;       \
Packit Service c5cf8c
        } else if (nbytes_ > 0) {                                       \
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
Packit Service c5cf8c
            stmt_;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
#define MPIR_CHKLMEM_FREEALL()                                          \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        while (mpiu_chklmem_stk_sp_ > 0) {                              \
Packit Service c5cf8c
            MPL_free(mpiu_chklmem_stk_[--mpiu_chklmem_stk_sp_]);        \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#endif                          /* defined(HAVE_ALLOCA) && defined(USE_ALLOCA) */
Packit Service c5cf8c
#define MPIR_CHKLMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
Packit Service c5cf8c
    MPIR_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
Packit Service c5cf8c
#define MPIR_CHKLMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
Packit Service c5cf8c
    MPIR_CHKLMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
Packit Service c5cf8c
Packit Service c5cf8c
/* Persistent memory that we may want to recover if something goes wrong */
Packit Service c5cf8c
#define MPIR_CHKPMEM_DECL(n_)                                   \
Packit Service c5cf8c
    void *(mpiu_chkpmem_stk_[n_]) = { NULL };                   \
Packit Service c5cf8c
    int mpiu_chkpmem_stk_sp_=0;                                 \
Packit Service c5cf8c
    MPIR_AssertDeclValue(const int mpiu_chkpmem_stk_sz_,n_)
Packit Service c5cf8c
#define MPIR_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
Packit Service c5cf8c
        if (pointer_) {                                                 \
Packit Service c5cf8c
            MPIR_Assert(mpiu_chkpmem_stk_sp_
Packit Service c5cf8c
            mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;       \
Packit Service c5cf8c
        } else if (nbytes_ > 0) {                                       \
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
Packit Service c5cf8c
            stmt_;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
#define MPIR_CHKPMEM_REGISTER(pointer_)                         \
Packit Service c5cf8c
    {                                                           \
Packit Service c5cf8c
        MPIR_Assert(mpiu_chkpmem_stk_sp_
Packit Service c5cf8c
        mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;   \
Packit Service c5cf8c
    }
Packit Service c5cf8c
#define MPIR_CHKPMEM_REAP()                                             \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        while (mpiu_chkpmem_stk_sp_ > 0) {                              \
Packit Service c5cf8c
            MPL_free(mpiu_chkpmem_stk_[--mpiu_chkpmem_stk_sp_]);        \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
#define MPIR_CHKPMEM_COMMIT()                   \
Packit Service c5cf8c
    mpiu_chkpmem_stk_sp_ = 0
Packit Service c5cf8c
#define MPIR_CHKPMEM_MALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
Packit Service c5cf8c
#define MPIR_CHKPMEM_MALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
Packit Service c5cf8c
    MPIR_CHKPMEM_MALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
Packit Service c5cf8c
Packit Service c5cf8c
/* now the CALLOC version for zeroed memory */
Packit Service c5cf8c
#define MPIR_CHKPMEM_CALLOC(pointer_,type_,nbytes_,rc_,name_,class_)    \
Packit Service c5cf8c
    MPIR_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_)
Packit Service c5cf8c
#define MPIR_CHKPMEM_CALLOC_ORJUMP(pointer_,type_,nbytes_,rc_,name_,class_) \
Packit Service c5cf8c
    MPIR_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,goto fn_fail)
Packit Service c5cf8c
#define MPIR_CHKPMEM_CALLOC_ORSTMT(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        pointer_ = (type_)MPL_calloc(1, (nbytes_), (class_));           \
Packit Service c5cf8c
        if (pointer_) {                                                 \
Packit Service c5cf8c
            MPIR_Assert(mpiu_chkpmem_stk_sp_
Packit Service c5cf8c
            mpiu_chkpmem_stk_[mpiu_chkpmem_stk_sp_++] = pointer_;       \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
        else if (nbytes_ > 0) {                                         \
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
Packit Service c5cf8c
            stmt_;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
/* A special version for routines that only allocate one item */
Packit Service c5cf8c
#define MPIR_CHKPMEM_MALLOC1(pointer_,type_,nbytes_,rc_,name_,class_,stmt_) \
Packit Service c5cf8c
    {                                                                   \
Packit Service c5cf8c
        pointer_ = (type_)MPL_malloc(nbytes_,class_);                   \
Packit Service c5cf8c
        if (!(pointer_) && (nbytes_ > 0)) {                             \
Packit Service c5cf8c
            MPIR_CHKMEM_SETERR(rc_,nbytes_,name_);                      \
Packit Service c5cf8c
            stmt_;                                                      \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
/* Provides a easy way to use realloc safely and avoid the temptation to use
Packit Service c5cf8c
 * realloc unsafely (direct ptr assignment).  Zero-size reallocs returning NULL
Packit Service c5cf8c
 * are handled and are not considered an error. */
Packit Service c5cf8c
#define MPIR_REALLOC_ORJUMP(ptr_,size_,class_,rc_)                      \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        void *realloc_tmp_ = MPL_realloc((ptr_), (size_), (class_));    \
Packit Service c5cf8c
        if (size_ != 0)                                                 \
Packit Service c5cf8c
            MPIR_ERR_CHKANDJUMP2(!realloc_tmp_,rc_,MPI_ERR_OTHER,"**nomem2","**nomem2 %d %s",(size_),MPL_QUOTE(ptr_)); \
Packit Service c5cf8c
        (ptr_) = realloc_tmp_;                                          \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
#if defined(HAVE_STRNCASECMP)
Packit Service c5cf8c
#define MPIR_Strncasecmp strncasecmp
Packit Service c5cf8c
#elif defined(HAVE_STRNICMP)
Packit Service c5cf8c
#define MPIR_Strncasecmp strnicmp
Packit Service c5cf8c
#else
Packit Service c5cf8c
/* FIXME: Provide a fallback function ? */
Packit Service c5cf8c
#error "No function defined for case-insensitive strncmp"
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Evaluates to a boolean expression, true if the given byte ranges overlap,
Packit Service c5cf8c
 * false otherwise.  That is, true iff [a_,a_+a_len_) overlaps with [b_,b_+b_len_) */
Packit Service c5cf8c
#define MPIR_MEM_RANGES_OVERLAP(a_,a_len_,b_,b_len_)                    \
Packit Service c5cf8c
    (((char *)(a_) >= (char *)(b_) && ((char *)(a_) < ((char *)(b_) + (b_len_)))) || \
Packit Service c5cf8c
     ((char *)(b_) >= (char *)(a_) && ((char *)(b_) < ((char *)(a_) + (a_len_)))))
Packit Service c5cf8c
#if (!defined(NDEBUG) && defined(HAVE_ERROR_CHECKING))
Packit Service c5cf8c
Packit Service c5cf8c
/* May be used to perform sanity and range checking on memcpy and mempcy-like
Packit Service c5cf8c
   function calls.  This macro will bail out much like an MPIR_Assert if any of
Packit Service c5cf8c
   the checks fail. */
Packit Service c5cf8c
#define CHECK_MEMCPY(dst_,src_,len_)                                    \
Packit Service c5cf8c
    do {                                                                \
Packit Service c5cf8c
        if (len_ != 0) {                                                \
Packit Service c5cf8c
            MPL_VG_CHECK_MEM_IS_ADDRESSABLE((dst_),(len_));             \
Packit Service c5cf8c
            MPL_VG_CHECK_MEM_IS_ADDRESSABLE((src_),(len_));             \
Packit Service c5cf8c
            if (MPIR_MEM_RANGES_OVERLAP((dst_),(len_),(src_),(len_))) { \
Packit Service c5cf8c
                MPIR_Assert_fmt_msg(FALSE,("memcpy argument memory ranges overlap, dst_=%p src_=%p len_=%ld\n", \
Packit Service c5cf8c
                                           (dst_), (src_), (long)(len_))); \
Packit Service c5cf8c
            }                                                           \
Packit Service c5cf8c
        }                                                               \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
#else
Packit Service c5cf8c
#define CHECK_MEMCPY(dst_,src_,len_) do {} while (0)
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* valgrind macros are now provided by MPL (via mpl.h included in mpiimpl.h) */
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/* end of mpir_mem.h */
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
Packit Service c5cf8c
#if defined(__cplusplus)
Packit Service c5cf8c
}
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#endif                          /* MPIR_MEM_H_INCLUDED */