Blame src/mpi/errhan/dynerrutil.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
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
Packit Service c5cf8c
#include "mpiimpl.h"
Packit Service c5cf8c
#include "errcodes.h"
Packit Service c5cf8c
Packit Service c5cf8c
#include <string.h>
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * This file contains the routines needed to implement the MPI routines that
Packit Service c5cf8c
 * can add error classes and codes during runtime.  This file is organized
Packit Service c5cf8c
 * so that applications that do not use the MPI-2 routines to create new
Packit Service c5cf8c
 * error codes will not load any of this code.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * ROMIO has been customized to provide error messages with the same tools
Packit Service c5cf8c
 * as the rest of MPICH and will not rely on the dynamically assigned
Packit Service c5cf8c
 * error classes.  This leaves all of the classes and codes for the user.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Because we have customized ROMIO, we do not need to implement
Packit Service c5cf8c
 * instance-specific messages for the dynamic error codes.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/* Local data structures.
Packit Service c5cf8c
   A message may be associated with each class and code.
Packit Service c5cf8c
   Since we limit the number of user-defined classes and code (no more
Packit Service c5cf8c
   than 256 of each), we allocate an array of pointers to the messages here.
Packit Service c5cf8c
Packit Service c5cf8c
   We *could* allow 256 codes with each class.  However, we don't expect
Packit Service c5cf8c
   any need for this many codes, so we simply allow 256 (actually
Packit Service c5cf8c
   ERROR_MAX_NCODE) codes, and distribute these among the error codes.
Packit Service c5cf8c
Packit Service c5cf8c
   A user-defined error code has the following format.  The ERROR_xxx
Packit Service c5cf8c
   is the macro that may be used to extract the data (usually a MASK and
Packit Service c5cf8c
   a (right)shift)
Packit Service c5cf8c
Packit Service c5cf8c
   [0-6] Class (same as predefined error classes);  ERROR_CLASS_MASK
Packit Service c5cf8c
   [7]   Is dynamic; ERROR_DYN_MASK and ERROR_DYN_SHIFT
Packit Service c5cf8c
   [8-18] Code index (for messages); ERROR_GENERIC_MASK and ERROR_GENERIC_SHIFT
Packit Service c5cf8c
   [19-31] Zero (unused but defined as zero)
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
static int not_initialized = 1; /* This allows us to use atomic decr */
Packit Service c5cf8c
static const char *(user_class_msgs[ERROR_MAX_NCLASS]) = {
Packit Service c5cf8c
0};
Packit Service c5cf8c
Packit Service c5cf8c
static const char *(user_code_msgs[ERROR_MAX_NCODE]) = {
Packit Service c5cf8c
0};
Packit Service c5cf8c
Packit Service c5cf8c
static int first_free_class = 1;        /* class 0 is reserved */
Packit Service c5cf8c
static int first_free_code = 1; /* code 0 is reserved */
Packit Service c5cf8c
static const char empty_error_string[1] = { 0 };
Packit Service c5cf8c
Packit Service c5cf8c
/* Forward reference */
Packit Service c5cf8c
static const char *get_dynerr_string(int code);
Packit Service c5cf8c
Packit Service c5cf8c
/* This external allows this package to define the routine that converts
Packit Service c5cf8c
   dynamically assigned codes and classes to their corresponding strings.
Packit Service c5cf8c
   A cleaner implementation could replace this exposed global with a method
Packit Service c5cf8c
   defined in the error_string.c file that allowed this package to set
Packit Service c5cf8c
   the routine. */
