1
1
openmpi/opal/mca/base/mca_base_param.c
Nathan Hjelm cf377db823 MCA/base: Add new MCA variable system
Features:
 - Support for an override parameter file (openmpi-mca-param-override.conf).
   Variable values in this file can not be overridden by any file or environment
   value.
 - Support for boolean, unsigned, and unsigned long long variables.
 - Support for true/false values.
 - Support for enumerations on integer variables.
 - Support for MPIT scope, verbosity, and binding.
 - Support for command line source.
 - Support for setting variable source via the environment using
   OMPI_MCA_SOURCE_<var name>=source (either command or file:filename)
 - Cleaner API.
 - Support for variable groups (equivalent to MPIT categories).

Notes:
 - Variables must be created with a backing store (char **, int *, or bool *)
   that must live at least as long as the variable.
 - Creating a variable with the MCA_BASE_VAR_FLAG_SETTABLE enables the use of
   mca_base_var_set_value() to change the value.
 - String values are duplicated when the variable is registered. It is up to
   the caller to free the original value if necessary. The new value will be
   freed by the mca_base_var system and must not be freed by the user.
 - Variables with constant scope may not be settable.
 - Variable groups (and all associated variables) are deregistered when the
   component is closed or the component repository item is freed. This
   prevents a segmentation fault from accessing a variable after its component
   is unloaded.
 - After some discussion we decided we should remove the automatic registration
   of component priority variables. Few component actually made use of this
   feature.
 - The enumerator interface was updated to be general enough to handle
   future uses of the interface.
 - The code to generate ompi_info output has been moved into the MCA variable
   system. See mca_base_var_dump().

opal: update core and components to mca_base_var system
orte: update core and components to mca_base_var system
ompi: update core and components to mca_base_var system

This commit also modifies the rmaps framework. The following variables were
moved from ppr and lama: rmaps_base_pernode, rmaps_base_n_pernode,
rmaps_base_n_persocket. Both lama and ppr create synonyms for these variables.

This commit was SVN r28236.
2013-03-27 21:09:41 +00:00

844 строки
24 KiB
C

