From cfd5524ad5025c274e380360eaaaa4aefbd3fe4f Mon Sep 17 00:00:00 2001 From: Jeff Squyres Date: Sat, 14 Aug 2004 01:56:05 +0000 Subject: [PATCH] Committing several things under one commit, but they're all at least somewhat tied together and I'd rather have a consistent commit rather than several smaller commits that individually break the tree: - first cut of src/file/file.c: MPI_File handling. More to come here. - tweaked MPI_Info handling a bit: cause MPI_Info_f2c to invoke error handler if provided index is out of range (vs. returing MPI_INFO_NULL without invoking an error handler) - moved general MPI MCA params off into their own .h and .c file (so that ompi_info can call it and therefore display MPI MCA params) - first [abbreviated] cut of src/mca/io/base/* -- much more to come here; stripped down to basics for this commit - filled in a small number of MPI_File* functions for testing purposes - updated a bunch of doxygen docs --> Unresolved questions about MPI_ERRORS_RETURN, MPI_ERRORS_ABORT, and MPI::ERRORS_THROW_EXCEPTIONS because of vagueness in MPI standard -- Edgar and I are discussing what to do here --> Unresolved questions about what to do in a case like this: MPI_File_open(..., &file); MPI_File_close(&file); MPI_File_read(..., &file); because MPI-2:9.7 says that the default error handler on MPI_File handles is MPI_ERRORS_RETURN -- we can't even print a warning here! This certainly violates the Law of Least Astonishment for MPI users (who certainly expect MPI functions that fail to complain loudly and to abort by default). This commit was SVN r2136. --- include/mpi.h | 4 +- src/Makefile.am | 7 +- src/communicator/comm_init.c | 1 + src/file/Makefile.am | 9 +- src/file/file.c | 267 ++++++++++++++++++++++++++++ src/file/file.h | 203 ++++++++++++++++++--- src/info/info.c | 245 ++++++++++++------------- src/info/info.h | 4 +- src/mca/io/base/Makefile.am | 18 +- src/mca/io/base/base.h | 25 +++ src/mca/io/base/io_base_close.c | 15 ++ src/mca/io/base/io_base_open.c | 15 ++ src/mpi/c/file_c2f.c | 18 +- src/mpi/c/file_close.c | 21 ++- src/mpi/c/file_delete.c | 20 ++- src/mpi/c/file_f2c.c | 19 +- src/mpi/c/file_open.c | 28 ++- src/mpi/c/file_read.c | 17 +- src/mpi/c/file_set_errhandler.c | 41 +++-- src/mpi/c/info_c2f.c | 2 +- src/mpi/c/info_f2c.c | 11 +- src/mpi/runtime/Makefile.am | 6 +- src/mpi/runtime/mpiruntime.h | 27 ++- src/mpi/runtime/ompi_mpi_finalize.c | 23 ++- src/mpi/runtime/ompi_mpi_init.c | 58 +++--- src/mpi/runtime/ompi_mpi_params.c | 63 +++++++ src/mpi/runtime/params.h | 68 +++++++ src/tools/ompi_info/components.cc | 5 + 28 files changed, 980 insertions(+), 260 deletions(-) create mode 100644 src/file/file.c create mode 100644 src/mca/io/base/base.h create mode 100644 src/mca/io/base/io_base_close.c create mode 100644 src/mca/io/base/io_base_open.c create mode 100644 src/mpi/runtime/ompi_mpi_params.c create mode 100644 src/mpi/runtime/params.h diff --git a/include/mpi.h b/include/mpi.h index babe293042..15d6d48781 100644 --- a/include/mpi.h +++ b/include/mpi.h @@ -278,7 +278,7 @@ enum { #define MPI_ERRHANDLER_NULL (&ompi_mpi_errhandler_null) #define MPI_INFO_NULL (&ompi_mpi_info_null) #define MPI_WIN_NULL ((MPI_Win) 0) -#define MPI_FILE_NULL ((MPI_File) 0) +#define MPI_FILE_NULL (&ompi_mpi_file_null) #define MPI_STATUS_IGNORE ((MPI_Status *) 0) #define MPI_STATUSES_IGNORE ((MPI_Status *) 0) @@ -399,6 +399,8 @@ extern struct ompi_errhandler_t ompi_mpi_errhandler_null; extern struct ompi_errhandler_t ompi_mpi_errors_are_fatal; extern struct ompi_errhandler_t ompi_mpi_errors_return; +extern struct ompi_file_t ompi_file_null; + extern struct ompi_info_t ompi_mpi_info_null; extern MPI_Fint *MPI_F_STATUS_IGNORE; diff --git a/src/Makefile.am b/src/Makefile.am index 61474e83f5..8bbe28145d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,12 +89,14 @@ libmpi_la_LIBADD = \ datatype/libdatatype.la \ errhandler/liberrhandler.la \ event/libevent.la \ + file/libfile.la \ group/libgroup.la \ info/libinfo.la \ mca/base/libmca_base.la \ mca/allocator/base/libmca_allocator_base.la $(MCA_allocator_STATIC_LTLIBS) \ mca/coll/base/libmca_coll_base.la $(MCA_coll_STATIC_LTLIBS) \ $(MCA_common_STATIC_LTLIBS) \ + mca/io/base/libmca_io_base.la $(MCA_coll_STATIC_LTLIBS) \ mca/llm/base/libmca_llm_base.la $(MCA_llm_STATIC_LTLIBS) \ mca/mpool/base/libmca_mpool_base.la $(MCA_mpool_STATIC_LTLIBS) \ mca/ns/base/libmca_ns_base.la $(MCA_ns_STATIC_LTLIBS) \ @@ -114,8 +116,3 @@ libmpi_la_LIBADD = \ threads/libthreads.la \ util/libutil.la libmpi_la_DEPENDENCIES = $(libmpi_la_LIBADD) - -not_implemented_yet =\ - ctnetwork/libctnetwork.la \ - file/libfile.la \ - win/libwin.la diff --git a/src/communicator/comm_init.c b/src/communicator/comm_init.c index bc31c678e4..7a3395c0c9 100644 --- a/src/communicator/comm_init.c +++ b/src/communicator/comm_init.c @@ -17,6 +17,7 @@ #include "mca/topo/topo.h" #include "mca/topo/base/base.h" #include "mca/ns/base/base.h" +#include "mpi/runtime/params.h" /* diff --git a/src/file/Makefile.am b/src/file/Makefile.am index 36fe02dc1a..706adaa446 100644 --- a/src/file/Makefile.am +++ b/src/file/Makefile.am @@ -1,19 +1,20 @@ -# -*- makefile -*- # # $HEADER$ # include $(top_srcdir)/config/Makefile.options -# JMS Remove this when we actually start building a library in here -# and $(headers) gets included in a SOURCES somewhere -EXTRA_DIST = $(headers) +noinst_LTLIBRARIES = libfile.la # Source code files headers = \ file.h +libfile_la_SOURCES = \ + $(headers) \ + file.c + # Conditionally install the header files if WANT_INSTALL_HEADERS diff --git a/src/file/file.c b/src/file/file.c new file mode 100644 index 0000000000..8bbcaf82bf --- /dev/null +++ b/src/file/file.c @@ -0,0 +1,267 @@ +/* + * $HEADER$ + */ + +#include "ompi_config.h" + +#include "file/file.h" +#include "class/ompi_list.h" +#include "mpi/runtime/params.h" + + +/* + * Table for Fortran <-> C file handle conversion + */ +ompi_pointer_array_t ompi_file_f_to_c_table; + +/* + * MPI_FILE_NULL + */ +ompi_file_t ompi_mpi_file_null; + + +/* + * Local functions + */ +static void file_constructor(ompi_file_t *obj); +static void file_destructor(ompi_file_t *obj); + + +/* + * Class instance for ompi_file_t + */ +OBJ_CLASS_INSTANCE(ompi_file_t, + ompi_object_t, + file_constructor, + file_destructor); + + +/* + * Initialize file handling bookeeping + */ +int ompi_file_init(void) +{ + /* Setup file array */ + + OBJ_CONSTRUCT(&ompi_file_f_to_c_table, ompi_pointer_array_t); + + /* Setup MPI_FILE_NULL. Note that it will have the default error + handler of MPI_ERRORS_RETURN, per MPI-2:9.7 (p265). */ + + OBJ_CONSTRUCT(&ompi_mpi_file_null, ompi_file_t); + ompi_mpi_file_null.f_comm = &ompi_mpi_comm_null; + OBJ_RETAIN(ompi_mpi_file_null.f_comm); + ompi_mpi_file_null.f_f_to_c_index = 0; + ompi_pointer_array_set_item(&ompi_file_f_to_c_table, 0, + &ompi_mpi_file_null); + + /* All done */ + + return OMPI_SUCCESS; +} + + +/* + * Create a file handle + */ +int ompi_file_open(ompi_communicator_t *comm, char *filename, + int amode, ompi_info_t *info, ompi_file_t **fh) +{ + ompi_file_t *file; + + file = OBJ_NEW(ompi_file_t); + if (NULL == file) { + return OMPI_ERR_OUT_OF_RESOURCE; + } + + /* Save the params */ + + file->f_comm = comm; + OBJ_RETAIN(comm); + file->f_filename = strdup(filename); + file->f_amode = amode; + + /* Select a module and actually open the file */ + + /* JMS fill in here */ + + /* All done */ + + *fh = file; + return OMPI_SUCCESS; +} + + +/* + * Close a file handle + */ +int ompi_file_close(ompi_file_t **file) +{ + (*file)->f_flags |= OMPI_FILE_ISCLOSED; + OBJ_RELEASE(*file); + *file = MPI_FILE_NULL; + return OMPI_SUCCESS; +} + + +/* + * Shut down the MPI_File bookkeeping + */ +int ompi_file_finalize(void) +{ + size_t i, max; + size_t num_unnamed; + ompi_file_t *file; + + /* Release MPI_FILE_NULL. Do this so that we don't get a bogus leak + report on it. Plus, it's statically allocated, so we don't want + to call OBJ_RELEASE on it. */ + + OBJ_DESTRUCT(&ompi_mpi_file_null); + ompi_pointer_array_set_item(&ompi_file_f_to_c_table, 0, NULL); + + /* Iterate through all the file handles and destroy them. Note + that this also takes care of destroying MPI_FILE_NULL. */ + + max = ompi_pointer_array_get_size(&ompi_file_f_to_c_table); + for (num_unnamed = i = 0; i < max; ++i) { + file = ompi_pointer_array_get_item(&ompi_file_f_to_c_table, i); + + /* If the file was closed but still exists because the user + told us to never free handles, then do an OBJ_RELEASE it + and all is well. Then get the value again and see if it's + actually been freed. */ + + if (NULL != file && ompi_debug_no_free_handles && + 0 == (file->f_flags & OMPI_FILE_ISCLOSED)) { + OBJ_RELEASE(file); + file = ompi_pointer_array_get_item(&ompi_file_f_to_c_table, i); + } + + if (NULL != file) { + + /* If the user wanted warnings about MPI object leaks, + print out a message */ + + if (ompi_debug_show_handle_leaks) { + ++num_unnamed; + } + + OBJ_RELEASE(file); + } + /* Don't bother setting each element back down to NULL; it + would just take a lot of thread locks / unlocks and since + we're destroying everything, it isn't worth it */ + } + if (num_unnamed > 0) { + ompi_output(0, "WANRING: %d unnamed MPI_File handles still allocated at MPI_FINALIZE", num_unnamed); + } + OBJ_DESTRUCT(&ompi_file_f_to_c_table); + + /* All done */ + + return OMPI_SUCCESS; +} + + +/* + * Constructor + */ +static void file_constructor(ompi_file_t *file) +{ + /* Initialize the MPI_FILE_OPEN params */ + + file->f_comm = NULL; + file->f_filename = NULL; + file->f_amode = 0; + + /* Initialize flags */ + + file->f_flags = 0; + + /* Initialize the fortran <--> C translation index */ + + file->f_f_to_c_index = ompi_pointer_array_add(&ompi_file_f_to_c_table, + file); + + /* Initialize the error handler. Per MPI-2:9.7 (p265), the + default error handler on file handles is the error handler on + MPI_FILE_NULL, which starts out as MPI_ERRORS_RETURN (but can + be changed by invoking MPI_FILE_SET_ERRHANDLER on + MPI_FILE_NULL). */ + + file->error_handler = ompi_mpi_file_null.error_handler; + OBJ_RETAIN(file->error_handler); + + /* Initialize the module */ + + file->f_io_version = OMPI_IO_VERSION_NONE; + memset(&(file->f_io_selected_module), 0, + sizeof(file->f_io_selected_module)); + file->f_selected_data = NULL; + + /* If the user doesn't want us to ever free it, then add an extra + RETAIN here */ + + if (ompi_debug_no_free_handles) { + OBJ_RETAIN(&(file->super)); + } +} + + +/* + * Destructor + */ +static void file_destructor(ompi_file_t *file) +{ + /* Finalize the module */ + + switch (file->f_io_version) { + case OMPI_IO_VERSION_1_0_0: +#if 0 + /* JMS need to implement */ + file->f_io_selected_module.v1_0_0.iom_finalize(file); +#endif + break; + + case OMPI_IO_VERSION_2_0_0: + /* JMS fill in here */ + break; + + default: + /* All other cases are uninitialized or MPI_FILE_NULL */ + break; + } + + /* Finalize the data members */ + + if (NULL != file->f_comm) { + OBJ_RELEASE(file->f_comm); +#if OMPI_ENABLE_DEBUG + file->f_comm = NULL; +#endif + } + + if (NULL != file->f_filename) { + free(file->f_filename); +#if OMPI_ENABLE_DEBUG + file->f_filename = NULL; +#endif + } + + if (NULL != file->error_handler) { + OBJ_RELEASE(file->error_handler); +#if OMPI_ENABLE_DEBUG + file->error_handler = NULL; +#endif + } + + /* Reset the f_to_c table entry */ + + if (MPI_UNDEFINED != file->f_f_to_c_index && + NULL != ompi_pointer_array_get_item(&ompi_file_f_to_c_table, + file->f_f_to_c_index)) { + ompi_pointer_array_set_item(&ompi_file_f_to_c_table, + file->f_f_to_c_index, NULL); + } +} diff --git a/src/file/file.h b/src/file/file.h index 521cec03f6..83949b72d7 100644 --- a/src/file/file.h +++ b/src/file/file.h @@ -7,34 +7,189 @@ #include "mpi.h" #include "errhandler/errhandler.h" +#include "communicator/communicator.h" +#include "threads/mutex.h" +#include "info/info.h" #include "mca/io/io.h" -typedef enum { - OMPI_IO_1_0_0, - OMPI_IO_2_0_0 -} ompi_io_version_t; +/** + * Version of IO component interface that we're using. + * + * The IO component is being designed to ensure that it can + * simultaneously support multiple component versions in a single + * executable. This is because ROMIO will always be v1.x that + * supports pretty much a 1-to-1 MPI-API-to-module-function mapping, + * but we plan to have a v2.x series that will be "something + * different" (as yet undefined). + */ +enum ompi_io_version_t { + OMPI_IO_VERSION_NONE, + OMPI_IO_VERSION_1_0_0, + OMPI_IO_VERSION_2_0_0, - -struct ompi_file_t { - char f_name[MPI_MAX_OBJECT_NAME]; - ompi_io_version_t ompi_io_version; - - /* Hooks for io modules to hang things */ - - union { - mca_io_base_module_1_0_0_t f_io; - } mca_io_functions; - - /* index in Fortran <-> C translation array */ - - int f_f_to_c_index; - - /* Error handling. This field does not have the "f_" prefix so that - the OMPI_ERRHDL_* macros can find it, regardless of whether it's a - comm, window, or file. */ - - ompi_errhandler_t *error_handler; + OMPI_IO_VERSION_MAX }; +/** + * Convenience typedef + */ +typedef enum ompi_io_version_t ompi_io_version_t; + + +/* + * Flags + */ +#define OMPI_FILE_ISCLOSED 0x00000001 +#define OMPI_FILE_HIDDEN 0x00000002 + + +/** + * Back-end structure for MPI_File + */ +struct ompi_file_t { + ompi_object_t super; + /**< Base of OBJ_* interface */ + + ompi_communicator_t *f_comm; + /**< Communicator that this file was created with */ + + char *f_filename; + /**< Filename that this file was created with */ + + int f_amode; + /**< Amode that this file was created with */ + + int32_t f_flags; + /**< Bit flags */ + + int f_f_to_c_index; + /**< Index in Fortran <-> C translation array */ + + ompi_errhandler_t *error_handler; + /**< Error handler. This field does not have the "f_" prefix so + that the OMPI_ERRHDL_* macros can find it, regardless of + whether it's a comm, window, or file. */ + + ompi_io_version_t f_io_version; + /**< Indicate what version of the IO component we're using (this + indicates what member to look at in the union, below) */ + + union { + mca_io_base_module_1_0_0_t v1_0_0; + /**< IO v1.0.0 module */ + } f_io_selected_module; + /**< The selected module */ + + struct mca_io_base_file_t *f_selected_data; + /**< Allow the selected module to cache data on the file */ +}; +/** + * Convenience typedef + */ typedef struct ompi_file_t ompi_file_t; + +/** + * Back-end instances for MPI_FILE_NULL + */ +extern ompi_file_t ompi_mpi_file_null; + + +/** + * Fortran to C conversion table + */ +extern ompi_pointer_array_t ompi_file_f_to_c_table; + + + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif + /** + * Initialize MPI_File handling. + * + * @retval OMPI_SUCCESS Always. + * + * Invoked during ompi_mpi_init(). + */ + int ompi_file_init(void); + + /** + * Open a file handle. + * + * @param comm Communicator + * @param filename String filename + * @param amode Mode flags + * @param info Info + * @param fh Output file handle + * + * @retval OMPI_SUCCESS Upon success + * @retval OMPI_ERR* Upon error + * + * Create a file handle and select an io module to be paired with + * it. + */ + int ompi_file_open(ompi_communicator_t *comm, char *filename, + int amode, ompi_info_t *info, + ompi_file_t **fh); + + /** + * Atomicly set a name on a file handle. + * + * @param file MPI_File handle to set the name on + * @param name NULL-terminated string to use + * + * @returns OMPI_SUCCESS Always. + * + * At most (MPI_MAX_OBJECT_NAME-1) characters will be copied over to + * the file name's name. This function is performed atomically -- a + * lock is used to ensure that there are not multiple writers to the + * name to ensure that we don't end up with an erroneous name (e.g., + * a name without a \0 at the end). After invoking this function, + * ompi_file_is_name_set() will return true. + */ + int ompi_file_set_name(ompi_file_t *file, char *name); + + /** + * Close a file handle + * + * @param file MPI_File handle to set the name on + * + * @returns OMPI_SUCCESS Always. + * + * Close a file handle and free all resources associated with it. + */ + int ompi_file_close(ompi_file_t **file); + + /** + * Tear down MPI_File handling. + * + * @retval OMPI_SUCCESS Always. + * + * Invoked during ompi_mpi_finalize(). + */ + int ompi_file_finalize(void); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + + +/** + * Check to see if an MPI_File handle is valid. + * + * @param file The MPI file handle + * + * @retval true If the file handle is not valid + * @retval false If the file handle is valid + * + * This is a convenience function, mainly for error checking in + * top-level MPI API functions. + */ +static inline bool ompi_file_invalid(ompi_file_t *file) +{ + return (NULL == file || + &ompi_mpi_file_null == file || + 0 != (file->f_flags & OMPI_FILE_ISCLOSED)); +} + #endif /* OMPI_FILE_H */ diff --git a/src/info/info.c b/src/info/info.c index e688b40f47..d41ed4a84d 100644 --- a/src/info/info.c +++ b/src/info/info.c @@ -4,7 +4,7 @@ #include "info/info.h" #include "include/constants.h" -#include "mpi/runtime/mpiruntime.h" +#include "mpi/runtime/params.h" #include "util/output.h" @@ -17,11 +17,11 @@ ompi_info_t ompi_mpi_info_null; /* * Local functions */ -static void ompi_info_construct(ompi_info_t *info); -static void ompi_info_destruct(ompi_info_t *info); -static void ompi_info_entry_construct(ompi_info_entry_t *entry); -static void ompi_info_entry_destruct(ompi_info_entry_t *entry); -static ompi_info_entry_t *ompi_info_find_key (ompi_info_t *info, char *key); +static void info_constructor(ompi_info_t *info); +static void info_destructor(ompi_info_t *info); +static void info_entry_constructor(ompi_info_entry_t *entry); +static void info_entry_destructor(ompi_info_entry_t *entry); +static ompi_info_entry_t *info_find_key (ompi_info_t *info, char *key); /* @@ -29,21 +29,21 @@ static ompi_info_entry_t *ompi_info_find_key (ompi_info_t *info, char *key); */ OBJ_CLASS_INSTANCE(ompi_info_t, ompi_list_t, - ompi_info_construct, - ompi_info_destruct); + info_constructor, + info_destructor); /* * ompi_info_entry_t classes */ OBJ_CLASS_INSTANCE(ompi_info_entry_t, ompi_list_item_t, - ompi_info_entry_construct, - ompi_info_entry_destruct); + info_entry_constructor, + info_entry_destructor); /* * The global fortran <-> C translation table */ -ompi_pointer_array_t *ompi_info_f_to_c_table; +ompi_pointer_array_t ompi_info_f_to_c_table; /* @@ -54,15 +54,12 @@ int ompi_info_init(void) { /* initialize table */ - ompi_info_f_to_c_table = OBJ_NEW(ompi_pointer_array_t); - if (NULL == ompi_info_f_to_c_table) { - return OMPI_ERROR; - } + OBJ_CONSTRUCT(&ompi_info_f_to_c_table, ompi_pointer_array_t); /* Create MPI_INFO_NULL */ OBJ_CONSTRUCT(&ompi_mpi_info_null, ompi_info_t); - ompi_mpi_info_null.i_fhandle = 0; + ompi_mpi_info_null.i_f_to_c_index = 0; /* All done */ @@ -70,79 +67,6 @@ int ompi_info_init(void) } -/* - * Shut down MPI_Info handling - */ -int ompi_info_finalize(void) -{ - size_t i, max; - ompi_info_t *info; - ompi_list_item_t *item; - ompi_info_entry_t *entry; - bool found = false; - - /* Destroy MPI_INFO_NULL */ - - OBJ_DESTRUCT(&ompi_mpi_info_null); - - /* Go through the f2c table and see if anything is left. Free them - all. */ - - max = ompi_pointer_array_get_size(ompi_info_f_to_c_table); - for (i = 0; i < max; ++i) { - info = ompi_pointer_array_get_item(ompi_info_f_to_c_table, i); - - /* If the info was freed but still exists because the user told us - to never free handles, then do an OBJ_RELEASE it and all is - well. Then get the value again and see if it's actually been - freed. */ - - if (NULL != info && ompi_debug_handle_never_free && info->i_freed) { - OBJ_RELEASE(info); - info = ompi_pointer_array_get_item(ompi_info_f_to_c_table, i); - } - - /* If it still exists here and was never freed, then it's an - orphan */ - - if (NULL != info) { - - /* If the user wanted warnings about MPI object leaks, print out - a message */ - - if (!info->i_freed && ompi_debug_show_handle_leaks) { - if (ompi_debug_show_handle_leaks) { - ompi_output(0, "WARNING: MPI_Info still allocated at MPI_FINALIZE"); - for (item = ompi_list_get_first(&(info->super)); - ompi_list_get_end(&(info->super)) != item; - item = ompi_list_get_next(item)) { - entry = (ompi_info_entry_t *) item; - ompi_output(0, "WARNING: key=\"%s\", value=\"%s\"", - entry->ie_key, - NULL != entry->ie_value ? entry->ie_value : "(null)"); - found = true; - } - } - OBJ_RELEASE(info); - } - - /* Don't bother setting each element back down to NULL; it would - just take a lot of thread locks / unlocks and since we're - destroying everything, it isn't worth it */ - - if (!found && ompi_debug_show_handle_leaks) { - ompi_output(0, "WARNING: (no keys)"); - } - } - } - - /* All done -- release the table */ - - OBJ_RELEASE(ompi_info_f_to_c_table); - return OMPI_SUCCESS; -} - - /* * Duplicate an info */ @@ -183,7 +107,7 @@ int ompi_info_set (ompi_info_t *info, char *key, char *value) } OMPI_THREAD_LOCK(info->i_lock); - old_info = ompi_info_find_key (info, key); + old_info = info_find_key (info, key); if (NULL != old_info) { /* * key already exists. remove the value associated with it @@ -227,7 +151,7 @@ int ompi_info_get (ompi_info_t *info, char *key, int valuelen, int value_length; OMPI_THREAD_LOCK(info->i_lock); - search = ompi_info_find_key (info, key); + search = info_find_key (info, key); if (NULL == search){ *flag = 0; } else { @@ -263,7 +187,7 @@ int ompi_info_delete (ompi_info_t *info, char *key) ompi_info_entry_t *found; OMPI_THREAD_LOCK(info->i_lock); - search = ompi_info_find_key (info, key); + search = info_find_key (info, key); if (NULL == search){ OMPI_THREAD_UNLOCK(info->i_lock); return MPI_ERR_INFO_NOKEY; @@ -291,7 +215,7 @@ int ompi_info_get_valuelen (ompi_info_t *info, char *key, int *valuelen, ompi_info_entry_t *search; OMPI_THREAD_LOCK(info->i_lock); - search = ompi_info_find_key (info, key); + search = info_find_key (info, key); if (NULL == search){ *flag = 0; } else { @@ -339,21 +263,98 @@ int ompi_info_get_nthkey (ompi_info_t *info, int n, char *key) } +/* + * Shut down MPI_Info handling + */ +int ompi_info_finalize(void) +{ + size_t i, max; + ompi_info_t *info; + ompi_list_item_t *item; + ompi_info_entry_t *entry; + bool found = false; + + /* Release MPI_INFO_NULL. Do this so that we don't get a bogus + leak report on it. Plus, it's statically allocated, so we + don't want to call OBJ_RELEASE on it. */ + + OBJ_DESTRUCT(&ompi_mpi_info_null); + ompi_pointer_array_set_item(&ompi_info_f_to_c_table, 0, NULL); + + /* Go through the f2c table and see if anything is left. Free them + all. */ + + max = ompi_pointer_array_get_size(&ompi_info_f_to_c_table); + for (i = 0; i < max; ++i) { + info = ompi_pointer_array_get_item(&ompi_info_f_to_c_table, i); + + /* If the info was freed but still exists because the user + told us to never free handles, then do an OBJ_RELEASE it + and all is well. Then get the value again and see if it's + actually been freed. */ + + if (NULL != info && ompi_debug_no_free_handles && info->i_freed) { + OBJ_RELEASE(info); + info = ompi_pointer_array_get_item(&ompi_info_f_to_c_table, i); + } + + /* If it still exists here and was never freed, then it's an + orphan */ + + if (NULL != info) { + + /* If the user wanted warnings about MPI object leaks, print out + a message */ + + if (!info->i_freed && ompi_debug_show_handle_leaks) { + if (ompi_debug_show_handle_leaks) { + ompi_output(0, "WARNING: MPI_Info still allocated at MPI_FINALIZE"); + for (item = ompi_list_get_first(&(info->super)); + ompi_list_get_end(&(info->super)) != item; + item = ompi_list_get_next(item)) { + entry = (ompi_info_entry_t *) item; + ompi_output(0, "WARNING: key=\"%s\", value=\"%s\"", + entry->ie_key, + NULL != entry->ie_value ? entry->ie_value : "(null)"); + found = true; + } + } + OBJ_RELEASE(info); + } + + /* Don't bother setting each element back down to NULL; it + would just take a lot of thread locks / unlocks and + since we're destroying everything, it isn't worth it */ + + if (!found && ompi_debug_show_handle_leaks) { + ompi_output(0, "WARNING: (no keys)"); + } + } + } + + /* All done -- destroy the table */ + + OBJ_DESTRUCT(&ompi_info_f_to_c_table); + return OMPI_SUCCESS; +} + + /* * This function is invoked when OBJ_NEW() is called. Here, we add this * info pointer to the table and then store its index as the handle */ -static void ompi_info_construct(ompi_info_t *info) +static void info_constructor(ompi_info_t *info) { - info->i_fhandle = ompi_pointer_array_add(ompi_info_f_to_c_table, info); + info->i_f_to_c_index = ompi_pointer_array_add(&ompi_info_f_to_c_table, + info); info->i_lock = OBJ_NEW(ompi_mutex_t); info->i_freed = false; /* If the user doesn't want us to ever free it, then add an extra RETAIN here */ - if (ompi_debug_handle_never_free) { - OBJ_RETAIN(&(info->super)); + if (ompi_debug_no_free_handles) { + OBJ_RETAIN(&(info->super)); } } @@ -363,45 +364,50 @@ static void ompi_info_construct(ompi_info_t *info) * done, we need to remove the entry from the ompi fortran to C * translation table */ -static void ompi_info_destruct(ompi_info_t *info) +static void info_destructor(ompi_info_t *info) { - ompi_list_item_t *item; - ompi_info_entry_t *iterator; + ompi_list_item_t *item; + ompi_info_entry_t *iterator; - /* Remove every key in the list */ + /* Remove every key in the list */ - for (item = ompi_list_remove_first(&(info->super)); - NULL != item; - item = ompi_list_remove_first(&(info->super))) { - iterator = (ompi_info_entry_t *) item; - OBJ_RELEASE(iterator); - } + for (item = ompi_list_remove_first(&(info->super)); + NULL != item; + item = ompi_list_remove_first(&(info->super))) { + iterator = (ompi_info_entry_t *) item; + OBJ_RELEASE(iterator); + } - /* reset the ompi_info_f_to_c_table entry - make sure that the - entry is in the table */ + /* reset the &ompi_info_f_to_c_table entry - make sure that the + entry is in the table */ + + if (MPI_UNDEFINED != info->i_f_to_c_index && + NULL != ompi_pointer_array_get_item(&ompi_info_f_to_c_table, + info->i_f_to_c_index)){ + ompi_pointer_array_set_item(&ompi_info_f_to_c_table, + info->i_f_to_c_index, NULL); + } - if (NULL != ompi_pointer_array_get_item(ompi_info_f_to_c_table, - info->i_fhandle)){ - ompi_pointer_array_set_item(ompi_info_f_to_c_table, - info->i_fhandle, NULL); - } + /* Release the lock */ + + OBJ_RELEASE(info->i_lock); } /* * ompi_info_entry_t interface functions */ -static void ompi_info_entry_construct(ompi_info_entry_t *entry) +static void info_entry_constructor(ompi_info_entry_t *entry) { memset(entry->ie_key, 0, sizeof(entry->ie_key)); entry->ie_key[MPI_MAX_INFO_KEY] = 0; } -static void ompi_info_entry_destruct(ompi_info_entry_t *entry) +static void info_entry_destructor(ompi_info_entry_t *entry) { if (NULL != entry->ie_value) { - free(entry->ie_value); + free(entry->ie_value); } } @@ -412,7 +418,7 @@ static void ompi_info_entry_destruct(ompi_info_entry_t *entry) * Do NOT thread lock in here -- the calling function is responsible * for that. */ -static ompi_info_entry_t *ompi_info_find_key (ompi_info_t *info, char *key) +static ompi_info_entry_t *info_find_key (ompi_info_t *info, char *key) { ompi_info_entry_t *iterator; @@ -431,6 +437,3 @@ static ompi_info_entry_t *ompi_info_find_key (ompi_info_t *info, char *key) } return NULL; } - - - diff --git a/src/info/info.h b/src/info/info.h index dd7a1db832..25015b27b8 100644 --- a/src/info/info.h +++ b/src/info/info.h @@ -23,7 +23,7 @@ struct ompi_info_t { ompi_list_t super; /**< generic list pointer which is the container for (key,value) pairs */ - int i_fhandle; + int i_f_to_c_index; /**< fortran handle for info. This is needed for translation from fortran to C and vice versa */ ompi_mutex_t *i_lock; @@ -59,7 +59,7 @@ typedef struct ompi_info_entry_t ompi_info_entry_t; /** * Table for Fortran <-> C translation table */ -extern ompi_pointer_array_t *ompi_info_f_to_c_table; +extern ompi_pointer_array_t ompi_info_f_to_c_table; /** * Global instance for MPI_INFO_NULL diff --git a/src/mca/io/base/Makefile.am b/src/mca/io/base/Makefile.am index 34c0ea958b..0721c4e5bf 100644 --- a/src/mca/io/base/Makefile.am +++ b/src/mca/io/base/Makefile.am @@ -4,7 +4,21 @@ include $(top_srcdir)/config/Makefile.options -# For VPATH builds, have to specify where static-modules.h will be found +noinst_LTLIBRARIES = libmca_io_base.la -AM_CPPFLAGS = -I$(top_builddir)/src +headers = \ + base.h +libmca_io_base_la_SOURCES = \ + $(headers) \ + io_base_close.c \ + io_base_open.c + +# Conditionally install the header files + +if WANT_INSTALL_HEADERS +ompidir = $(includedir)/openmpi/mca/io/base +ompi_HEADERS = $(headers) +else +ompidir = $(includedir) +endif diff --git a/src/mca/io/base/base.h b/src/mca/io/base/base.h new file mode 100644 index 0000000000..66452c3842 --- /dev/null +++ b/src/mca/io/base/base.h @@ -0,0 +1,25 @@ +/* + * $HEADER$ + */ + +#ifndef OMPI_MCA_IO_BASE_H +#define OMPI_MCA_IO_BASE_H + +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif + /** + * To be filled in soon + */ + int mca_io_base_open(void); + + /** + * To be filled in soon + */ + int mca_io_base_close(void); + +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif + +#endif /* OMPI_MCA_IO_BASE_H */ diff --git a/src/mca/io/base/io_base_close.c b/src/mca/io/base/io_base_close.c new file mode 100644 index 0000000000..ed5ab76a73 --- /dev/null +++ b/src/mca/io/base/io_base_close.c @@ -0,0 +1,15 @@ +/* + * $HEADER$ + */ + +#include "ompi_config.h" + +#include "include/constants.h" +#include "mca/io/base/base.h" + + +int mca_io_base_close(void) +{ + /* JMS More coming here soon */ + return OMPI_SUCCESS; +} diff --git a/src/mca/io/base/io_base_open.c b/src/mca/io/base/io_base_open.c new file mode 100644 index 0000000000..627c9501fb --- /dev/null +++ b/src/mca/io/base/io_base_open.c @@ -0,0 +1,15 @@ +/* + * $HEADER$ + */ + +#include "ompi_config.h" + +#include "include/constants.h" +#include "mca/io/base/base.h" + + +int mca_io_base_open(void) +{ + /* JMS More coming here soon */ + return OMPI_SUCCESS; +} diff --git a/src/mpi/c/file_c2f.c b/src/mpi/c/file_c2f.c index 107d1f64a7..a981332920 100644 --- a/src/mpi/c/file_c2f.c +++ b/src/mpi/c/file_c2f.c @@ -8,6 +8,7 @@ #include "mpi/c/bindings.h" #include "communicator/communicator.h" #include "errhandler/errhandler.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_c2f = PMPI_File_c2f @@ -22,11 +23,14 @@ static const char FUNC_NAME[] = "MPI_File_c2f"; MPI_Fint MPI_File_c2f(MPI_File file) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - } - - /* This function is not yet implemented */ - - return (MPI_Fint) OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + if (ompi_file_invalid(file)) { + return (MPI_Fint) OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, + MPI_ERR_FILE, + FUNC_NAME); + } + } + + return (MPI_Fint) file->f_f_to_c_index; } diff --git a/src/mpi/c/file_close.c b/src/mpi/c/file_close.c index 8436f928e9..b5e1af181b 100644 --- a/src/mpi/c/file_close.c +++ b/src/mpi/c/file_close.c @@ -8,6 +8,7 @@ #include "mpi/c/bindings.h" #include "communicator/communicator.h" #include "errhandler/errhandler.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_close = PMPI_File_close @@ -22,11 +23,21 @@ static const char FUNC_NAME[] = "MPI_File_close"; int MPI_File_close(MPI_File *fh) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - } + int rc; - /* This function is not yet implemented */ + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + /* Note that MPI-2:9.7 (p265) says that errors in + MPI_FILE_CLOSE should invoke the default error handler on + MPI_FILE_NULL */ + + if (NULL == fh || ompi_file_invalid(*fh)) { + return OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, MPI_ERR_FILE, + FUNC_NAME); + } + } + + rc = ompi_file_close(fh); + OMPI_ERRHANDLER_RETURN(rc, *fh, rc, FUNC_NAME); } diff --git a/src/mpi/c/file_delete.c b/src/mpi/c/file_delete.c index f03906268e..e3ae2b3621 100644 --- a/src/mpi/c/file_delete.c +++ b/src/mpi/c/file_delete.c @@ -9,6 +9,7 @@ #include "communicator/communicator.h" #include "errhandler/errhandler.h" #include "info/info.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_delete = PMPI_File_delete @@ -23,15 +24,18 @@ static const char FUNC_NAME[] = "MPI_File_delete"; int MPI_File_delete(char *filename, MPI_Info info) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - if (NULL == info || ompi_info_is_freed(info)) { - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INFO, - FUNC_NAME); + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + if (NULL == info || ompi_info_is_freed(info)) { + return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INFO, + FUNC_NAME); + } } - } - /* This function is not yet implemented */ + /* Note that MPI-2:9.7 (p265) says that errors in MPI_FILE_DELETE + should invoke the default error handler on MPI_FILE_NULL */ - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + /* This function is not yet implemented */ + + return OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, MPI_ERR_INTERN, FUNC_NAME); } diff --git a/src/mpi/c/file_f2c.c b/src/mpi/c/file_f2c.c index 618e8401cb..62c47e6dfd 100644 --- a/src/mpi/c/file_f2c.c +++ b/src/mpi/c/file_f2c.c @@ -8,6 +8,7 @@ #include "mpi/c/bindings.h" #include "communicator/communicator.h" #include "errhandler/errhandler.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_f2c = PMPI_File_f2c @@ -20,13 +21,19 @@ static const char FUNC_NAME[] = "MPI_File_f2c"; -MPI_File MPI_File_f2c(MPI_Fint file) +MPI_File MPI_File_f2c(MPI_Fint file_f) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - } + size_t file_index = (size_t) file_f; - /* This function is not yet implemented */ + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + if (file_index < 0 || + file_index >= ompi_pointer_array_get_size(&ompi_file_f_to_c_table)) { + (void) OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, MPI_ERR_FILE, + FUNC_NAME); + return MPI_FILE_NULL; + } + } - return (MPI_File) OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + return ompi_file_f_to_c_table.addr[file_index]; } diff --git a/src/mpi/c/file_open.c b/src/mpi/c/file_open.c index 5db7b7cd56..4f20f4f63e 100644 --- a/src/mpi/c/file_open.c +++ b/src/mpi/c/file_open.c @@ -9,6 +9,7 @@ #include "communicator/communicator.h" #include "errhandler/errhandler.h" #include "info/info.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_open = PMPI_File_open @@ -24,15 +25,26 @@ static const char FUNC_NAME[] = "MPI_File_open"; int MPI_File_open(MPI_Comm comm, char *filename, int amode, MPI_Info info, MPI_File *fh) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - if (NULL == info || ompi_info_is_freed(info)) { - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INFO, - FUNC_NAME); + int rc; + + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + if (NULL == info || ompi_info_is_freed(info)) { + return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INFO, + FUNC_NAME); + } else if (ompi_comm_invalid(comm)) { + return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_COMM, + FUNC_NAME); + } } - } - /* This function is not yet implemented */ + /* Note that MPI-2:9.7 (p265) says that errors in MPI_FILE_OPEN + (before the file handle is created) should invoke the default + error handler on MPI_FILE_NULL. Hence, if we get a file handle + out of ompi_file_open(), invoke the error handler on that. If + not, invoke the error handler on MPI_FILE_NULL. */ - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + *fh = MPI_FILE_NULL; + rc = ompi_file_open(comm, filename, amode, info, fh); + OMPI_ERRHANDLER_RETURN(rc, *fh, rc, FUNC_NAME); } diff --git a/src/mpi/c/file_read.c b/src/mpi/c/file_read.c index f3a39e269e..49c27cd733 100644 --- a/src/mpi/c/file_read.c +++ b/src/mpi/c/file_read.c @@ -8,6 +8,7 @@ #include "mpi/c/bindings.h" #include "communicator/communicator.h" #include "errhandler/errhandler.h" +#include "file/file.h" #if OMPI_HAVE_WEAK_SYMBOLS && OMPI_PROFILING_DEFINES #pragma weak MPI_File_read = PMPI_File_read @@ -23,11 +24,15 @@ static const char FUNC_NAME[] = "MPI_File_read"; int MPI_File_read(MPI_File fh, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) { - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - } + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + if (ompi_file_invalid(fh)) { + return OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, MPI_ERR_FILE, + FUNC_NAME); + } + } - /* This function is not yet implemented */ - - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); + /* This function is not yet implemented */ + + return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INTERN, FUNC_NAME); } diff --git a/src/mpi/c/file_set_errhandler.c b/src/mpi/c/file_set_errhandler.c index 257619babc..fe9e5da66a 100644 --- a/src/mpi/c/file_set_errhandler.c +++ b/src/mpi/c/file_set_errhandler.c @@ -23,31 +23,34 @@ static const char FUNC_NAME[] = "MPI_File_set_errhandler"; int MPI_File_set_errhandler( MPI_File file, MPI_Errhandler errhandler) { - /* Error checking */ + /* Error checking */ - if (MPI_PARAM_CHECK) { - OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - if (NULL == file || - MPI_FILE_NULL == file) { - return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_FILE, - FUNC_NAME); - } else if (NULL == errhandler || - MPI_ERRHANDLER_NULL == errhandler || - OMPI_ERRHANDLER_TYPE_FILE != errhandler->eh_mpi_object_type) { - return OMPI_ERRHANDLER_INVOKE(file, MPI_ERR_ARG, FUNC_NAME); + if (MPI_PARAM_CHECK) { + OMPI_ERR_INIT_FINALIZE(FUNC_NAME); + + /* Note that MPI-2:9.7 (p265) explicitly says that you are + allowed to set the error handler on MPI_FILE_NULL */ + + if (NULL == file) { + return OMPI_ERRHANDLER_INVOKE(MPI_FILE_NULL, MPI_ERR_FILE, + FUNC_NAME); + } else if (NULL == errhandler || + MPI_ERRHANDLER_NULL == errhandler || + OMPI_ERRHANDLER_TYPE_FILE != errhandler->eh_mpi_object_type) { + return OMPI_ERRHANDLER_INVOKE(file, MPI_ERR_ARG, FUNC_NAME); + } } - } - /* Ditch the old errhandler, and decrement its refcount */ + /* Ditch the old errhandler, and decrement its refcount */ - OBJ_RELEASE(file->error_handler); + OBJ_RELEASE(file->error_handler); - /* We have a valid comm and errhandler, so increment its refcount */ + /* We have a valid comm and errhandler, so increment its refcount */ - file->error_handler = errhandler; - OBJ_RETAIN(file->error_handler); + file->error_handler = errhandler; + OBJ_RETAIN(file->error_handler); - /* All done */ + /* All done */ - return MPI_SUCCESS; + return MPI_SUCCESS; } diff --git a/src/mpi/c/info_c2f.c b/src/mpi/c/info_c2f.c index ffc4c0f4f4..80de8763c1 100644 --- a/src/mpi/c/info_c2f.c +++ b/src/mpi/c/info_c2f.c @@ -45,5 +45,5 @@ MPI_Fint MPI_Info_c2f(MPI_Info info) } /* return the index */ - return (MPI_Fint)(info->i_fhandle); + return (MPI_Fint)(info->i_f_to_c_index); } diff --git a/src/mpi/c/info_f2c.c b/src/mpi/c/info_f2c.c index 6c0a30118d..3838a88a08 100644 --- a/src/mpi/c/info_f2c.c +++ b/src/mpi/c/info_f2c.c @@ -30,15 +30,20 @@ static const char FUNC_NAME[] = "MPI_Info_f2c"; */ MPI_Info MPI_Info_f2c(MPI_Fint info) { + size_t info_index = (size_t) info; + /* check the arguments */ + if (MPI_PARAM_CHECK) { OMPI_ERR_INIT_FINALIZE(FUNC_NAME); - if (0 > info || - info >= ompi_pointer_array_get_size(ompi_info_f_to_c_table)) { + if (info_index < 0 || + info_index >= ompi_pointer_array_get_size(&ompi_info_f_to_c_table)) { + (void) OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_INFO, + FUNC_NAME); return MPI_INFO_NULL; } } /* return the index */ - return ompi_info_f_to_c_table->addr[info]; + return ompi_info_f_to_c_table.addr[info_index]; } diff --git a/src/mpi/runtime/Makefile.am b/src/mpi/runtime/Makefile.am index b344dcb8f3..c616ee762a 100644 --- a/src/mpi/runtime/Makefile.am +++ b/src/mpi/runtime/Makefile.am @@ -12,12 +12,14 @@ noinst_LTLIBRARIES = libmpiruntime.la # Source code files headers = \ - mpiruntime.h + mpiruntime.h \ + params.h libmpiruntime_la_SOURCES = \ $(headers) \ ompi_mpi_init.c \ - ompi_mpi_finalize.c + ompi_mpi_finalize.c \ + ompi_mpi_params.c # Conditionally install the header files diff --git a/src/mpi/runtime/mpiruntime.h b/src/mpi/runtime/mpiruntime.h index 82d670d734..fdf188ed47 100644 --- a/src/mpi/runtime/mpiruntime.h +++ b/src/mpi/runtime/mpiruntime.h @@ -8,8 +8,8 @@ * Interface into the MPI portion of the Open MPI Run Time Environment */ -#ifndef OMPI_MPIRUNTIME_H -#define OMPI_MPIRUNTIME_H +#ifndef OMPI_MPI_MPIRUNTIME_H +#define OMPI_MPI_MPIRUNTIME_H #include "ompi_config.h" @@ -20,10 +20,6 @@ extern bool ompi_mpi_initialized; extern bool ompi_mpi_finalized; -extern bool ompi_mpi_param_check; -extern bool ompi_debug_show_handle_leaks; -extern bool ompi_debug_handle_never_free; - extern bool ompi_mpi_thread_multiple; extern int ompi_mpi_thread_requested; extern int ompi_mpi_thread_provided; @@ -36,16 +32,29 @@ extern "C" { /** * Initialize the Open MPI MPI environment * + * @param argc argc, typically from main() (IN) + * @param argv argv, typically from main() (IN) + * @param requested Thread support that is requested (IN) + * @param provided Thread support that is provided (OUT) + * + * @returns MPI_SUCCESS if successful + * @returns Error code if unsuccessful + * * Intialize all support code needed for MPI applications. This * function should only be called by MPI applications (including - * singletons). If this function is called, ompi_init and - * ompi_rte_init should *not* be called. + * singletons). If this function is called, ompi_init() and + * ompi_rte_init() should *not* be called. + * + * It is permissable to pass in (0, NULL) for (argc, argv). */ int ompi_mpi_init(int argc, char **argv, int requested, int *provided); /** * Finalize the Open MPI MPI environment * + * @returns MPI_SUCCESS if successful + * @returns Error code if unsuccessful + * * Should be called after all MPI functionality is complete (usually * during MPI_FINALIZE). */ @@ -55,4 +64,4 @@ extern "C" { } #endif -#endif /* OMPI_MPIRUNTIME_H */ +#endif /* OMPI_MPI_MPIRUNTIME_H */ diff --git a/src/mpi/runtime/ompi_mpi_finalize.c b/src/mpi/runtime/ompi_mpi_finalize.c index 0a4419033f..627dfa3d18 100644 --- a/src/mpi/runtime/ompi_mpi_finalize.c +++ b/src/mpi/runtime/ompi_mpi_finalize.c @@ -12,8 +12,10 @@ #include "communicator/communicator.h" #include "datatype/datatype.h" #include "op/op.h" +#include "file/file.h" #include "info/info.h" #include "runtime/runtime.h" + #include "mca/base/base.h" #include "mca/ptl/ptl.h" #include "mca/ptl/base/base.h" @@ -21,6 +23,10 @@ #include "mca/pml/base/base.h" #include "mca/coll/coll.h" #include "mca/coll/base/base.h" +#include "mca/topo/topo.h" +#include "mca/topo/base/base.h" +#include "mca/io/io.h" +#include "mca/io/base/base.h" int ompi_mpi_finalize(void) @@ -34,15 +40,18 @@ int ompi_mpi_finalize(void) /* Free communication objects */ + /* free window resources */ + + /* free file resources */ + if (OMPI_SUCCESS != (ret = ompi_file_finalize())) { + return ret; + } + /* free communicator resources */ if (OMPI_SUCCESS != (ret = ompi_comm_finalize())) { return ret; } - /* free window resources */ - - /* free file resources */ - /* Free secondary resources */ /* free group resources */ @@ -76,6 +85,12 @@ int ompi_mpi_finalize(void) /* Close down MCA modules */ + if (OMPI_SUCCESS != (ret = mca_io_base_close())) { + return ret; + } + if (OMPI_SUCCESS != (ret = mca_topo_base_close())) { + return ret; + } if (OMPI_SUCCESS != (ret = mca_coll_base_close())) { return ret; } diff --git a/src/mpi/runtime/ompi_mpi_init.c b/src/mpi/runtime/ompi_mpi_init.c index cc87bc6cb6..8dbb97626d 100644 --- a/src/mpi/runtime/ompi_mpi_init.c +++ b/src/mpi/runtime/ompi_mpi_init.c @@ -5,11 +5,12 @@ #include "ompi_config.h" #include "include/constants.h" +#include "mpi/runtime/mpiruntime.h" +#include "mpi/runtime/params.h" #include "runtime/runtime.h" #include "util/sys_info.h" #include "util/proc_info.h" #include "mpi.h" -#include "runtime/runtime.h" #include "communicator/communicator.h" #include "group/group.h" #include "info/info.h" @@ -19,6 +20,8 @@ #include "errhandler/errclass.h" #include "errhandler/errcode-internal.h" #include "op/op.h" +#include "file/file.h" + #include "mca/base/base.h" #include "mca/base/base.h" #include "mca/allocator/base/base.h" @@ -33,6 +36,8 @@ #include "mca/coll/base/base.h" #include "mca/topo/topo.h" #include "mca/topo/base/base.h" +#include "mca/io/io.h" +#include "mca/io/base/base.h" /* @@ -42,13 +47,6 @@ bool ompi_mpi_initialized = false; bool ompi_mpi_finalized = false; -/* As a deviation from the norm, ompi_mpi_param_check is extern'ed in - src/mpi/interface/c/bindings.h because it is already included in - all MPI function imlementation files */ -bool ompi_mpi_param_check = true; -bool ompi_debug_show_handle_leaks = false; -bool ompi_debug_handle_never_free = false; - bool ompi_mpi_thread_multiple = false; int ompi_mpi_thread_requested = MPI_THREAD_SINGLE; int ompi_mpi_thread_provided = MPI_THREAD_SINGLE; @@ -56,7 +54,7 @@ int ompi_mpi_thread_provided = MPI_THREAD_SINGLE; int ompi_mpi_init(int argc, char **argv, int requested, int *provided) { - int ret, param, value; + int ret, param; bool allow_multi_user_threads; bool have_hidden_threads; ompi_proc_t** procs; @@ -94,6 +92,15 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided) return ret; } + /* Once we've joined the RTE, see if any MCA parameters were + passed to the MPI level */ + + if (OMPI_SUCCESS != (ret = ompi_mpi_register_params())) { + /* JMS show_help */ + printf("show_help: ompi_mpi_init failed in mca_mpi_register_params\n"); + return ret; + } + /* initialize ompi procs */ if (OMPI_SUCCESS != (ret = ompi_proc_init())) { /* JMS show_help */ @@ -101,36 +108,41 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided) return ret; } - /* Open up relevant MCA modules. Do not open io, topo, or one - module types here -- they are loaded upon demand (i.e., upon - relevant constructors). */ + /* Open up relevant MCA modules. */ + if (OMPI_SUCCESS != (ret = mca_allocator_base_open())) { /* JMS show_help */ - printf("show_help: ompi_mpi_init failed in mca_allocator_base_init\n"); + printf("show_help: ompi_mpi_init failed in mca_allocator_base_open\n"); return ret; } if (OMPI_SUCCESS != (ret = mca_mpool_base_open())) { /* JMS show_help */ - printf("show_help: ompi_mpi_init failed in mca_mpool_base_init\n"); + printf("show_help: ompi_mpi_init failed in mca_mpool_base_open\n"); return ret; } if (OMPI_SUCCESS != (ret = mca_pml_base_open())) { /* JMS show_help */ - printf("show_help: ompi_mpi_init failed in mca_pml_base_init\n"); + printf("show_help: ompi_mpi_init failed in mca_pml_base_open\n"); return ret; } if (OMPI_SUCCESS != (ret = mca_ptl_base_open())) { /* JMS show_help */ - printf("show_help: ompi_mpi_init failed in mca_ptl_base_init\n"); + printf("show_help: ompi_mpi_init failed in mca_ptl_base_open\n"); return ret; } if (OMPI_SUCCESS != (ret = mca_coll_base_open())) { /* JMS show_help */ - printf("show_help: ompi_mpi_init failed in mca_coll_base_init\n"); + printf("show_help: ompi_mpi_init failed in mca_coll_base_open\n"); return ret; } if (OMPI_SUCCESS != (ret = mca_topo_base_open())) { /* JMS show_help */ + printf("show_help: ompi_mpi_init failed in mca_topo_base_open\n"); + return ret; + } + if (OMPI_SUCCESS != (ret = mca_io_base_open())) { + /* JMS show_help */ + printf("show_help: ompi_mpi_init failed in mca_io_base_open\n"); return ret; } @@ -216,12 +228,12 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided) return ret; } - /* If we have run-time MPI parameter checking possible, register - an MCA paramter to find out if the user wants it on or off by - default */ - param = mca_base_param_register_int("mpi", NULL, "error_check", NULL, 1); - mca_base_param_lookup_int(param, &value); - ompi_mpi_param_check = (bool) value; + /* initialize file handles */ + if (OMPI_SUCCESS != (ret = ompi_file_init())) { + /* JMS show_help */ + printf("show_help: ompi_mpi_init failed in ompi_file_init\n"); + return ret; + } /* do module exchange */ if (OMPI_SUCCESS != (ret = mca_base_modex_exchange())) { diff --git a/src/mpi/runtime/ompi_mpi_params.c b/src/mpi/runtime/ompi_mpi_params.c new file mode 100644 index 0000000000..dc58827b9c --- /dev/null +++ b/src/mpi/runtime/ompi_mpi_params.c @@ -0,0 +1,63 @@ +/* + * $HEADER$ + */ + +#include "ompi_config.h" + +#include "include/constants.h" +#include "mpi/runtime/mpiruntime.h" +#include "mpi/runtime/params.h" +#include "mca/base/mca_base_param.h" + + +/* + * Global variables + * + * As a deviation from the norm, ompi_mpi_param_check is also + * extern'ed in src/mpi/interface/c/bindings.h because it is already + * included in all MPI function imlementation files + * + * The values below are the default values. + */ +bool ompi_mpi_param_check = true; +bool ompi_debug_show_handle_leaks = false; +bool ompi_debug_no_free_handles = false; + + +int ompi_mpi_register_params(void) +{ + int param_check_param; + int show_leaks_param; + int no_free_param; + int value; + + param_check_param = + mca_base_param_register_int("base", "mpi", "param_check", + "mpi_param_check", + (int) ompi_mpi_param_check); + mca_base_param_lookup_int(param_check_param, &value); + ompi_mpi_param_check = (bool) value; + + /* Whether or not to show MPI handle leaks */ + + show_leaks_param = + mca_base_param_register_int("base", "mpi", "show_handle_leaks", + "mpi_show_handle_leaks", + (int) ompi_debug_show_handle_leaks); + mca_base_param_lookup_int(show_leaks_param, &value); + ompi_debug_show_handle_leaks = (bool) value; + + /* Whether or not to free MPI handles */ + + no_free_param = + mca_base_param_register_int("base", "mpi", "no_free_handles", + "mpi_no_free_handles", + (int) ompi_debug_no_free_handles); + mca_base_param_lookup_int(no_free_param, &value); + ompi_debug_no_free_handles = (bool) value; + + /* All done */ + + return OMPI_SUCCESS; +} + diff --git a/src/mpi/runtime/params.h b/src/mpi/runtime/params.h new file mode 100644 index 0000000000..dfef8b7278 --- /dev/null +++ b/src/mpi/runtime/params.h @@ -0,0 +1,68 @@ +/* + * $HEADER$ + */ + +#ifndef OMPI_RUNTIME_PARAMS_H +#define OMPI_RUNTIME_PARAMS_H + +/* + * Global variables + */ + +/** + * Whether or not to check the parameters of top-level MPI API + * functions or not. + * + * This variable should never be checked directly; the macro + * MPI_PARAM_CHECK should be used instead. This allows multiple + * levels of MPI function parameter checking: + * + * #- Disable all parameter checking at configure/compile time + * #- Enable all parameter checking at configure/compile time + * #- Disable all parameter checking at run time + * #- Enable all parameter checking at run time + * + * Hence, the MPI_PARAM_CHECK macro will either be "0", "1", or + * "ompi_mpi_param_check". + */ +extern bool ompi_mpi_param_check; + +/** + * Whether or not to check for MPI handle leaks during MPI_FINALIZE. + * If enabled, each MPI handle type will display a summary of the + * handles that are still allocated during MPI_FINALIZE. + * + * This is good debugging for user applications to find out if they + * are inadvertantly orphaning MPI handles. + */ +extern bool ompi_debug_show_handle_leaks; + +/** + * Whether or not to actually free MPI handles when their + * corresponding destructor is invoked. If enabled, Open MPI will not + * free handles, but will rather simply mark them as "freed". Any + * attempt to use them will result in an MPI exception. + * + * This is good debugging for user applications to find out if they + * are inadvertantly using MPI handles after they have been freed. + */ +extern bool ompi_debug_no_free_handles; + + +#ifdef __cplusplus +extern "C" { +#endif + /** + * Register MCA parameters used by the MPI layer. + * + * @returns OMPI_SUCCESS + * + * Registers several MCA parameters and initializes corresponding + * global variables to the values obtained from the MCA system. + */ + int ompi_mpi_register_params(void); +#ifdef __cplusplus +} +#endif + +#endif /* OMPI_RUNTIME_PARAMS_H */ diff --git a/src/tools/ompi_info/components.cc b/src/tools/ompi_info/components.cc index 8948172e04..42ead4d74a 100644 --- a/src/tools/ompi_info/components.cc +++ b/src/tools/ompi_info/components.cc @@ -10,6 +10,7 @@ #include #include +#include "mpi/runtime/params.h" #include "mca/base/base.h" #include "mca/allocator/allocator.h" #include "mca/allocator/base/base.h" @@ -80,6 +81,10 @@ void ompi_info::open_components() } } + // Register the MPI layer's MCA parameters + + ompi_mpi_register_params(); + // Find / open all components mca_base_open();