Blame src/mpi/attr/attrutil.c

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
 * Portions of this code were written by Microsoft. Those portions are
Packit Service c5cf8c
 * Copyright (c) 2007 Microsoft Corporation. Microsoft grants
Packit Service c5cf8c
 * permission to use, reproduce, prepare derivative works, and to
Packit Service c5cf8c
 * redistribute to others. The code is licensed "as is." The User
Packit Service c5cf8c
 * bears the risk of using it. Microsoft gives no express warranties,
Packit Service c5cf8c
 * guarantees or conditions. To the extent permitted by law, Microsoft
Packit Service c5cf8c
 * excludes the implied warranties of merchantability, fitness for a
Packit Service c5cf8c
 * particular purpose and non-infringement.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
#include "attr.h"
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Keyvals.  These are handled just like the other opaque objects in MPICH
Packit Service c5cf8c
 * The predefined keyvals (and their associated attributes) are handled
Packit Service c5cf8c
 * separately, without using the keyval
Packit Service c5cf8c
 * storage
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
#ifndef MPID_KEYVAL_PREALLOC
Packit Service c5cf8c
#define MPID_KEYVAL_PREALLOC 16
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Preallocated keyval objects */
Packit Service c5cf8c
MPII_Keyval MPII_Keyval_direct[MPID_KEYVAL_PREALLOC] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
MPIR_Object_alloc_t MPII_Keyval_mem = { 0, 0, 0, 0, MPIR_KEYVAL,
Packit Service c5cf8c
    sizeof(MPII_Keyval),
Packit Service c5cf8c
    MPII_Keyval_direct,
Packit Service c5cf8c
    MPID_KEYVAL_PREALLOC,
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
#ifndef MPIR_ATTR_PREALLOC
Packit Service c5cf8c
#define MPIR_ATTR_PREALLOC 32
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* Preallocated keyval objects */
Packit Service c5cf8c
MPIR_Attribute MPID_Attr_direct[MPIR_ATTR_PREALLOC] = { {0}
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
MPIR_Object_alloc_t MPID_Attr_mem = { 0, 0, 0, 0, MPIR_ATTR,
Packit Service c5cf8c
    sizeof(MPIR_Attribute),
Packit Service c5cf8c
    MPID_Attr_direct,
Packit Service c5cf8c
    MPIR_ATTR_PREALLOC,
Packit Service c5cf8c
};
Packit Service c5cf8c
Packit Service c5cf8c
/* Provides a way to trap all attribute allocations when debugging leaks. */
Packit Service c5cf8c
MPIR_Attribute *MPID_Attr_alloc(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Attribute *attr = (MPIR_Attribute *) MPIR_Handle_obj_alloc(&MPID_Attr_mem);
Packit Service c5cf8c
    /* attributes don't have refcount semantics, but let's keep valgrind and
Packit Service c5cf8c
     * the debug logging pacified */
Packit Service c5cf8c
    MPIR_Assert(attr != NULL);
Packit Service c5cf8c
    MPIR_Object_set_ref(attr, 0);
Packit Service c5cf8c
    return attr;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
void MPID_Attr_free(MPIR_Attribute * attr_ptr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Handle_obj_free(&MPID_Attr_mem, attr_ptr);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Call_attr_delete
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/*
Packit Service c5cf8c
  This function deletes a single attribute.
Packit Service c5cf8c
  It is called by both the function to delete a list and attribute set/put
Packit Service c5cf8c
  val.  Return the return code from the delete function; 0 if there is no
Packit Service c5cf8c
  delete function.
Packit Service c5cf8c
Packit Service c5cf8c
  Even though there are separate keyvals for communicators, types, and files,
Packit Service c5cf8c
  we can use the same function because the handle for these is always an int
Packit Service c5cf8c
  in MPICH.
Packit Service c5cf8c
Packit Service c5cf8c
  Note that this simply invokes the attribute delete function.  It does not
Packit Service c5cf8c
  remove the attribute from the list of attributes.
Packit Service c5cf8c
*/
Packit Service c5cf8c
int MPIR_Call_attr_delete(int handle, MPIR_Attribute * attr_p)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    MPII_Keyval *kv = attr_p->keyval;
Packit Service c5cf8c
Packit Service c5cf8c
    if (kv->delfn.user_function == NULL)
Packit Service c5cf8c
        goto fn_exit;
Packit Service c5cf8c
Packit Service c5cf8c
    rc = kv->delfn.proxy(kv->delfn.user_function,
Packit Service c5cf8c
                         handle,
Packit Service c5cf8c
                         attr_p->keyval->handle,
Packit Service c5cf8c
                         attr_p->attrType,
Packit Service c5cf8c
                         (void *) (intptr_t) attr_p->value, attr_p->keyval->extra_state);
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (rc != 0) {
Packit Service c5cf8c
#if MPICH_ERROR_MSG_LEVEL < MPICH_ERROR_MSG__ALL
Packit Service c5cf8c
        /* If rc is a valid error class, then return that.
Packit Service c5cf8c
         * Note that it may be a dynamic error class */
Packit Service c5cf8c
        /* AMBIGUOUS: This is an ambiguity in the MPI standard: What is the
Packit Service c5cf8c
         * error value returned from the user-provided routine?  Particularly
Packit Service c5cf8c
         * with the MPI-2 feature of user-defined error codes, the
Packit Service c5cf8c
         * user expectation is probably that the user-provided error code
Packit Service c5cf8c
         * is returned. */
Packit Service c5cf8c
        mpi_errno = rc;
Packit Service c5cf8c
#else
Packit Service c5cf8c
        mpi_errno =
Packit Service c5cf8c
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
Packit Service c5cf8c
                                 "**user", "**userdel %d", rc);
Packit Service c5cf8c
#endif
Packit Service c5cf8c
        goto fn_fail;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  This function copies a single attribute.
Packit Service c5cf8c
  It is called by the function to copy a list of attribute
Packit Service c5cf8c
  Return the return code from the copy function; MPI_SUCCESS if there is
Packit Service c5cf8c
  no copy function.
Packit Service c5cf8c
Packit Service c5cf8c
  Even though there are separate keyvals for communicators, types, and files,
Packit Service c5cf8c
  we can use the same function because the handle for these is always an int
Packit Service c5cf8c
  in MPICH.
Packit Service c5cf8c
Packit Service c5cf8c
  Note that this simply invokes the attribute copy function.
Packit Service c5cf8c
*/
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Call_attr_copy
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
int MPIR_Call_attr_copy(int handle, MPIR_Attribute * attr_p, void **value_copy, int *flag)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
    MPII_Keyval *kv = attr_p->keyval;
Packit Service c5cf8c
Packit Service c5cf8c
    if (kv->copyfn.user_function == NULL)
Packit Service c5cf8c
        goto fn_exit;
Packit Service c5cf8c
Packit Service c5cf8c
    rc = kv->copyfn.proxy(kv->copyfn.user_function,
Packit Service c5cf8c
                          handle,
Packit Service c5cf8c
                          attr_p->keyval->handle,
Packit Service c5cf8c
                          attr_p->keyval->extra_state,
Packit Service c5cf8c
                          attr_p->attrType, (void *) (intptr_t) attr_p->value, value_copy, flag);
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (rc != 0) {
Packit Service c5cf8c
#if MPICH_ERROR_MSG_LEVEL < MPICH_ERROR_MSG__ALL
Packit Service c5cf8c
        mpi_errno = rc;
Packit Service c5cf8c
#else
Packit Service c5cf8c
        mpi_errno =
Packit Service c5cf8c
            MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__, MPI_ERR_OTHER,
Packit Service c5cf8c
                                 "**user", "**usercopy %d", rc);
Packit Service c5cf8c
#endif
Packit Service c5cf8c
        goto fn_fail;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Attr_dup_list
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/* Routine to duplicate an attribute list */
Packit Service c5cf8c
int MPIR_Attr_dup_list(int handle, MPIR_Attribute * old_attrs, MPIR_Attribute ** new_attr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Attribute *p, *new_p, **next_new_attr_ptr = new_attr;
Packit Service c5cf8c
    void *new_value = NULL;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    for (p = old_attrs; p != NULL; p = p->next) {
Packit Service c5cf8c
        /* call the attribute copy function (if any) */
Packit Service c5cf8c
        int flag = 0;
Packit Service c5cf8c
        mpi_errno = MPIR_Call_attr_copy(handle, p, &new_value, &flag;;
Packit Service c5cf8c
Packit Service c5cf8c
        if (mpi_errno != MPI_SUCCESS)
Packit Service c5cf8c
            goto fn_fail;
Packit Service c5cf8c
Packit Service c5cf8c
        if (!flag)
Packit Service c5cf8c
            continue;
Packit Service c5cf8c
        /* If flag was returned as true, then insert this attribute into the
Packit Service c5cf8c
         * new list (new_attr) */
Packit Service c5cf8c
Packit Service c5cf8c
        /* duplicate the attribute by creating new storage, copying the
Packit Service c5cf8c
         * attribute value, and invoking the copy function */
Packit Service c5cf8c
        new_p = MPID_Attr_alloc();
Packit Service c5cf8c
        /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
        if (!new_p) {
Packit Service c5cf8c
            mpi_errno =
Packit Service c5cf8c
                MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE, FCNAME, __LINE__,
Packit Service c5cf8c
                                     MPI_ERR_OTHER, "**nomem", 0);
Packit Service c5cf8c
            goto fn_fail;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* --END ERROR HANDLING-- */
Packit Service c5cf8c
        if (!*new_attr) {
Packit Service c5cf8c
            *new_attr = new_p;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        *(next_new_attr_ptr) = new_p;
Packit Service c5cf8c
Packit Service c5cf8c
        new_p->keyval = p->keyval;
Packit Service c5cf8c
        /* Remember that we need this keyval */
Packit Service c5cf8c
        MPII_Keyval_add_ref(p->keyval);
Packit Service c5cf8c
Packit Service c5cf8c
        new_p->attrType = p->attrType;
Packit Service c5cf8c
        new_p->pre_sentinal = 0;
Packit Service c5cf8c
        /* FIXME: This is not correct in some cases (size(MPI_Aint)>
Packit Service c5cf8c
         * sizeof(intptr_t)) */
Packit Service c5cf8c
        new_p->value = (MPII_Attr_val_t) (intptr_t) new_value;
Packit Service c5cf8c
        new_p->post_sentinal = 0;
Packit Service c5cf8c
        new_p->next = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        next_new_attr_ptr = &(new_p->next);
Packit Service c5cf8c
    }   /* for(;;) */
Packit Service c5cf8c
Packit Service c5cf8c
  fn_exit:
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
  fn_fail:
Packit Service c5cf8c
    goto fn_exit;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Attr_delete_list
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/* Routine to delete an attribute list */
Packit Service c5cf8c
int MPIR_Attr_delete_list(int handle, MPIR_Attribute ** attr)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPIR_Attribute *p, *new_p;
Packit Service c5cf8c
    int mpi_errno = MPI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    p = *attr;
Packit Service c5cf8c
    while (p) {
Packit Service c5cf8c
        /* delete the attribute by first executing the delete routine, if any,
Packit Service c5cf8c
         * determine the the next attribute, and recover the attributes
Packit Service c5cf8c
         * storage */
Packit Service c5cf8c
        new_p = p->next;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Check the sentinals first */
Packit Service c5cf8c
        /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
        if (p->pre_sentinal != 0 || p->post_sentinal != 0) {
Packit Service c5cf8c
            MPIR_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**attrsentinal");
Packit Service c5cf8c
            /* We could keep trying to free the attributes, but for now
Packit Service c5cf8c
             * we'll just bag it */
Packit Service c5cf8c
            return mpi_errno;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* --END ERROR HANDLING-- */
Packit Service c5cf8c
        /* For this attribute, find the delete function for the
Packit Service c5cf8c
         * corresponding keyval */
Packit Service c5cf8c
        /* Still to do: capture any error returns but continue to
Packit Service c5cf8c
         * process attributes */
Packit Service c5cf8c
        mpi_errno = MPIR_Call_attr_delete(handle, p);
Packit Service c5cf8c
Packit Service c5cf8c
        /* We must also remove the keyval reference.  If the keyval
Packit Service c5cf8c
         * was freed earlier (reducing the refcount), the actual
Packit Service c5cf8c
         * release and free will happen here.  We must free the keyval
Packit Service c5cf8c
         * even if the attr delete failed, as we then remove the
Packit Service c5cf8c
         * attribute.
Packit Service c5cf8c
         */
Packit Service c5cf8c
        {
Packit Service c5cf8c
            int in_use;
Packit Service c5cf8c
            /* Decrement the use of the keyval */
Packit Service c5cf8c
            MPII_Keyval_release_ref(p->keyval, &in_use);
Packit Service c5cf8c
            if (!in_use) {
Packit Service c5cf8c
                MPIR_Handle_obj_free(&MPII_Keyval_mem, p->keyval);
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        MPIR_Handle_obj_free(&MPID_Attr_mem, p);
Packit Service c5cf8c
Packit Service c5cf8c
        p = new_p;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* We must zero out the attribute list pointer or we could attempt to use it
Packit Service c5cf8c
     * later.  This normally can't happen because the communicator usually
Packit Service c5cf8c
     * disappears after a call to MPI_Comm_free.  But if the attribute keyval
Packit Service c5cf8c
     * has an associated delete function that returns an error then we don't
Packit Service c5cf8c
     * actually free the communicator despite having freed all the attributes
Packit Service c5cf8c
     * associated with the communicator.
Packit Service c5cf8c
     *
Packit Service c5cf8c
     * This function is also used for Win and Type objects, but the idea is the
Packit Service c5cf8c
     * same in those cases as well. */
Packit Service c5cf8c
    *attr = NULL;
Packit Service c5cf8c
    return mpi_errno;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int
Packit Service c5cf8c
MPII_Attr_copy_c_proxy(MPI_Comm_copy_attr_function * user_function,
Packit Service c5cf8c
                       int handle,
Packit Service c5cf8c
                       int keyval,
Packit Service c5cf8c
                       void *extra_state,
Packit Service c5cf8c
                       MPIR_Attr_type attrib_type, void *attrib, void **attrib_copy, int *flag)
Packit Service c5cf8c
{
Packit Service c5cf8c
    void *attrib_val = NULL;
Packit Service c5cf8c
    int ret;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Make sure that the attribute value is delieverd as a pointer */
Packit Service c5cf8c
    if (MPII_ATTR_KIND(attrib_type) == MPII_ATTR_KIND(MPIR_ATTR_INT)) {
Packit Service c5cf8c
        attrib_val = &attrib;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        attrib_val = attrib;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* user functions might call other MPI functions, so we need to
Packit Service c5cf8c
     * release the lock here. This is safe to do as GLOBAL is not at
Packit Service c5cf8c
     * all recursive in our implementation. */
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    ret = user_function(handle, keyval, extra_state, attrib_val, attrib_copy, flag);
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
Packit Service c5cf8c
    return ret;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
int
Packit Service c5cf8c
MPII_Attr_delete_c_proxy(MPI_Comm_delete_attr_function * user_function,
Packit Service c5cf8c
                         int handle,
Packit Service c5cf8c
                         int keyval, MPIR_Attr_type attrib_type, void *attrib, void *extra_state)
Packit Service c5cf8c
{
Packit Service c5cf8c
    void *attrib_val = NULL;
Packit Service c5cf8c
    int ret;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Make sure that the attribute value is delieverd as a pointer */
Packit Service c5cf8c
    if (MPII_ATTR_KIND(attrib_type) == MPII_ATTR_KIND(MPIR_ATTR_INT))
Packit Service c5cf8c
        attrib_val = &attrib;
Packit Service c5cf8c
    else
Packit Service c5cf8c
        attrib_val = attrib;
Packit Service c5cf8c
Packit Service c5cf8c
    /* user functions might call other MPI functions, so we need to
Packit Service c5cf8c
     * release the lock here. This is safe to do as GLOBAL is not at
Packit Service c5cf8c
     * all recursive in our implementation. */
Packit Service c5cf8c
    MPID_THREAD_CS_EXIT(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
    ret = user_function(handle, keyval, attrib_val, extra_state);
Packit Service c5cf8c
    MPID_THREAD_CS_ENTER(GLOBAL, MPIR_THREAD_GLOBAL_ALLFUNC_MUTEX);
Packit Service c5cf8c
Packit Service c5cf8c
    return ret;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* FIXME: Missing routine description */
Packit Service c5cf8c
void
Packit Service c5cf8c
MPII_Keyval_set_proxy(int keyval,
Packit Service c5cf8c
                      MPII_Attr_copy_proxy copy_proxy, MPII_Attr_delete_proxy delete_proxy)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPII_Keyval *keyval_ptr;
Packit Service c5cf8c
    MPII_Keyval_get_ptr(keyval, keyval_ptr);
Packit Service c5cf8c
    if (keyval_ptr == NULL)
Packit Service c5cf8c
        return;
Packit Service c5cf8c
Packit Service c5cf8c
    keyval_ptr->copyfn.proxy = copy_proxy;
Packit Service c5cf8c
    keyval_ptr->delfn.proxy = delete_proxy;
Packit Service c5cf8c
}