Packit Service c5cf8c
Packit Service c5cf8c
static int MPIR_Dynerrcodes_finalize(void *);
Packit Service c5cf8c
Packit Service c5cf8c
/* Local routine to initialize the data structures for the dynamic
Packit Service c5cf8c
   error classes and codes.
Packit Service c5cf8c
Packit Service c5cf8c
   MPIR_Init_err_dyncodes is called if not_initialized is true.
Packit Service c5cf8c
   Because all of the routines in this file are called by the
Packit Service c5cf8c
   MPI_Add_error_xxx routines, and those routines use the SINGLE_CS
Packit Service c5cf8c
   when the implementation is multithreaded, these routines (until
Packit Service c5cf8c
   we implement finer-grain thread-synchronization) need not worry about
Packit Service c5cf8c
   multiple threads
Packit Service c5cf8c
 */
Packit Service c5cf8c
static void MPIR_Init_err_dyncodes(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: Does this need a thread-safe init? */
Packit Service c5cf8c
    not_initialized = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    for (i = 0; i < ERROR_MAX_NCLASS; i++) {
Packit Service c5cf8c
        user_class_msgs[i] = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    for (i = 0; i < ERROR_MAX_NCODE; i++) {
Packit Service c5cf8c
        user_code_msgs[i] = 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* Set the routine to provides access to the dynamically created
Packit Service c5cf8c
     * error strings */
Packit Service c5cf8c
    MPIR_Process.errcode_to_string = get_dynerr_string;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Add a finalize handler to free any allocated space */
Packit Service c5cf8c
    MPIR_Add_finalize(MPIR_Dynerrcodes_finalize, (void *) 0, 9);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#undef FUNCNAME
Packit Service c5cf8c
#define FUNCNAME MPIR_Err_set_msg
Packit Service c5cf8c
#undef FCNAME
Packit Service c5cf8c
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit Service c5cf8c
/*
Packit Service c5cf8c
  MPIR_Err_set_msg - Change the message for an error code or class
Packit Service c5cf8c
Packit Service c5cf8c
Input Parameters:
Packit Service c5cf8c
+ code - Error code or class
Packit Service c5cf8c
- msg  - New message to use
Packit Service c5cf8c
Packit Service c5cf8c
  Notes:
Packit Service c5cf8c
  This routine is needed to implement 'MPI_Add_error_string'.
Packit Service c5cf8c
*/
Packit Service c5cf8c
int MPIR_Err_set_msg(int code, const char *msg_string)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int errcode, errclass;
Packit Service c5cf8c
    size_t msg_len;
Packit Service c5cf8c
    char *str;
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (not_initialized) {
Packit Service c5cf8c
        /* Just to keep the rest of the code more robust, we'll
Packit Service c5cf8c
         * initialize the dynamic error codes *anyway*, but this is
Packit Service c5cf8c
         * an error (see MPI_Add_error_string in the standard) */
Packit Service c5cf8c
        MPIR_Init_err_dyncodes();
Packit Service c5cf8c
        return MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                    "MPIR_Err_set_msg", __LINE__,
Packit Service c5cf8c
                                    MPI_ERR_ARG, "**argerrcode", "**argerrcode %d", code);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Error strings are attached to a particular error code, not class.
Packit Service c5cf8c
     * As a special case, if the code is 0, we use the class message */
Packit Service c5cf8c
    errclass = code & ERROR_CLASS_MASK;
Packit Service c5cf8c
    errcode = (code & ERROR_GENERIC_MASK) >> ERROR_GENERIC_SHIFT;
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (code & ~(ERROR_CLASS_MASK | ERROR_DYN_MASK | ERROR_GENERIC_MASK)) {
Packit Service c5cf8c
        /* Check for invalid error code */
Packit Service c5cf8c
        return MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                    FCNAME, __LINE__,
Packit Service c5cf8c
                                    MPI_ERR_ARG, "**argerrcode", "**argerrcode %d", code);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
    /* --------------------------------------------------------------------- */
Packit Service c5cf8c
    msg_len = strlen(msg_string);
Packit Service c5cf8c
    str = (char *) MPL_malloc(msg_len + 1, MPL_MEM_BUFFER);
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (!str) {
Packit Service c5cf8c
        return MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_RECOVERABLE,
Packit Service c5cf8c
                                    FCNAME, __LINE__, MPI_ERR_OTHER,
Packit Service c5cf8c
                                    "**nomem", "**nomem %s %d", "error message string", msg_len);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
    /* --------------------------------------------------------------------- */
Packit Service c5cf8c
    MPL_strncpy(str, msg_string, msg_len + 1);
Packit Service c5cf8c
    if (errcode) {
Packit Service c5cf8c
        if (errcode < first_free_code) {
Packit Service c5cf8c
            if (user_code_msgs[errcode]) {
Packit Service c5cf8c
                MPL_free((void *) (user_code_msgs[errcode]));
Packit Service c5cf8c
            }
Packit Service c5cf8c
            user_code_msgs[errcode] = (const char *) str;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            /* FIXME : Unallocated error code? */
Packit Service c5cf8c
            MPL_free(str);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        if (errclass < first_free_class) {
Packit Service c5cf8c
            if (user_class_msgs[errclass]) {
Packit Service c5cf8c
                MPL_free((void *) (user_class_msgs[errclass]));
Packit Service c5cf8c
            }
Packit Service c5cf8c
            user_class_msgs[errclass] = (const char *) str;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            /* FIXME : Unallocated error code? */
Packit Service c5cf8c
            MPL_free(str);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return MPI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  MPIR_Err_add_class - Creata a new error class
Packit Service c5cf8c
Packit Service c5cf8c
  Return value:
Packit Service c5cf8c
  An error class.  Returns -1 if no more classes are available.
Packit Service c5cf8c
Packit Service c5cf8c
  Notes:
Packit Service c5cf8c
  This is used to implement 'MPI_Add_error_class'; it may also be used by a
Packit Service c5cf8c
  device to add device-specific error classes.
Packit Service c5cf8c
Packit Service c5cf8c
  Predefined classes are handled directly; this routine is not used to
Packit Service c5cf8c
  initialize the predefined MPI error classes.  This is done to reduce the
Packit Service c5cf8c
  number of steps that must be executed when starting an MPI program.
Packit Service c5cf8c
Packit Service c5cf8c
  This routine should be run within a SINGLE_CS in the multithreaded case.
Packit Service c5cf8c
*/
Packit Service c5cf8c
int MPIR_Err_add_class(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int new_class;
Packit Service c5cf8c
Packit Service c5cf8c
    if (not_initialized)
Packit Service c5cf8c
        MPIR_Init_err_dyncodes();
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get new class */
Packit Service c5cf8c
    new_class = first_free_class;
Packit Service c5cf8c
    ++first_free_class;
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (new_class >= ERROR_MAX_NCLASS) {
Packit Service c5cf8c
        /* Fail if out of classes */
Packit Service c5cf8c
        return -1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Note that the MPI interface always adds an error class without
Packit Service c5cf8c
     * a string.  */
Packit Service c5cf8c
    user_class_msgs[new_class] = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    return (new_class | ERROR_DYN_MASK);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  MPIR_Err_add_code - Create a new error code that is associated with an
Packit Service c5cf8c
  existing error class
Packit Service c5cf8c
Packit Service c5cf8c
Input Parameters:
Packit Service c5cf8c
. class - Error class to which the code belongs.
Packit Service c5cf8c
Packit Service c5cf8c
  Return value:
Packit Service c5cf8c
  An error code.
Packit Service c5cf8c
Packit Service c5cf8c
  Notes:
Packit Service c5cf8c
  This is used to implement 'MPI_Add_error_code'; it may also be used by a
Packit Service c5cf8c
  device to add device-specific error codes.
Packit Service c5cf8c
Packit Service c5cf8c
  */
Packit Service c5cf8c
int MPIR_Err_add_code(int class)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int new_code;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Note that we can add codes to existing classes, so we may
Packit Service c5cf8c
     * need to initialize the dynamic error routines in this function */
Packit Service c5cf8c
    if (not_initialized)
Packit Service c5cf8c
        MPIR_Init_err_dyncodes();
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get the new code */
Packit Service c5cf8c
    new_code = first_free_code;
Packit Service c5cf8c
    ++first_free_code;
Packit Service c5cf8c
Packit Service c5cf8c
    /* --BEGIN ERROR HANDLING-- */
Packit Service c5cf8c
    if (new_code >= ERROR_MAX_NCODE) {
Packit Service c5cf8c
        /* Fail if out of codes */
Packit Service c5cf8c
        return -1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* --END ERROR HANDLING-- */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Create the full error code */
Packit Service c5cf8c
    new_code = class | (new_code << ERROR_GENERIC_SHIFT);
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: For robustness, we should make sure that the associated string
Packit Service c5cf8c
     * is initialized to null */
Packit Service c5cf8c
    return new_code;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
  get_dynerr_string - Get the message string that corresponds to a
Packit Service c5cf8c
  dynamically created error class or code
Packit Service c5cf8c
Packit Service c5cf8c
Input Parameters:
Packit Service c5cf8c
+ code - An error class or code.  If a code, it must have been created by
Packit Service c5cf8c
  'MPIR_Err_create_code'.
Packit Service c5cf8c
Packit Service c5cf8c
  Return value:
Packit Service c5cf8c
  A pointer to a null-terminated text string with the corresponding error
Packit Service c5cf8c
  message.  A null return indicates an error; usually the value of 'code' is
Packit Service c5cf8c
  neither a valid error class or code.
Packit Service c5cf8c
Packit Service c5cf8c
  Notes:
Packit Service c5cf8c
  This routine is used to implement 'MPI_ERROR_STRING'.  It is only called
Packit Service c5cf8c
  for dynamic error codes.
Packit Service c5cf8c
  */
Packit Service c5cf8c
static const char *get_dynerr_string(int code)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int errcode, errclass;
Packit Service c5cf8c
    const char *errstr = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Error strings are attached to a particular error code, not class.
Packit Service c5cf8c
     * As a special case, if the code is 0, we use the class message */
Packit Service c5cf8c
    errclass = code & ERROR_CLASS_MASK;
Packit Service c5cf8c
    errcode = (code & ERROR_GENERIC_MASK) >> ERROR_GENERIC_SHIFT;
Packit Service c5cf8c
Packit Service c5cf8c
    if (code & ~(ERROR_CLASS_MASK | ERROR_DYN_MASK | ERROR_GENERIC_MASK)) {
Packit Service c5cf8c
        /* Check for invalid error code */
Packit Service c5cf8c
        return 0;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (errcode) {
Packit Service c5cf8c
        if (errcode < first_free_code) {
Packit Service c5cf8c
            errstr = user_code_msgs[errcode];
Packit Service c5cf8c
            if (!errstr)
Packit Service c5cf8c
                errstr = empty_error_string;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        if (errclass < first_free_class) {
Packit Service c5cf8c
            errstr = user_class_msgs[errclass];
Packit Service c5cf8c
            if (!errstr)
Packit Service c5cf8c
                errstr = empty_error_string;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return errstr;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
static int MPIR_Dynerrcodes_finalize(void *p ATTRIBUTE((unused)))
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i;
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_UNREFERENCED_ARG(p);
Packit Service c5cf8c
Packit Service c5cf8c
    if (not_initialized == 0) {
Packit Service c5cf8c
Packit Service c5cf8c
        for (i = 0; i < first_free_class; i++) {
Packit Service c5cf8c
            if (user_class_msgs[i])
Packit Service c5cf8c
                MPL_free((char *) user_class_msgs[i]);
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        for (i = 0; i < first_free_code; i++) {
Packit Service c5cf8c
            if (user_code_msgs[i])
Packit Service c5cf8c
                MPL_free((char *) user_code_msgs[i]);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return 0;
Packit Service c5cf8c
}