/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
/*
* Copyright (c) 2004-2008 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2012 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2008-2011 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2012-2013 Los Alamos National Security, LLC. All rights
* reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include "opal/mca/installdirs/installdirs.h"
#include "opal/util/os_path.h"
#include "opal/util/path.h"
#include "opal/class/opal_value_array.h"
#include "opal/util/show_help.h"
#include "opal/class/opal_hash_table.h"
#include "opal/util/printf.h"
#include "opal/util/argv.h"
#include "opal/mca/mca.h"
#include "opal/mca/base/mca_base_param.h"
#include "opal/mca/base/mca_base_param_internal.h"
#include "opal/constants.h"
#include "opal/util/output.h"
#include "opal/util/opal_environ.h"
#include "opal/runtime/opal.h"
#include "opal/mca/base/mca_base_var.h"
/*
* local variables
*/
static opal_value_array_t mca_base_params;
static const char *mca_prefix = "OMPI_MCA_";
static bool initialized = false;
/*
* local functions
*/
static void param_constructor(mca_base_param_t *p);
static void param_destructor(mca_base_param_t *p);
static void info_constructor(mca_base_param_info_t *p);
static void info_destructor(mca_base_param_info_t *p);
/*
* Make the class instance for mca_base_param_t
*/
OBJ_CLASS_INSTANCE(mca_base_param_t, opal_object_t,
param_constructor, param_destructor);
OBJ_CLASS_INSTANCE(mca_base_param_info_t, opal_list_item_t,
info_constructor, info_destructor);
/*
* Set it up
*/
int mca_base_param_init(void)
{
int ret;
if (!initialized) {
initialized = true;
OBJ_CONSTRUCT(&mca_base_params, opal_value_array_t);
opal_value_array_init (&mca_base_params, sizeof (mca_base_param_t));
ret = mca_base_var_init ();
if (OPAL_SUCCESS != ret) {
return ret;
}
}
return OPAL_SUCCESS;
}
/* Leave file caching up to the variable system */
int mca_base_param_recache_files(bool rel_path_search)
{
return OPAL_SUCCESS;
}
/*
* Register an MCA parameter
*/
static int register_param (const char *type_name, const char *component_name,
const char *param_name, const char *help_msg,
bool internal, bool read_only, mca_base_param_type_t type,
void *default_value, void *current_value)
{
mca_base_var_flag_t flags = 0;
mca_base_var_type_t var_type;
mca_base_param_t param;
int ret, var_index;
if (!initialized) {
mca_base_param_init ();
}
OBJ_CONSTRUCT(&param, mca_base_param_t);
if (internal) {
flags |= MCA_BASE_VAR_FLAG_INTERNAL;
}
if (read_only) {
flags |= MCA_BASE_VAR_FLAG_DEFAULT_ONLY;
}
/* Create a backing store for this parameter (needs to be malloc since the param
will be memcpy'd into the parameter list) */
param.param_value = calloc (1, sizeof (*param.param_value));
if (NULL == param.param_value) {
OBJ_DESTRUCT(&param);
return OPAL_ERR_OUT_OF_RESOURCE;
}
switch (type) {
case MCA_BASE_PARAM_TYPE_INT:
var_type = MCA_BASE_VAR_TYPE_INT;
param.param_value->intval = ((int *)default_value)[0];
break;
case MCA_BASE_PARAM_TYPE_STRING:
var_type = MCA_BASE_VAR_TYPE_STRING;
if (default_value) {
param.param_value->stringval = (char *) default_value;
}
break;
case MCA_BASE_PARAM_TYPE_MAX:
OBJ_DESTRUCT(&param);
return OPAL_ERROR;
}
var_index = mca_base_var_register (NULL, type_name, component_name,
param_name, help_msg, var_type, NULL,
0, flags, OPAL_INFO_LVL_9,
MCA_BASE_VAR_SCOPE_READONLY,
param.param_value);
param.var_index = var_index;
if (0 > var_index) {
return OPAL_ERROR;
}
ret = opal_value_array_append_item (&mca_base_params, &param);
if (OPAL_SUCCESS != ret) {
return ret;
}
if (current_value) {
switch (type) {
case MCA_BASE_PARAM_TYPE_INT:
((int *) current_value)[0] = param.param_value->intval;
break;
case MCA_BASE_PARAM_TYPE_STRING:
if (NULL != param.param_value->stringval) {
((char **) current_value)[0] = strdup (param.param_value->stringval);
} else {
((char **) current_value)[0] = NULL;
}
case MCA_BASE_PARAM_TYPE_MAX:
/* Impossible */
break;
}
}
return var_index;
}
int mca_base_param_reg_int(const mca_base_component_t *component,
const char *param_name,
const char *help_msg,
bool internal,
bool read_only,
int default_value,
int *current_value)
{
return register_param (component->mca_type_name, component->mca_component_name,
param_name, help_msg, internal, read_only,
MCA_BASE_PARAM_TYPE_INT, (void *) &default_value,
(void *) current_value);
}
/*
* Register an integer MCA parameter that is not associated with a
* component
*/
int mca_base_param_reg_int_name(const char *type,
const char *param_name,
const char *help_msg,
bool internal,
bool read_only,
int default_value,
int *current_value)
{
return register_param (type, NULL, param_name, help_msg, internal, read_only,
MCA_BASE_PARAM_TYPE_INT, (void *) &default_value,
(void *) current_value);
}
int mca_base_param_reg_string(const mca_base_component_t *component,
const char *param_name,
const char *help_msg,
bool internal,
bool read_only,
const char *default_value,
char **current_value)
{
return register_param (component->mca_type_name, component->mca_component_name,
param_name, help_msg, internal, read_only,
MCA_BASE_PARAM_TYPE_STRING, (void *) default_value,
(void *) current_value);
}
/*
* Register a string MCA parameter that is not associated with a
* component
*/
int mca_base_param_reg_string_name(const char *type,
const char *param_name,
const char *help_msg,
bool internal,
bool read_only,
const char *default_value,
char **current_value)
{
return register_param (type, NULL, param_name, help_msg, internal, read_only,
MCA_BASE_PARAM_TYPE_STRING, (void *) default_value,
(void *) current_value);
}
/*
* Register a synonym name for an existing MCA parameter
*/
static int reg_syn (int index_orig, const char *type_name, const char *component_name,
const char *syn_param_name, bool deprecated)
{
return mca_base_var_register_synonym (index_orig, NULL, type_name,
component_name, syn_param_name,
deprecated ? MCA_BASE_VAR_SYN_FLAG_DEPRECATED : 0);
}
int mca_base_param_reg_syn(int index_orig,
const mca_base_component_t *syn_component,
const char *syn_param_name, bool deprecated)
{
return reg_syn (index_orig, syn_component->mca_type_name,
syn_component->mca_component_name, syn_param_name,
deprecated);
}
/*
* Register a synonym name for an existing MCA parameter
*/
int mca_base_param_reg_syn_name(int index_orig,
const char *syn_type_name,
const char *syn_param_name, bool deprecated)
{
return reg_syn (index_orig, syn_type_name, NULL, syn_param_name,
deprecated);
}
/*
* Look up an integer MCA parameter.
*/
int mca_base_param_lookup_int(int index, int *value)
{
const mca_base_var_t *var;
const mca_base_var_storage_t *tmp;
int ret;
ret = mca_base_var_get (index, &var);
if (OPAL_SUCCESS != ret) {
return ret;
}
ret = mca_base_var_get_value (index, &tmp, NULL, NULL);
if (OPAL_SUCCESS != ret) {
return ret;
}
if (MCA_BASE_VAR_TYPE_BOOL == var->mbv_type) {
*value = tmp->boolval;
} else if (MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG == var->mbv_type) {
*value = (int) tmp->ullval;
} else if (MCA_BASE_VAR_TYPE_SIZE_T == var->mbv_type) {
*value = (int) tmp->sizetval;
} else {
*value = tmp->intval;
}
return OPAL_SUCCESS;
}
/*
* Set an integer parameter
*/
int mca_base_param_set_int(int index, int value)
{
const mca_base_var_t *var;
mca_base_var_storage_t tmp;
int ret;
ret = mca_base_var_get (index, &var);
if (OPAL_SUCCESS != ret) {
return ret;
}
if (MCA_BASE_VAR_TYPE_BOOL == var->mbv_type) {
tmp.boolval = !!value;
} else if (MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG == var->mbv_type) {
tmp.ullval = (unsigned long long) value;
} else if (MCA_BASE_VAR_TYPE_SIZE_T == var->mbv_type) {
tmp.sizetval = (size_t) value;
} else {
tmp.intval = value;
}
return mca_base_var_set_value (index, &tmp, sizeof (tmp),
MCA_BASE_VAR_SOURCE_SET, NULL);
}
/*
* Deregister a parameter
*/
int mca_base_param_deregister(int index)
{
return mca_base_var_deregister (index);
}
/*
* Look up a string MCA parameter.
*/
int mca_base_param_lookup_string(int index, char **value)
{
const char **tmp;
int ret;
*value = NULL;
ret = mca_base_var_get_value (index, &tmp, NULL, NULL);
if (OPAL_SUCCESS != ret) {
return ret;
}
/* MCA param users expect us to return a copy of the string */
if (tmp && tmp[0]) {
*value = strdup (tmp[0]);
if (NULL == *value) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
}
return OPAL_SUCCESS;
}
/*
* Set an string parameter
*/
int mca_base_param_set_string(int index, char *value)
{
return mca_base_var_set_value (index, value, value ? strlen (value) : 0,
MCA_BASE_VAR_SOURCE_SET, NULL);
}
/*
* Lookup the source of an MCA param's value
*/
int mca_base_param_lookup_source(int index, mca_base_param_source_t *source, const char **source_file)
{
mca_base_var_source_t var_source;
int ret;
ret = mca_base_var_get_value (index, NULL, &var_source, source_file);
if (OPAL_SUCCESS != ret) {
return ret;
}
if (NULL != source) {
switch (var_source) {
case MCA_BASE_VAR_SOURCE_ENV:
case MCA_BASE_VAR_SOURCE_COMMAND_LINE:
*source = MCA_BASE_PARAM_SOURCE_ENV;
break;
case MCA_BASE_VAR_SOURCE_FILE:
case MCA_BASE_VAR_SOURCE_OVERRIDE:
*source = MCA_BASE_PARAM_SOURCE_FILE;
break;
case MCA_BASE_VAR_SOURCE_SET:
*source = MCA_BASE_PARAM_SOURCE_OVERRIDE;
break;
case MCA_BASE_VAR_SOURCE_DEFAULT:
*source = MCA_BASE_PARAM_SOURCE_DEFAULT;
break;
case MCA_BASE_VAR_SOURCE_MAX:
return OPAL_ERROR;
}
}
return OPAL_SUCCESS;
}
/*
* Unset a parameter
*/
int mca_base_param_unset(int index)
{
/* It is possible to support the semantics of unset by:
* 1) When registering the parameter, save the default.
* 2) On calling unset, lookup the default (can only be done for
* parameters that use the old system).
* 3) Deregister the parameter
* 4) Set the default
* 5) Register the parameter.
*
* The mca_base_var system will ensure the parameter keeps the
* same index and will do the lookup (env, file, default) again.
*/
return OPAL_ERR_NOT_SUPPORTED;
}
char *mca_base_param_env_var(const char *param_name)
{
char *var_name;
int ret;
ret = mca_base_var_env_name (param_name, &var_name);
if (OPAL_SUCCESS != ret) {
return NULL;
}
return var_name;
}
/*
* Find the index for an MCA parameter based on its names.
*/
int mca_base_param_find(const char *type_name, const char *component_name,
const char *param_name)
{
return mca_base_var_find (NULL, type_name, component_name, param_name);
}
int mca_base_param_set_internal (int index, bool internal)
{
return mca_base_var_set_flag (index, MCA_BASE_VAR_FLAG_INTERNAL, internal);
}
/*
* Return a list of info of all currently registered parameters
*/
int mca_base_param_dump(opal_list_t **info, bool internal)
{
mca_base_param_info_t *p, *q;
size_t i, j, len;
int *synonyms;
int ret;
/* Check for bozo cases */
if (!initialized || NULL == info) {
return OPAL_ERROR;
}
*info = OBJ_NEW(opal_list_t);
if (NULL == *info) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
/* Iterate through all the registered parameters */
len = mca_base_var_get_count ();
for (i = 0; i < len; ++i) {
const mca_base_var_t *var, *syn;
ret = mca_base_var_get (i, &var);
if (OPAL_SUCCESS != ret) {
continue;
}
/* Dump this variable only if it is not a synonym and either it
is not internal or internal variables were requested */
if ((internal || !(var->mbv_flags & MCA_BASE_VAR_FLAG_INTERNAL)) &&
0 > var->mbv_synonym_for) {
const mca_base_var_group_t *group;
ret = mca_base_var_group_get (var->mbv_group_index, &group);
if (OPAL_SUCCESS != ret) {
continue;
}
p = OBJ_NEW(mca_base_param_info_t);
if (NULL == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
p->mbpp_index = i;
p->mbpp_type_name = group->group_framework;
p->mbpp_component_name = group->group_component;
p->mbpp_param_name = var->mbv_variable_name;
p->mbpp_full_name = var->mbv_full_name;
p->mbpp_deprecated = !!(var->mbv_flags & MCA_BASE_VAR_FLAG_DEPRECATED);
p->mbpp_internal = !!(var->mbv_flags & MCA_BASE_VAR_FLAG_INTERNAL);
p->mbpp_read_only = !!(var->mbv_flags & MCA_BASE_VAR_FLAG_DEFAULT_ONLY);
if (var->mbv_type == MCA_BASE_VAR_TYPE_INT ||
var->mbv_type == MCA_BASE_VAR_TYPE_UNSIGNED_INT ||
var->mbv_type == MCA_BASE_VAR_TYPE_UNSIGNED_LONG_LONG ||
var->mbv_type == MCA_BASE_VAR_TYPE_SIZE_T ||
var->mbv_type == MCA_BASE_VAR_TYPE_BOOL) {
p->mbpp_type = MCA_BASE_PARAM_TYPE_INT;
} else {
p->mbpp_type = MCA_BASE_PARAM_TYPE_STRING;
}
p->mbpp_help_msg = var->mbv_description;
/* Save this entry to the list */
opal_list_append(*info, &p->super);
p->mbpp_synonyms_len = opal_value_array_get_size ((opal_value_array_t *) &var->mbv_synonyms);
if (p->mbpp_synonyms_len) {
p->mbpp_synonyms = calloc(p->mbpp_synonyms_len,
sizeof (mca_base_param_info_t *));
if (NULL == p->mbpp_synonyms) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
synonyms = OPAL_VALUE_ARRAY_GET_BASE(&var->mbv_synonyms, int);
for (j = 0 ; j < (size_t) p->mbpp_synonyms_len ; ++j) {
ret = mca_base_var_get (synonyms[j], &syn);
if (OPAL_SUCCESS != ret) {
p->mbpp_synonyms[j] = NULL;
continue;
}
ret = mca_base_var_group_get (syn->mbv_group_index, &group);
if (OPAL_SUCCESS != ret) {
continue;
}
q = OBJ_NEW(mca_base_param_info_t);
if (NULL == q) {
p->mbpp_synonyms_len = j;
return OPAL_ERR_OUT_OF_RESOURCE;
}
q->mbpp_index = (int) i;
q->mbpp_type_name = group->group_framework;
q->mbpp_component_name = group->group_component;
q->mbpp_param_name = syn->mbv_variable_name;
q->mbpp_full_name = syn->mbv_full_name;
q->mbpp_deprecated = !!(syn->mbv_flags & MCA_BASE_VAR_FLAG_DEPRECATED);
q->mbpp_internal = !!(syn->mbv_flags & MCA_BASE_VAR_FLAG_INTERNAL);
q->mbpp_read_only = !!(syn->mbv_flags & MCA_BASE_VAR_FLAG_DEFAULT_ONLY);
q->mbpp_type = syn->mbv_type;
q->mbpp_help_msg = syn->mbv_description;
/* Let this one point to the original */
q->mbpp_synonym_parent = p;
/* Let the original point to this one */
p->mbpp_synonyms[j] = q;
/* Save this entry to the list */
opal_list_append(*info, &q->super);
}
}
}
}
/* All done */
return OPAL_SUCCESS;
}
/*
* Make an argv-style list of strings suitable for an environment
*/
int mca_base_param_build_env(char ***env, int *num_env, bool internal)
{
return mca_base_var_build_env (env, num_env, internal);
}
/*
* Free a list -- and all associated memory -- that was previously
* returned from mca_base_param_dump()
*/
int mca_base_param_dump_release(opal_list_t *info)
{
opal_list_item_t *item;
while (NULL != (item = opal_list_remove_first(info))) {
OBJ_RELEASE(item);
}
OBJ_RELEASE(info);
return OPAL_SUCCESS;
}
/*
* Shut down the MCA parameter system (normally only invoked by the
* MCA framework itself).
*/
int mca_base_param_finalize(void)
{
mca_base_param_t *array;
size_t size, i;
int ret;
if (initialized) {
ret = mca_base_var_finalize ();
if (OPAL_SUCCESS != ret) {
return ret;
}
size = opal_value_array_get_size(&mca_base_params);
array = OPAL_VALUE_ARRAY_GET_BASE(&mca_base_params, mca_base_param_t);
for (i = 0 ; i < size ; ++i) {
OBJ_DESTRUCT(&array[i]);
}
OBJ_DESTRUCT(&mca_base_params);
initialized = false;
}
/* All done */
return OPAL_SUCCESS;
}
/*
* Create an empty param container
*/
static void param_constructor(mca_base_param_t *p)
{
memset ((char *) p + sizeof (p->super), 0, sizeof (*p) - sizeof (p->super));
}
/*
* Free all the contents of a param container
*/
static void param_destructor(mca_base_param_t *p)
{
if (NULL != p->param_value) {
free (p->param_value);
}
#if OPAL_ENABLE_DEBUG
/* Cheap trick to reset everything to NULL */
param_constructor(p);
#endif
}
static void info_constructor(mca_base_param_info_t *p)
{
p->mbpp_index = -1;
p->mbpp_type = MCA_BASE_PARAM_TYPE_MAX;
p->mbpp_type_name = NULL;
p->mbpp_component_name = NULL;
p->mbpp_param_name = NULL;
p->mbpp_full_name = NULL;
p->mbpp_deprecated = false;
p->mbpp_synonyms = NULL;
p->mbpp_synonyms_len = 0;
p->mbpp_synonym_parent = NULL;
p->mbpp_help_msg = NULL;
}
static void info_destructor(mca_base_param_info_t *p)
{
if (NULL != p->mbpp_synonyms) {
free(p->mbpp_synonyms);
}
/* No need to free any of the strings -- the pointers were copied
by value from their corresponding parameter registration */
info_constructor(p);
}
int mca_base_param_find_int(const mca_base_component_t *component,
const char *param_name,
char **env,
int *current_value)
{
char *tmp, *ptr;
int len, i;
int rc=OPAL_ERR_NOT_FOUND;
if (NULL == env) {
return OPAL_ERR_NOT_FOUND;
}
asprintf(&tmp, "%s%s_%s_%s", mca_prefix, component->mca_type_name,
component->mca_component_name, param_name);
len = strlen(tmp);
for (i=0; NULL != env[i]; i++) {
if (0 == strncmp(tmp, env[i], len)) {
ptr = strchr(env[i], '=');
ptr++;
*current_value = strtol(ptr, NULL, 10);
rc = OPAL_SUCCESS;
break;
}
}
free(tmp);
return rc;
}
int mca_base_param_find_int_name(const char *type,
const char *param_name,
char **env,
int *current_value)
{
char *tmp, *ptr;
int len, i;
int rc=OPAL_ERR_NOT_FOUND;
if (NULL == env) {
return OPAL_ERR_NOT_FOUND;
}
asprintf(&tmp, "%s%s_%s", mca_prefix, type, param_name);
len = strlen(tmp);
for (i=0; NULL != env[i]; i++) {
if (0 == strncmp(tmp, env[i], len)) {
ptr = strchr(env[i], '=');
ptr++;
*current_value = strtol(ptr, NULL, 10);
rc = OPAL_SUCCESS;
break;
}
}
free(tmp);
return rc;
}
int mca_base_param_find_string(const mca_base_component_t *component,
const char *param_name,
char **env,
char **current_value)
{
char *tmp, *ptr;
int len, i;
int rc=OPAL_ERR_NOT_FOUND;
if (NULL == env) {
return OPAL_ERR_NOT_FOUND;
}
asprintf(&tmp, "%s%s_%s_%s", mca_prefix, component->mca_type_name,
component->mca_component_name, param_name);
len = strlen(tmp);
for (i=0; NULL != env[i]; i++) {
if (0 == strncmp(tmp, env[i], len)) {
ptr = strchr(env[i], '=');
ptr++;
*current_value = ptr;
rc = OPAL_SUCCESS;
break;
}
}
free(tmp);
return rc;
}
int mca_base_param_find_string_name(const char *type,
const char *param_name,
char **env,
char **current_value)
{
char *tmp, *ptr;
int len, i;
int rc=OPAL_ERR_NOT_FOUND;
if (NULL == env) {
return OPAL_ERR_NOT_FOUND;
}
asprintf(&tmp, "%s%s_%s", mca_prefix, type, param_name);
len = strlen(tmp);
for (i=0; NULL != env[i]; i++) {
if (0 == strncmp(tmp, env[i], len)) {
ptr = strchr(env[i], '=');
ptr++;
*current_value = ptr;
rc = OPAL_SUCCESS;
break;
}
}
free(tmp);
return rc;
}
int mca_base_param_check_exclusive_string(const char *type_a,
const char *component_a,
const char *param_a,
const char *type_b,
const char *component_b,
const char *param_b)
{
return mca_base_var_check_exclusive (NULL, type_a, component_a,
param_a, type_b, component_b,
param_b);
}