/* * $HEADER$ */ /** @file **/ #include "lam_config.h" #include #include #include #include "lam/constants.h" #include "lam/lfc/array.h" #include "lam/mem/malloc.h" #include "mca/mca.h" #include "mca/lam/base/mca_base_param.h" typedef enum { MCA_BASE_PARAM_TYPE_INT, MCA_BASE_PARAM_TYPE_STRING, MCA_BASE_PARAM_TYPE_MAX } mca_base_param_type_t; struct mca_base_param_t { lam_array_item_t super; mca_base_param_type_t mbp_type; char *mbp_type_name; char *mbp_module_name; char *mbp_param_name; char *mbp_full_name; int mbp_keyval; char *mbp_env_var_name; mca_base_param_storage_t mbp_default_value; }; typedef struct mca_base_param_t mca_base_param_t; /* * local variables */ static lam_array_t mca_base_params; static char *mca_prefix = "LAM_MPI_MCA_"; static bool initialized = false; /* * local functions */ static int param_register(const char *type_name, const char *module_name, const char *param_name, const char *mca_param_name, mca_base_param_type_t type, mca_base_param_storage_t *default_value); static bool param_lookup(int index, mca_base_param_storage_t *storage); static int param_compare(const void *a, const void *b); static void param_free(mca_base_param_t *p); /** * Register an integer MCA parameter. * * @param type_name The MCA type (string). * @param module_name The name of the module (string). * @param param_name The name of the parameter being registered (string). * @param mca_param_name If NULL, the user-visible name of the * parameter is {type_name}_{module_name}_{param_name}. If this * parameter is non-NULL, it is used instead of the default name. * @param default_value The value that is used for this parameter if * the user does not supply one. * * @retval LAM_ERROR Upon failure to register the parameter. * @retval index Index value that can be used with * mca_base_param_lookup_int() to retrieve the value of the parameter. * * This function registers an integer MCA parameter and associates it * with a specific module. * * In most cases, mca_param_name should be NULL. Only in rare cases * is it necessary (or advisable) to override the default name. */ int mca_base_param_register_int(const char *type_name, const char *module_name, const char *param_name, const char *mca_param_name, int default_value) { mca_base_param_storage_t storage; storage.intval = default_value; return param_register(type_name, module_name, param_name, mca_param_name, MCA_BASE_PARAM_TYPE_INT, &storage); } /** * Register a string MCA parameter. * * @param type_name The MCA type (string). * @param module_name The name of the module (string). * @param param_name The name of the parameter being registered (string). * @param mca_param_name If NULL, the user-visible name of the * parameter is {type_name}_{module_name}_{param_name}. If this * parameter is non-NULL, it is used instead of the default name. * @param default_value The value that is used for this parameter if * the user does not supply one. * * @retval LAM_ERROR Upon failure to register the parameter. * @retval index Index value that can be used with * mca_base_param_lookup_string() to retrieve the value of the * parameter. * * This function registers an string MCA parameter and associates it * with a specific module. * * In most cases, mca_param_name should be NULL. Only in rare cases * is it necessary (or advisable) to override the default name. */ int mca_base_param_register_string(const char *type_name, const char *module_name, const char *param_name, const char *mca_param_name, const char *default_value) { mca_base_param_storage_t storage; if (NULL != default_value) storage.stringval = strdup(default_value); else storage.stringval = NULL; return param_register(type_name, module_name, param_name, mca_param_name, MCA_BASE_PARAM_TYPE_STRING, &storage); } /** * Look up an integer MCA parameter. * * @param index Index previous returned from * mca_base_param_register_int(). * @param value Pointer to int where the parameter value will be * stored. * * @retvalue LAM_ERROR Upon failure. The contents of value are * undefined. * @retvalue LAM_SUCCESS Upon success. value will be filled with the * parameter's current value. * * The value of a specific MCA parameter can be looked up using the * return value from mca_base_param_register_int(). */ int mca_base_param_lookup_int(int index, int *value) { mca_base_param_storage_t storage; if (param_lookup(index, &storage)) { *value = storage.intval; return LAM_SUCCESS; } return LAM_ERROR; } /** * Look up a string MCA parameter. * * @param index Index previous returned from * mca_base_param_register_string(). * @param value Pointer to (char *) where the parameter value will be * stored. * * @retvalue LAM_ERROR Upon failure. The contents of value are * undefined. * @retvalue LAM_SUCCESS Upon success. value will be filled with the * parameter's current value. * * The value of a specific MCA parameter can be looked up using the * return value from mca_base_param_register_string(). */ int mca_base_param_lookup_string(int index, char **value) { mca_base_param_storage_t storage; if (param_lookup(index, &storage)) { *value = storage.stringval; return LAM_SUCCESS; } return LAM_ERROR; } /** * Find the index for an MCA parameter based on its names. * * @param type_name Name of the type containing the parameter. * @param module_name Name of the module containing the parameter. * @param param_name Name of the parameter. * * @retval LAM_ERROR If the parameter was not found. * @retval index If the parameter was found. * * It is not always convenient to widely propagate a parameter's index * value, or it may be necessary to look up the parameter from a * different module -- where it is not possible to have the return * value from mca_base_param_register_int() or * mca_base_param_register_string(). This function can be used to * look up the index of any registered parameter. The returned index * can be used with mca_base_param_lookup_int() and * mca_base_param_lookup_string(). */ int mca_base_param_find(const char *type_name, const char *module_name, const char *param_name) { size_t i, size; mca_base_param_t **array; /* Check for bozo cases */ if (!initialized) return LAM_ERROR; if (NULL == type_name || NULL == param_name) return LAM_ERROR; /* Loop through looking for a parameter of a given type/module/param */ array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &size); for (i = 0; i < size; ++i) { if (0 == strcmp(type_name, array[i]->mbp_type_name) && ((NULL == module_name && NULL == array[i]->mbp_module_name) || (NULL != module_name && NULL != array[i]->mbp_module_name && 0 == strcmp(module_name, array[i]->mbp_module_name))) && 0 == strcmp(param_name, array[i]->mbp_param_name)) return i; } /* Didn't find it */ return LAM_ERROR; } /** * Shut down the MCA parameter system (normally only invoked by the * MCA framework itself). * * @returns LAM_SUCCESS This function never fails. * * This function shuts down the MCA parameter registry and frees all * associated memory. No other mca_base_param*() functions can be * invoked after this function. * * This function is normally only invoked by the MCA framework itself * when the process is shutting down (e.g., during MPI_FINALIZE). It * is only documented here for completeness. */ int mca_base_param_finalize(void) { size_t i, size; mca_base_param_t **array; if (initialized) { array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &size); for (i = 0; i < size; ++i) { param_free(array[i]); } lam_arr_destroy(&mca_base_params); initialized = false; } return LAM_SUCCESS; } /*************************************************************************/ static int param_register(const char *type_name, const char *module_name, const char *param_name, const char *mca_param_name, mca_base_param_type_t type, mca_base_param_storage_t *default_value) { size_t i, len; mca_base_param_t *param, **array; /* Initialize the array if it has never been initialized */ if (!initialized) { lam_arr_init(&mca_base_params); initialized = true; } /* Create a parameter entry. If a keyval is to be used, it will be registered elsewhere. We simply assign -1 here. */ param = LAM_MALLOC(sizeof(mca_base_param_t)); if (NULL == param) { return LAM_ERR_OUT_OF_RESOURCE; } lam_arr_item_init((lam_array_item_t *) param); param->mbp_type = type; param->mbp_keyval = -1; param->mbp_type_name = strdup(type_name); if (NULL == param->mbp_type_name) { return LAM_ERROR; } if (NULL != module_name) { param->mbp_module_name = strdup(module_name); if (NULL == param->mbp_module_name) { LAM_FREE(param->mbp_type_name); return LAM_ERROR; } } else { param->mbp_module_name = NULL; } if (param_name != NULL) { param->mbp_param_name = strdup(param_name); if (NULL == param->mbp_param_name) { LAM_FREE(param->mbp_type_name); LAM_FREE(param->mbp_module_name); return LAM_ERROR; } } else { param->mbp_param_name = NULL; } /* The full parameter name may have been specified by the caller. If it was, use that (only for backwards compatability). Otherwise, derive it from the type, module, and parameter name. */ param->mbp_env_var_name = NULL; if (MCA_BASE_PARAM_INFO != mca_param_name && NULL != mca_param_name) { param->mbp_full_name = strdup(mca_param_name); } else { len = 16 + strlen(type_name); if (NULL != module_name) { len += strlen(module_name); } if (NULL != param_name) { len += strlen(param_name); } param->mbp_full_name = LAM_MALLOC(len); if (NULL != param->mbp_full_name) { LAM_FREE(param->mbp_type_name); LAM_FREE(param->mbp_module_name); LAM_FREE(param->mbp_param_name); return LAM_ERROR; } strncpy(param->mbp_full_name, type_name, len); if (NULL != module_name) { strcat(param->mbp_full_name, "_"); strcat(param->mbp_full_name, module_name); } if (NULL != param_name) { strcat(param->mbp_full_name, "_"); strcat(param->mbp_full_name, param_name); } } /* If mca_param_name isn't MCA_BASE_PARAM_INFO, then it's a lookup-able value. So alloc the environment variable name as well. */ if (MCA_BASE_PARAM_INFO != mca_param_name) { len = strlen(param->mbp_full_name) + strlen(mca_prefix) + 16; param->mbp_env_var_name = LAM_MALLOC(len); if (NULL == param->mbp_env_var_name) { LAM_FREE(param->mbp_full_name); LAM_FREE(param->mbp_type_name); LAM_FREE(param->mbp_module_name); LAM_FREE(param->mbp_param_name); return LAM_ERROR; } snprintf(param->mbp_env_var_name, len, "%s%s", mca_prefix, param->mbp_full_name); } /* Figure out the default value */ if (NULL != default_value) { if (MCA_BASE_PARAM_TYPE_STRING == param->mbp_type && NULL != default_value->stringval) { param->mbp_default_value.stringval = strdup(default_value->stringval); } else { param->mbp_default_value = *default_value; } } else { memset(¶m->mbp_default_value, 0, sizeof(param->mbp_default_value)); } /* See if this entry is already in the Array */ array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &len); for (i = 0; i < len; ++i) { if (0 == param_compare(¶m, array[i])) { /* Copy in the new default value to the old entry */ if (MCA_BASE_PARAM_TYPE_STRING == array[i]->mbp_type && NULL != array[i]->mbp_default_value.stringval) { LAM_FREE(array[i]->mbp_default_value.stringval); } if (MCA_BASE_PARAM_TYPE_STRING == param->mbp_type && NULL != param->mbp_default_value.stringval) { array[i]->mbp_default_value.stringval = strdup(param->mbp_default_value.stringval); } param_free(param); return i; } } /* Add it to the array */ if (!lam_arr_append_item(&mca_base_params, (lam_object_t*) param)) { return LAM_ERROR; } return lam_arr_get_size(&mca_base_params) - 1; } /* * DO NOT MODIFY THIS FUNCTION WITHOUT ALSO MODIFYING mca_mpi_param.c! * * This function appears in liblam. Because of unix linker semantics, * it's simply easier to essentially duplicate this function in libmpi * because in libmpi, we need to lookup on a keyval before looking in * the environment. The logic is simpler if we just duplicate/alter * the code in mca_mpi_param.c rather than try to make this a) public, * and b) more general (to accomodate looking up keyvals while not * linking to MPI_Comm_get_attr() in libmpi). */ static bool param_lookup(int index, mca_base_param_storage_t *storage) { size_t size; char *env; mca_base_param_t **array, *p; /* Lookup the index and see if it's valid */ if (!initialized) { return false; } if (lam_arr_get_size(&mca_base_params) < index) { return false; } array = (mca_base_param_t **) lam_arr_get_c_array(&mca_base_params, &size); p = array[index]; #if 0 p = ((mca_base_param_t*) lam_arr_get_c_array(&mca_base_params, &size)) + index; #endif /* We either don't have a keyval or didn't find it. So look in the environment. */ if (NULL != p->mbp_env_var_name && NULL != (env = getenv(p->mbp_env_var_name))) { if (MCA_BASE_PARAM_TYPE_INT == p->mbp_type) { storage->intval = atoi(env); } else if (MCA_BASE_PARAM_TYPE_STRING == p->mbp_type) { storage->stringval = strdup(env); } else { return false; } return true; } /* Didn't find it; use the default value. */ switch (p->mbp_type) { case MCA_BASE_PARAM_TYPE_INT: storage->intval = p->mbp_default_value.intval; break; case MCA_BASE_PARAM_TYPE_STRING: storage->stringval = p->mbp_default_value.stringval; break; default: return false; } /* All done */ return true; } static int param_compare(const void *a, const void *b) { const mca_base_param_t *aa = (const mca_base_param_t*) a; const mca_base_param_t *bb = (const mca_base_param_t*) b; return strcmp(aa->mbp_full_name, bb->mbp_full_name); } static void param_free(mca_base_param_t *p) { if (NULL != p->mbp_type_name) { LAM_FREE(p->mbp_type_name); } if (NULL != p->mbp_module_name) { LAM_FREE(p->mbp_module_name); } if (NULL != p->mbp_param_name) { LAM_FREE(p->mbp_param_name); } if (NULL != p->mbp_env_var_name) { LAM_FREE(p->mbp_env_var_name); } if (NULL != p->mbp_full_name) { LAM_FREE(p->mbp_full_name); } if (MCA_BASE_PARAM_TYPE_STRING == p->mbp_type && NULL != p->mbp_default_value.stringval) { LAM_FREE(p->mbp_default_value.stringval); } LAM_FREE(p); }