diff options
-rw-r--r-- | var/spack/packages/mpibash/mpibash-4.3.patch | 1565 | ||||
-rw-r--r-- | var/spack/packages/mpibash/package.py | 32 |
2 files changed, 1597 insertions, 0 deletions
diff --git a/var/spack/packages/mpibash/mpibash-4.3.patch b/var/spack/packages/mpibash/mpibash-4.3.patch new file mode 100644 index 0000000000..17e285b0bf --- /dev/null +++ b/var/spack/packages/mpibash/mpibash-4.3.patch @@ -0,0 +1,1565 @@ +diff -Naur bash-4.3/builtins/circle.def mpibash-4.3/builtins/circle.def +--- bash-4.3/builtins/circle.def 1969-12-31 17:00:00.000000000 -0700 ++++ mpibash-4.3/builtins/circle.def 2014-05-13 11:27:37.314100671 -0600 +@@ -0,0 +1,620 @@ ++This file is circle.def, from which is created circle.c. ++It implements all of the "circle_*" builtins in Bash. ++ ++$PRODUCES circle.c ++ ++#include <config.h> ++ ++#include <stdio.h> ++#if defined (HAVE_UNISTD_H) ++# ifdef _MINIX ++# include <sys/types.h> ++# endif ++# include <unistd.h> ++#endif ++ ++#include "../bashintl.h" ++#include "../shell.h" ++#include "common.h" ++#include "bashgetopt.h" ++#include <libcircle.h> ++ ++extern int running_trap, trap_saved_exit_value; ++ ++static int circle_rank; /* Rank in the Libcircle job */ ++static SHELL_VAR *create_func = NULL; /* User-defined callback function for CIRCLE_cb_create. */ ++static SHELL_VAR *process_func = NULL; /* User-defined callback function for CIRCLE_cb_process. */ ++static SHELL_VAR *reduce_init_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_init. */ ++static SHELL_VAR *reduce_fini_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_fini. */ ++static SHELL_VAR *reduce_op_func = NULL; /* User-defined callback function for CIRCLE_cb_reduce_op. */ ++static CIRCLE_handle *current_handle = NULL; /* Active handle within a callback or NULL if not within a callback */ ++static int within_reduction = 0; /* 1=within a reduction callback; 0=not */ ++ ++/* Return with a usage message if no arguments remain. */ ++#define YES_ARGS(LIST) \ ++ if ((LIST) == 0) \ ++ { \ ++ builtin_usage (); \ ++ return (EX_USAGE); \ ++ } ++ ++/* Perform the same operation as bind_variable, but with VALUE being a ++ * number, not a string. */ ++static SHELL_VAR * ++bind_variable_number (name, value, flags) ++ const char *name; ++ long value; ++ int flags; ++{ ++ char numstr[25]; /* String version of VALUE */ ++ ++ sprintf (numstr, "%ld", value); ++ return bind_variable (name, numstr, flags); ++} ++ ++/* Invoke the user-defined creation-callback function (create_func). */ ++static void ++internal_create_func (handle) ++ CIRCLE_handle *handle; ++{ ++ WORD_LIST *funcargs; ++ ++ if (create_func == NULL) ++ return; ++ current_handle = handle; ++ funcargs = make_word_list (make_word ("cb_create"), NULL); ++ execute_shell_function (create_func, funcargs); ++ dispose_words (funcargs); ++ current_handle = NULL; ++} ++ ++/* Invoke the user-defined process-callback function (process_func). */ ++static void ++internal_process_func (handle) ++ CIRCLE_handle *handle; ++{ ++ WORD_LIST *funcargs; ++ ++ if (process_func == NULL) ++ return; ++ current_handle = handle; ++ funcargs = make_word_list (make_word ("cb_process"), NULL); ++ execute_shell_function (process_func, funcargs); ++ dispose_words (funcargs); ++ current_handle = NULL; ++} ++ ++/* Invoke the user-defined reduction-initiation callback function ++ * (reduce_init_func). */ ++static void ++internal_reduce_init_func (void) ++{ ++ WORD_LIST *funcargs; ++ ++ if (reduce_init_func == NULL) ++ return; ++ within_reduction = 1; ++ funcargs = make_word_list (make_word ("cb_reduce_init"), NULL); ++ execute_shell_function (reduce_init_func, funcargs); ++ dispose_words (funcargs); ++ within_reduction = 0; ++} ++ ++/* Invoke the user-defined reduction callback function ++ * (reduce_op_func). */ ++static void ++internal_reduce_op_func (buf1, size1, buf2, size2) ++ const void* buf1; ++ size_t size1; ++ const void* buf2; ++ size_t size2; ++{ ++ WORD_LIST *funcargs; ++ ++ if (reduce_op_func == NULL) ++ return; ++ within_reduction = 1; ++ funcargs = make_word_list (make_word (buf2), NULL); ++ funcargs = make_word_list (make_word (buf1), funcargs); ++ funcargs = make_word_list (make_word ("cb_reduce_op"), funcargs); ++ execute_shell_function (reduce_op_func, funcargs); ++ dispose_words (funcargs); ++ within_reduction = 0; ++} ++ ++/* Invoke the user-defined reduction-finalization callback function ++ * (reduce_fini_func). */ ++static void ++internal_reduce_fini_func (buf, size) ++ const void* buf; ++ size_t size; ++{ ++ WORD_LIST *funcargs; ++ ++ if (reduce_fini_func == NULL) ++ return; ++ funcargs = make_word_list (make_word (buf), NULL); ++ funcargs = make_word_list (make_word ("cb_reduce_fini"), funcargs); ++ execute_shell_function (reduce_fini_func, funcargs); ++ dispose_words (funcargs); ++} ++ ++/* Look up a user-provided callback function. */ ++static int ++find_callback_function (list, user_func) ++ WORD_LIST *list; ++ SHELL_VAR **user_func; ++{ ++ char *funcname; /* Name of the user-defined function. */ ++ ++ /* If no argument was provided, nullify the callback function. */ ++ if (list == NULL) ++ { ++ *user_func = NULL; ++ return EXECUTION_SUCCESS; ++ } ++ ++ /* Get the callback function. */ ++ funcname = list->word->word; ++ list = list->next; ++ no_args (list); ++ *user_func = find_function (funcname); ++ if (*user_func == NULL) ++ { ++ builtin_error (_("function %s not found"), funcname); ++ return EXECUTION_FAILURE; ++ } ++ return EXECUTION_SUCCESS; ++} ++ ++/* Initialize Libcircle. */ ++void ++initialize_libcircle (argc, argv) ++ int argc; ++ char **argv; ++{ ++ circle_rank = CIRCLE_init (argc, argv, CIRCLE_DEFAULT_FLAGS); ++ bind_variable_number ("circle_rank", circle_rank, 0); ++ CIRCLE_enable_logging (CIRCLE_LOG_WARN); ++ CIRCLE_cb_create (internal_create_func); ++ CIRCLE_cb_process (internal_process_func); ++ CIRCLE_cb_reduce_init (internal_reduce_init_func); ++ CIRCLE_cb_reduce_op (internal_reduce_op_func); ++ CIRCLE_cb_reduce_fini (internal_reduce_fini_func); ++} ++ ++/* Finalize Libcircle. */ ++void ++finalize_libcircle (void) ++{ ++ CIRCLE_finalize (); ++} ++ ++/* ---------------------------------------------------------------------- */ ++ ++$BUILTIN circle_set_options ++$FUNCTION circle_set_options_builtin ++$SHORT_DOC circle_set_options [flag]... ++Change Libcircle's run-time behavior. ++ ++Arguments: ++ FLAG "split_random", "split_equal", or "create_global" ++ ++Multiple flags can be provided. If no flags are provided, Libcircle ++reverts to its default options. ++ ++Exit Status: ++Returns 0 unless an invalid option is given. ++$END ++/*'*/ ++ ++/* Here is the circle_set_options builtin. */ ++int ++circle_set_options_builtin (list) ++ WORD_LIST *list; ++{ ++ char *word; /* One argument */ ++ int flags = 0; /* Flags to pass to CIRCLE_set_options */ ++ ++ if (list == NULL) ++ flags = CIRCLE_DEFAULT_FLAGS; ++ else ++ while (list != NULL) ++ { ++ word = list->word->word; ++ if (!strcmp (word, "split_random")) ++ flags |= CIRCLE_SPLIT_RANDOM; ++ else if (!strcmp (word, "split_equal")) ++ flags |= CIRCLE_SPLIT_EQUAL; ++ else if (!strcmp (word, "create_global")) ++ flags |= CIRCLE_CREATE_GLOBAL; ++ else ++ { ++ builtin_error (_("invalid flag \"%s\""), word); ++ return (EXECUTION_FAILURE); ++ } ++ list = list->next; ++ } ++ CIRCLE_set_options (flags); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_cb_create ++$FUNCTION circle_cb_create_builtin ++$SHORT_DOC circle_cb_create [func] ++Register a function that will create work when asked. ++ ++Arguments: ++ FUNC User-defined callback function that will invoke ++ circle_enqueue when called ++ ++If FUNC is omitted, no function will be associated with work creation. ++This can be used to nullify a previous circle_cb_create invocation. ++ ++Exit Status: ++Returns 0 unless an invalid function is given or an error occurs. ++$END ++ ++/* Here is the circle_cb_create builtin. */ ++int ++circle_cb_create_builtin (list) ++ WORD_LIST *list; ++{ ++ return find_callback_function (list, &create_func); ++} ++ ++$BUILTIN circle_cb_process ++$FUNCTION circle_cb_process_builtin ++$SHORT_DOC circle_cb_process [func] ++Register a function that will process work when asked. ++ ++Arguments: ++ FUNC User-defined callback function that will invoke ++ circle_enqueue when called ++ ++If FUNC is omitted, no function will be associated with work processing. ++This can be used to nullify a previous circle_cb_process invocation. ++ ++Exit Status: ++Returns 0 unless an invalid function is given or an error occurs. ++$END ++ ++/* Here is the circle_cb_process builtin. */ ++int ++circle_cb_process_builtin (list) ++ WORD_LIST *list; ++{ ++ return find_callback_function (list, &process_func); ++} ++ ++$BUILTIN circle_begin ++$FUNCTION circle_begin_builtin ++$SHORT_DOC circle_begin ++Begin creation and processing of the distributed work queue. ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++ ++/* Here is the circle_begin builtin. */ ++int ++circle_begin_builtin (list) ++ WORD_LIST *list; ++{ ++ no_args (list); ++ CIRCLE_begin (); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_enqueue ++$FUNCTION circle_enqueue_builtin ++$SHORT_DOC circle_enqueue work ++Enqueue work onto the distributed queue. ++ ++Arguments: ++ WORK "Work" as represented by an arbitrary string of limited ++ size (generally around 4KB) ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++ ++/* Here is the circle_enqueue builtin. */ ++int ++circle_enqueue_builtin (list) ++ WORD_LIST *list; ++{ ++ char *work; /* Work to perform */ ++ ++ /* Extract the work argument. */ ++ YES_ARGS (list); ++ work = list->word->word; ++ list = list->next; ++ no_args (list); ++ ++ /* Complain if we're not within a proper callback function. */ ++ if (current_handle == NULL) ++ { ++ builtin_error (_("not within a Libcircle \"create\" or \"process\" callback function")); ++ return EXECUTION_FAILURE; ++ } ++ ++ /* Enqueue the work. */ ++ if (current_handle->enqueue (work) == -1) ++ return EXECUTION_FAILURE; ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_dequeue ++$FUNCTION circle_dequeue_builtin ++$SHORT_DOC circle_dequeue var ++Dequeue work from the distributed queue into a variable. ++ ++Arguments: ++ VAR Variable in which to receive previously enqueued "work" ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++ ++/* Here is the circle_dequeue builtin. */ ++int ++circle_dequeue_builtin (list) ++ WORD_LIST *list; ++{ ++ char *varname; /* Variable in which to store the work string */ ++ char work[CIRCLE_MAX_STRING_LEN+1]; /* Work to perform */ ++ ++ /* Extract the variable-name argument. */ ++ YES_ARGS (list); ++ varname = list->word->word; ++ list = list->next; ++ no_args (list); ++ ++ /* Complain if we're not within a callback function. */ ++ if (current_handle == NULL) ++ { ++ builtin_error (_("not within a Libcircle callback function")); ++ return EXECUTION_FAILURE; ++ } ++ ++ /* Dequeue the work and bind it to the given variable. */ ++ if (current_handle->dequeue (work) == -1) ++ return EXECUTION_FAILURE; ++ bind_variable (varname, work, 0); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_enable_logging ++$FUNCTION circle_enable_logging_builtin ++$SHORT_DOC circle_enable_logging log_level ++Change Libcircle's logging verbosity ++ ++Arguments: ++ LOG_LEVEL "fatal", "error", "warning", "info", or "debug" ++ ++Exit Status: ++Returns 0 unless an invalid option is given. ++$END ++/*'*/ ++ ++/* Here is the circle_enable_logging builtin. */ ++int ++circle_enable_logging_builtin (list) ++ WORD_LIST *list; ++{ ++ char *word; /* One argument */ ++ CIRCLE_loglevel loglevel; /* Level to set */ ++ ++ /* Parse the log level. */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (!strcmp (word, "fatal")) ++ loglevel = CIRCLE_LOG_FATAL; ++ else if (!strcmp (word, "error")) ++ loglevel = CIRCLE_LOG_ERR; ++ else if (!strcmp (word, "warning")) ++ loglevel = CIRCLE_LOG_WARN; ++ else if (!strcmp (word, "info")) ++ loglevel = CIRCLE_LOG_INFO; ++ else if (!strcmp (word, "debug")) ++ loglevel = CIRCLE_LOG_DBG; ++ else ++ { ++ builtin_error (_("invalid log level \"%s\""), word); ++ return (EXECUTION_FAILURE); ++ } ++ ++ /* Set the log level. */ ++ CIRCLE_enable_logging (loglevel); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_abort ++$FUNCTION circle_abort_builtin ++$SHORT_DOC circle_abort ++Terminate queue processing. ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++ ++/* Here is the circle_abort builtin. */ ++int ++circle_abort_builtin (list) ++ WORD_LIST *list; ++{ ++ no_args (list); ++ CIRCLE_abort (); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_checkpoint ++$FUNCTION circle_checkpoint_builtin ++$SHORT_DOC circle_checkpoint ++Checkpoint a work queue to disk. ++ ++Write a file called circle${circle_rank}.txt containing the current ++queue state of rank ${circle_rank}. On a later run, a worker can ++invoke circle_read_restarts to repopulate its queue from such a ++checkpoint file. ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++/*'*/ ++ ++/* Here is the circle_checkpoint builtin. */ ++int ++circle_checkpoint_builtin (list) ++ WORD_LIST *list; ++{ ++ no_args (list); ++ CIRCLE_checkpoint (); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_read_restarts ++$FUNCTION circle_read_restarts_builtin ++$SHORT_DOC circle_read_restarts ++Repopulate a work queue from a disk checkpoint. ++ ++Read queue contents from a file called circle${circle_rank}.txt, which ++was previously produced by circle_checkpoint. ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++/*'*/ ++ ++/* Here is the circle_read_restarts builtin. */ ++int ++circle_read_restarts_builtin (list) ++ WORD_LIST *list; ++{ ++ no_args (list); ++ CIRCLE_read_restarts (); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN circle_cb_reduce_init ++$FUNCTION circle_cb_reduce_init_builtin ++$SHORT_DOC circle_cb_reduce_init [func] ++Register a function that will initiate a reduction operation. ++ ++Arguments: ++ FUNC User-defined callback function that will invoke ++ circle_reduce when called ++ ++FUNC will be invoked on all ranks. ++ ++If FUNC is omitted, no function will be associated with reduction ++initialization. This can be used to nullify a previous ++circle_cb_reduce_init invocation. ++ ++Exit Status: ++Returns 0 unless an invalid function is given or an error occurs. ++$END ++ ++/* Here is the circle_cb_reduce_init builtin. */ ++int ++circle_cb_reduce_init_builtin (list) ++ WORD_LIST *list; ++{ ++ return find_callback_function (list, &reduce_init_func); ++} ++ ++$BUILTIN circle_cb_reduce_op ++$FUNCTION circle_cb_reduce_op_builtin ++$SHORT_DOC circle_cb_reduce_op [func] ++Register a function that will complete a reduction operation. ++ ++Arguments: ++ FUNC User-defined callback function that will receive ++ two items to reduce and invoke circle_reduce on ++ the reduced value ++ ++If FUNC is omitted, no function will be associated with reduction ++execution. This can be used to nullify a previous circle_cb_reduce_op ++invocation. ++ ++Exit Status: ++Returns 0 unless an invalid function is given or an error occurs. ++$END ++ ++/* Here is the circle_cb_reduce_op builtin. */ ++int ++circle_cb_reduce_op_builtin (list) ++ WORD_LIST *list; ++{ ++ return find_callback_function (list, &reduce_op_func); ++} ++ ++$BUILTIN circle_cb_reduce_fini ++$FUNCTION circle_cb_reduce_fini_builtin ++$SHORT_DOC circle_cb_reduce_fini [func] ++Register a function that will complete a reduction operation. ++ ++Arguments: ++ FUNC User-defined callback function that will receive ++ the final reduced data ++ ++If FUNC is omitted, no function will be associated with reduction ++completion. This can be used to nullify a previous ++circle_cb_reduce_fini invocation. ++ ++Libcircle guarantees that FUNC will be invoked only on rank 0. ++ ++Exit Status: ++Returns 0 unless an invalid function is given or an error occurs. ++$END ++ ++/* Here is the circle_cb_reduce_fini builtin. */ ++int ++circle_cb_reduce_fini_builtin (list) ++ WORD_LIST *list; ++{ ++ return find_callback_function (list, &reduce_fini_func); ++} ++ ++$BUILTIN circle_reduce ++$FUNCTION circle_reduce_builtin ++$SHORT_DOC circle_reduce work ++Seed the next phase of a reduction operation ++ ++Arguments: ++ WORK "Work" as represented by an arbitrary string of limited ++ size (generally around 4KB) ++ ++This function should be called both by the callback function ++registered with circle_reduce_init and the callback function ++registered with circle_reduce_op. ++ ++Exit Status: ++Returns 0 unless an error occurs. ++$END ++ ++/* Here is the circle_reduce builtin. */ ++int ++circle_reduce_builtin (list) ++ WORD_LIST *list; ++{ ++ char *work; /* Work to perform */ ++ ++ /* Extract the work argument. */ ++ YES_ARGS (list); ++ work = list->word->word; ++ list = list->next; ++ no_args (list); ++ ++ /* Complain if we're not within a proper callback function. */ ++ if (!within_reduction) ++ { ++ builtin_error (_("not within a Libcircle \"reduce_init\" or \"reduce_op\" callback function")); ++ return EXECUTION_FAILURE; ++ } ++ ++ /* Reduce the work. */ ++ CIRCLE_reduce (work, strlen (work)); ++ return EXECUTION_SUCCESS; ++} +diff -Naur bash-4.3/builtins/Makefile.in mpibash-4.3/builtins/Makefile.in +--- bash-4.3/builtins/Makefile.in 2012-05-25 07:29:19.000000000 -0600 ++++ mpibash-4.3/builtins/Makefile.in 2014-05-13 11:27:37.314100671 -0600 +@@ -141,7 +141,9 @@ + $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \ + $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \ + $(srcdir)/reserved.def $(srcdir)/pushd.def $(srcdir)/shopt.def \ +- $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def ++ $(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def \ ++ $(srcdir)/mpi.def \ ++@CIRCLE@ $(srcdir)/circle.def + + STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \ + getopt.h +@@ -153,7 +155,9 @@ + jobs.o kill.o let.o mapfile.o \ + pushd.o read.o return.o set.o setattr.o shift.o source.o \ + suspend.o test.o times.o trap.o type.o ulimit.o umask.o \ +- wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o ++ wait.o getopts.o shopt.o printf.o getopt.o bashgetopt.o complete.o \ ++ mpi.o \ ++@CIRCLE@ circle.o + + CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \ + tmpbuiltins.h +@@ -317,6 +321,8 @@ + getopts.o: getopts.def + reserved.o: reserved.def + complete.o: complete.def ++@CIRCLE@ circle.o: circle.def ++mpi.o: mpi.def + + # C files + bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h +@@ -644,6 +650,19 @@ + mapfile.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h + mapfile.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/variables.h $(topdir)/conftypes.h + mapfile.o: $(topdir)/arrayfunc.h ../pathnames.h ++@CIRCLE@ circle.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h ++@CIRCLE@ circle.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h ++@CIRCLE@ circle.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h ++@CIRCLE@ circle.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h ++@CIRCLE@ circle.o: $(BASHINCDIR)/maxpath.h ../pathnames.h ++mpi.o: ../config.h ../config-top.h ../config-bot.h ../bashintl.h ++mpi.o: ../include/gettext.h ../shell.h ../config.h ../bashjmp.h ++mpi.o: ../include/posixjmp.h ../command.h ../syntax.h ../general.h ++mpi.o: ../bashtypes.h ../include/chartypes.h ../xmalloc.h ../bashansi.h ++mpi.o: ../error.h ../variables.h ../array.h ../assoc.h ../hashlib.h ++mpi.o: ../conftypes.h ../arrayfunc.h ../quit.h ../sig.h ../include/maxpath.h ++mpi.o: ../unwind_prot.h ../dispose_cmd.h ../make_cmd.h ../include/ocache.h ++mpi.o: ../subst.h ../pathnames.h ../externs.h common.h bashgetopt.h + + #bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h + +diff -Naur bash-4.3/builtins/mpi.def mpibash-4.3/builtins/mpi.def +--- bash-4.3/builtins/mpi.def 1969-12-31 17:00:00.000000000 -0700 ++++ mpibash-4.3/builtins/mpi.def 2014-05-13 11:27:37.314100671 -0600 +@@ -0,0 +1,744 @@ ++This file is mpi.def, from which is created mpi.c. ++It implements all of the "mpi_*" builtins in Bash. ++ ++$PRODUCES mpi.c ++ ++#include <config.h> ++ ++#include <stdio.h> ++#if defined (HAVE_UNISTD_H) ++# ifdef _MINIX ++# include <sys/types.h> ++# endif ++# include <unistd.h> ++#endif ++ ++#include "../bashintl.h" ++#include "../shell.h" ++#include "common.h" ++#include "bashgetopt.h" ++#include <mpi.h> ++ ++extern int running_trap, trap_saved_exit_value; ++ ++/* Keep track of who we are within MPI_COMM_WORLD. */ ++static int mpi_rank; ++static int mpi_num_ranks; ++ ++/* Try an MPI operation. Return with an error message on failure. */ ++#define MPI_TRY(STMT) \ ++ do \ ++ { \ ++ int mpierr; \ ++ mpierr = STMT; \ ++ if (mpierr != MPI_SUCCESS) \ ++ return report_mpi_error (mpierr); \ ++ } \ ++ while (0) ++ ++/* Return with a usage message if no arguments remain. */ ++#define YES_ARGS(LIST) \ ++ if ((LIST) == 0) \ ++ { \ ++ builtin_usage (); \ ++ return (EX_USAGE); \ ++ } ++ ++/* Return with an error message if a given variable is read-only or if ++ * we can't write to it for any other reason (e.g., it's defined as a ++ * function). */ ++#define REQUIRE_WRITABLE(NAME) \ ++ do \ ++ { \ ++ SHELL_VAR *bindvar = find_shell_variable (NAME); \ ++ if (bindvar) \ ++ { \ ++ if (readonly_p (bindvar)) \ ++ { \ ++ err_readonly (NAME); \ ++ return (EXECUTION_FAILURE); \ ++ } \ ++ if (unbind_variable (NAME) == -1) \ ++ { \ ++ builtin_error ("Failed to write to variable %s", NAME); \ ++ return (EXECUTION_FAILURE); \ ++ } \ ++ } \ ++ } \ ++ while (0) ++ ++/* Initialize MPI. */ ++void ++initialize_mpi (argc, argv) ++ int argc; ++ char **argv; ++{ ++ int init_done; ++ ++ MPI_Initialized (&init_done); ++ if (!init_done) ++ MPI_Init (&argc, &argv); ++ MPI_Errhandler_set (MPI_COMM_WORLD, MPI_ERRORS_RETURN); ++ MPI_Comm_rank (MPI_COMM_WORLD, &mpi_rank); ++ MPI_Comm_size (MPI_COMM_WORLD, &mpi_num_ranks); ++} ++ ++/* Finalize MPI. */ ++void ++finalize_mpi () ++{ ++ MPI_Finalize (); ++} ++ ++/* Parse an operation name into an MPI_Op. Return 1 on success, 0 on ++ * failure. */ ++static int ++parse_operation (char *name, MPI_Op *op) ++{ ++ /* Define a mapping from operator names to MPI_Op values. */ ++ typedef struct { ++ char *name; /* Operation name (e.g., "sum") */ ++ MPI_Op value; /* Operation value (e.g., MPI_SUM) */ ++ } opname2value_t; ++ static opname2value_t oplist[] = { ++ {"max", MPI_MAX}, ++ {"min", MPI_MIN}, ++ {"sum", MPI_SUM}, ++ {"prod", MPI_PROD}, ++ {"land", MPI_LAND}, ++ {"band", MPI_BAND}, ++ {"lor", MPI_LOR}, ++ {"bor", MPI_BOR}, ++ {"lxor", MPI_LXOR}, ++ {"bxor", MPI_BXOR}, ++ {"maxloc", MPI_MAXLOC}, ++ {"minloc", MPI_MINLOC} ++ }; ++ size_t i; ++ ++ for (i = 0; i < sizeof(oplist)/sizeof(opname2value_t); i++) ++ if (!strcmp(name, oplist[i].name)) ++ { ++ *op = oplist[i].value; ++ if (i > 0) ++ { ++ /* As a performance optimization, bubble up the value we ++ * just found. */ ++ opname2value_t prev = oplist[i - 1]; ++ oplist[i - 1] = oplist[i]; ++ oplist[i] = prev; ++ } ++ return 1; ++ } ++ return 0; ++} ++ ++/* Report an error to the user and return EXECUTION_FAILURE. */ ++static int ++report_mpi_error (mpierr) ++ int mpierr; ++{ ++ char errstr[MPI_MAX_ERROR_STRING]; ++ int errstrlen; ++ ++ MPI_Error_string (mpierr, errstr, &errstrlen); ++ builtin_error ("%s", errstr); ++ return EXECUTION_FAILURE; ++} ++ ++/* Perform the same operation as bind_variable, but with VALUE being a ++ * number, not a string. */ ++static SHELL_VAR * ++bind_variable_number (name, value, flags) ++ const char *name; ++ long value; ++ int flags; ++{ ++ char numstr[25]; /* String version of VALUE */ ++ ++ sprintf (numstr, "%ld", value); ++ return bind_variable (name, numstr, flags); ++} ++ ++/* Perform the same operation as bind_array_variable, but with VALUE ++ * being a number, not a string. */ ++static SHELL_VAR * ++bind_array_variable_number (name, ind, value, flags) ++ char *name; ++ arrayind_t ind; ++ long value; ++ int flags; ++{ ++ char numstr[25]; /* String version of VALUE */ ++ ++ sprintf (numstr, "%ld", value); ++ return bind_array_variable (name, ind, numstr, flags); ++} ++ ++/* Define a reduction-type function (allreduce, scan, exscan, etc.). */ ++typedef int (*reduction_func_t)(void *, void *, int, MPI_Datatype, MPI_Op, MPI_Comm); ++ ++/* Perform any reduction-type operation (allreduce, scan, exscan, etc.). */ ++static int ++reduction_like (list, funcname, func) ++ WORD_LIST *list; ++ char *funcname; ++ reduction_func_t func; ++{ ++ char *word; /* One argument */ ++ struct { ++ long int value; /* Reduced value */ ++ int rank; /* Rank associated with the above */ ++ } number, result; ++ MPI_Op operation = MPI_SUM; /* Operation to perform */ ++ char *varname; /* Name of the variable to bind the results to */ ++ intmax_t n; ++ int i; ++ ++ /* Parse "-O OPERATION" (optional), where OPERATION is a reduction ++ * operation. */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (ISOPTION (word, 'O')) ++ { ++ list = list->next; ++ if (list == 0) ++ { ++ sh_needarg (funcname); ++ return (EX_USAGE); ++ } ++ word = list->word->word; ++ if (!parse_operation (word, &operation)) ++ { ++ sh_invalidopt ("-O"); ++ return (EX_USAGE); ++ } ++ list = list->next; ++ } ++ ++ /* Parse the argument, which must be a number. */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (!legal_number (word, &n)) ++ { ++ sh_neednumarg (funcname); ++ return (EX_USAGE); ++ } ++ number.value = (long int) n; ++ number.rank = mpi_rank; ++ list = list->next; ++ ++ /* Parse the target variable, which must not be read-only. */ ++ YES_ARGS (list); ++ varname = list->word->word; ++ if (mpi_rank != 0 || func != MPI_Exscan) ++ REQUIRE_WRITABLE (varname); ++ list = list->next; ++ no_args (list); ++ ++ /* Perform the reduction operation. Bind the given array variable ++ * to the result and, for minloc/maxloc, the associated rank. */ ++ if (mpi_rank != 0 || func != MPI_Exscan) { ++ bind_array_variable (varname, 0, "", 0); ++ bind_array_variable (varname, 1, "", 0); ++ } ++ if (operation == MPI_MINLOC || operation == MPI_MAXLOC) ++ { ++ MPI_TRY (func (&number, &result, 1, MPI_LONG_INT, operation, MPI_COMM_WORLD)); ++ if (mpi_rank != 0 || func != MPI_Exscan) ++ bind_array_variable_number (varname, 1, result.rank, 0); ++ } ++ else ++ MPI_TRY (func (&number.value, &result.value, 1, MPI_LONG, operation, MPI_COMM_WORLD)); ++ if (mpi_rank != 0 || func != MPI_Exscan) ++ bind_array_variable_number (varname, 0, result.value, 0); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_comm_rank ++$FUNCTION mpi_comm_rank_builtin ++$SHORT_DOC mpi_comm_rank name ++Return the process's rank in the MPI job. ++ ++Arguments: ++ NAME Scalar variable in which to receive the rank ++ ++Exit Status: ++Returns 0 unless an invalid option is given. ++$END ++/*'*/ ++ ++/* Here is the mpi_comm_rank builtin. */ ++int ++mpi_comm_rank_builtin (list) ++ WORD_LIST *list; ++{ ++ char *varname; /* Name of the variable to bind the results to */ ++ ++ YES_ARGS (list); ++ varname = list->word->word; ++ REQUIRE_WRITABLE (varname); ++ list = list->next; ++ no_args (list); ++ bind_variable_number (varname, mpi_rank, 0); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_comm_size ++$FUNCTION mpi_comm_size_builtin ++$SHORT_DOC mpi_comm_size name ++Return the total number of ranks in the MPI job. ++ ++Arguments: ++ NAME Scalar variable in which to receive the number of ranks ++ ++Exit Status: ++Returns 0 unless an invalid option is given. ++$END ++ ++/* Here is the mpi_comm_size builtin. */ ++int ++mpi_comm_size_builtin (list) ++ WORD_LIST *list; ++{ ++ char *varname; /* Name of the variable to bind the results to */ ++ ++ YES_ARGS (list); ++ varname = list->word->word; ++ REQUIRE_WRITABLE (varname); ++ list = list->next; ++ no_args (list); ++ bind_variable_number (varname, mpi_num_ranks, 0); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_abort ++$FUNCTION mpi_abort_builtin ++$SHORT_DOC mpi_abort [n] ++Abort all processes in the MPI job and exit the shell. ++ ++Exits not only the caller's shell (with a status of N) but also all ++remote shells that are part of the same MPI job. If N is omitted, the ++exit status is that of the last command executed. ++ ++This command should be used only in extreme circumstances. It is ++better for each process to exit normally on its own. ++$END ++/*'*/ ++ ++/* Here is the mpi_abort builtin. */ ++int ++mpi_abort_builtin (list) ++ WORD_LIST *list; ++{ ++ int exit_value; ++ ++ exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list); /* Copied from exit.def */ ++ MPI_TRY (MPI_Abort (MPI_COMM_WORLD, exit_value)); ++ return EXECUTION_FAILURE; ++} ++ ++$BUILTIN mpi_send ++$FUNCTION mpi_send_builtin ++$SHORT_DOC mpi_send [-t tag] rank message ++Send a message to a remote process in the same MPI job. ++ ++Options: ++ -t TAG Send the message using tag TAG (default: 0). TAG must ++ be a nonnegative integer. ++ ++Arguments: ++ RANK Whom to send the message to. RANK must be an integer in ++ the range [0, $(mpi_comm_size)-1]. ++ ++ MESSAGE String to send to rank RANK. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_send builtin. */ ++int ++mpi_send_builtin (list) ++ WORD_LIST *list; ++{ ++ char *word; /* One argument */ ++ intmax_t target_rank; /* MPI target rank */ ++ char *message; /* Message to send to rank target_rank */ ++ intmax_t tag = 0; /* Message tag to use */ ++ ++ /* Parse "-t TAG" (optional), where TAG is a number or "any". */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (ISOPTION (word, 't')) ++ { ++ list = list->next; ++ if (list == 0) ++ { ++ sh_needarg ("mpi_recv"); ++ return (EX_USAGE); ++ } ++ word = list->word->word; ++ if (!legal_number (word, &tag)) ++ { ++ sh_neednumarg ("-t"); ++ return (EX_USAGE); ++ } ++ list = list->next; ++ } ++ else if (*word == '-') ++ { ++ sh_invalidopt (word); ++ builtin_usage (); ++ return (EX_USAGE); ++ } ++ ++ /* Parse the target rank, which must be a number. */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (!legal_number (word, &target_rank)) ++ { ++ builtin_error (_("mpi_send: numeric rank required")); ++ return (EX_USAGE); ++ } ++ list = list->next; ++ ++ /* Parse the message to send. */ ++ YES_ARGS (list); ++ message = list->word->word; ++ list = list->next; ++ no_args (list); ++ ++ /* Send the message. */ ++ MPI_TRY (MPI_Send (message, strlen(message)+1, MPI_BYTE, (int)target_rank, (int)tag, MPI_COMM_WORLD)); ++ return EXECUTION_SUCCESS; ++} ++ ++ ++$BUILTIN mpi_recv ++$FUNCTION mpi_recv_builtin ++$SHORT_DOC mpi_recv [-t tag] rank name ++Receive a message from a remote process in the same MPI job. ++ ++Options: ++ -t TAG Receive only messages sent using tag TAG (default: 0). ++ TAG must be either a nonnegative integer or the string ++ "any" to receive messages sent using any tag. ++ ++Arguments: ++ RANK Receive only messages sent from sender RANK. RANK ++ must either be in the range [0, $(mpi_comm_size)-1] or ++ be the string "any" to receive messages from any sender. ++ ++ NAME Array variable in which to receive the message, sender ++ rank, and tag. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_recv builtin. */ ++int ++mpi_recv_builtin (list) ++ WORD_LIST *list; ++{ ++ char *word; /* One argument */ ++ intmax_t source_rank; /* MPI source rank */ ++ char *endptr; /* Used for parsing strings into numbers */ ++ MPI_Status status; /* Status of an MPI operation */ ++ int count; /* Message length in bytes */ ++ intmax_t tag = 0; /* Message tag to use */ ++ char *varname; /* Name of the variable to bind the results to */ ++ static char *message = NULL; /* Message received from MPI */ ++ static size_t alloced = 0; /* Number of bytes allocated for the above */ ++ int opt; /* Parsed option */ ++ ++ /* Parse any options provided. */ ++ reset_internal_getopt (); ++ while ((opt = internal_getopt (list, "t:")) != -1) ++ { ++ switch (opt) ++ { ++ case 't': ++ if (!strcmp (list_optarg, "any")) ++ tag = MPI_ANY_TAG; ++ else if (!legal_number (list_optarg, &tag)) ++ { ++ builtin_error (_("-t: numeric argument or \"any\" required")); ++ return (EX_USAGE); ++ } ++ break; ++ ++ default: ++ sh_invalidopt (word); ++ builtin_usage (); ++ return (EX_USAGE); ++ } ++ } ++ list = loptend; ++ ++ /* Parse the source rank, which must be a number or "any". */ ++ YES_ARGS (list); ++ word = list->word->word; ++ if (!legal_number (word, &source_rank)) ++ { ++ if (!strcmp (word, "any")) ++ source_rank = MPI_ANY_SOURCE; ++ else ++ { ++ builtin_error (_("mpi_recv: numeric rank or \"any\" required")); ++ return (EX_USAGE); ++ } ++ } ++ list = list->next; ++ ++ /* Parse the target variable, which must not be read-only. */ ++ YES_ARGS (list); ++ varname = list->word->word; ++ REQUIRE_WRITABLE (varname); ++ list = list->next; ++ no_args (list); ++ ++ /* Receive a message. Because we don't know long the message will ++ * be, we first probe to get the length. */ ++ MPI_TRY (MPI_Probe ((int)source_rank, (int)tag, MPI_COMM_WORLD, &status)); ++ MPI_TRY (MPI_Get_count (&status, MPI_BYTE, &count)); ++ if (alloced < count) ++ { ++ message = xrealloc (message, count); ++ alloced = count; ++ } ++ MPI_TRY (MPI_Recv (message, count, MPI_BYTE, status.MPI_SOURCE, status.MPI_TAG, MPI_COMM_WORLD, &status)); ++ bind_array_variable (varname, 0, message, 0); ++ bind_array_variable_number (varname, 1, status.MPI_SOURCE, 0); ++ bind_array_variable_number (varname, 2, status.MPI_TAG, 0); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_barrier ++$FUNCTION mpi_barrier_builtin ++$SHORT_DOC mpi_barrier ++Synchronizes all of the processes in the MPI job. ++ ++No process will return from mpi_barrier until all processes have ++called mpi_barrier. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_barrier builtin. */ ++int ++mpi_barrier_builtin (list) ++ WORD_LIST *list; ++{ ++ no_args (list); ++ MPI_TRY (MPI_Barrier (MPI_COMM_WORLD)); ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_bcast ++$FUNCTION mpi_bcast_builtin ++$SHORT_DOC mpi_bcast [message] name ++Broadcast a message to all processes in the same MPI job. ++ ++Arguments: ++ MESSAGE String to broadcast from one process to all the others. ++ ++ NAME Scalar variable in which to receive the broadcast message. ++ ++Exactly one process in the MPI job must specify a message to ++broadcast. No process will return from mpi_bcast until all processes ++have called mpi_bcast. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_bcast builtin. */ ++int ++mpi_bcast_builtin (list) ++ WORD_LIST *list; ++{ ++ char *word; /* One argument */ ++ int root; /* MPI root rank */ ++ char *root_message; /* Message to broadcast */ ++ int msglen; /* Length in bytes of the above (including the NULL byte) */ ++ char *varname; /* Name of the variable to bind the results to */ ++ static int *all_lengths = NULL; /* List of every rank's msglen */ ++ static char *message = NULL; /* Message received from the root */ ++ static int alloced = 0; /* Bytes allocated for the above */ ++ int i; ++ ++ /* Parse the optional message and target variable, which must not be ++ * read-only. */ ++ YES_ARGS (list); ++ if (list->next == NULL) ++ { ++ /* Non-root */ ++ root_message = NULL; ++ msglen = -1; ++ } ++ else ++ { ++ /* Root */ ++ root_message = list->word->word; ++ msglen = (int) strlen(root_message) + 1; ++ list = list->next; ++ } ++ varname = list->word->word; ++ REQUIRE_WRITABLE (varname); ++ list = list->next; ++ no_args (list); ++ ++ /* Acquire global agreement on the root and the message size. */ ++ if (all_lengths == NULL) ++ all_lengths = xmalloc (mpi_num_ranks*sizeof(int)); ++ MPI_TRY (MPI_Allgather (&msglen, 1, MPI_INT, all_lengths, 1, MPI_INT, MPI_COMM_WORLD)); ++ root = -1; ++ for (i = 0; i < mpi_num_ranks; i++) ++ { ++ if (all_lengths[i] == -1) ++ continue; ++ if (root != -1) ++ { ++ builtin_error (_("mpi_bcast: more than one process specified a message")); ++ return (EXECUTION_FAILURE); ++ } ++ root = i; ++ msglen = all_lengths[i]; ++ } ++ if (root == -1) ++ { ++ builtin_error (_("mpi_bcast: no process specified a message")); ++ return (EXECUTION_FAILURE); ++ } ++ ++ /* Broadcast the message. */ ++ if (mpi_rank == root) ++ { ++ MPI_TRY (MPI_Bcast (root_message, msglen, MPI_BYTE, root, MPI_COMM_WORLD)); ++ bind_variable (varname, root_message, 0); ++ } ++ else ++ { ++ if (alloced < msglen) ++ { ++ message = xrealloc (message, msglen); ++ alloced = msglen; ++ } ++ MPI_TRY (MPI_Bcast (message, msglen, MPI_BYTE, root, MPI_COMM_WORLD)); ++ bind_variable (varname, message, 0); ++ } ++ return EXECUTION_SUCCESS; ++} ++ ++$BUILTIN mpi_scan ++$FUNCTION mpi_scan_builtin ++$SHORT_DOC mpi_scan number name ++Perform an inclusive scan across all processes in the same MPI job. ++ ++ -O OPERATION Operation to perform. Must be one of "max", "min", ++ "sum", "prod", "land", "band", "lor", "bor", "lxor", ++ "bxor", "maxloc", or "minloc" (default: "sum"). ++ ++Arguments: ++ NUMBER Integer to use in the scan operation. ++ ++ NAME Array variable in which to receive the result and, in ++ the case of maxloc and minloc, the associated rank. ++ ++In an inclusive-scan operation, each process i presents a number, ++a[i]. Once all processes in the MPI job have presented their number, ++the command returns a[0] to rank 0, a[0]+a[1] to rank 1, ++a[0]+a[1]+a[2] to rank 2, and so forth. The -O option enables "+" to ++be replaced with other operations. ++ ++Inclusive scans can be useful for assigning a unique index to each ++process in the MPI job. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_scan builtin. */ ++int ++mpi_scan_builtin (list) ++ WORD_LIST *list; ++{ ++ return reduction_like (list, "mpi_scan", MPI_Scan); ++} ++ ++$BUILTIN mpi_exscan ++$FUNCTION mpi_exscan_builtin ++$SHORT_DOC mpi_exscan number name ++Perform an exclusive scan across all processes in the same MPI job. ++ ++ -O OPERATION Operation to perform. Must be one of "max", "min", ++ "sum", "prod", "land", "band", "lor", "bor", "lxor", ++ "bxor", "maxloc", or "minloc" (default: "sum"). ++ ++Arguments: ++ NUMBER Integer to use in the scan operation. ++ ++ NAME Array variable in which to receive the result and, in ++ the case of maxloc and minloc, the associated rank. ++ ++In a exclusive-scan operation, each process i presents a number, a[i]. ++Once all processes in the MPI job have presented their number, the ++command assigns a[0] to NAME on rank 1, a[0]+a[1] to NAME on rank 2, ++a[0]+a[1]+a[2] to NAME on rank 3, and so forth. No assignment is ++performed on rank 0. The -O option enables "+" to be replaced with ++other operations. ++ ++Exclusive scans can be useful for assigning a unique index to each ++process in the MPI job. ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_exscan builtin. */ ++int ++mpi_exscan_builtin (list) ++ WORD_LIST *list; ++{ ++ return reduction_like (list, "mpi_exscan", MPI_Exscan); ++} ++ ++$BUILTIN mpi_allreduce ++$FUNCTION mpi_allreduce_builtin ++$SHORT_DOC mpi_allreduce number name ++Reduce numbers from all processes in an MPI job to a single number. ++ ++Options: ++ ++ -O OPERATION Operation to perform. Must be one of "max", "min", ++ "sum", "prod", "land", "band", "lor", "bor", "lxor", ++ "bxor", "maxloc", or "minloc" (default: "sum"). ++ ++Arguments: ++ NUMBER Integer to use in the allreduce operation. ++ ++ NAME Array variable in which to receive the result and, in ++ the case of maxloc and minloc, the associated rank. ++ ++In an all-reduce operation, each process i presents a number, a[i]. ++Once all processes in the MPI job have presented their number, the ++command returns a[0]+a[1]+...+a[n-1] to all ranks. The -O option ++enables "+" to be replaced with other operations. ++ ++All-reduces can be useful for reaching global agreement (e.g., of a ++termination condition). ++ ++Exit Status: ++Returns 0 unless an invalid option is given or an error occurs. ++$END ++ ++/* Here is the mpi_allreduce builtin. */ ++int ++mpi_allreduce_builtin (list) ++ WORD_LIST *list; ++{ ++ return reduction_like (list, "mpi_allreduce", MPI_Allreduce); ++} +diff -Naur bash-4.3/config.h.in mpibash-4.3/config.h.in +--- bash-4.3/config.h.in 2013-06-29 15:35:33.000000000 -0600 ++++ mpibash-4.3/config.h.in 2014-05-13 11:27:37.314100671 -0600 +@@ -1147,6 +1147,12 @@ + /* Define if you have the `__argz_stringify' function. */ + #undef HAVE___ARGZ_STRINGIFY + ++/* Define if you have both the <libcircle.h> header file and the libcircle library. */ ++#undef HAVE_LIBCIRCLE ++ ++/* Define if you have the `CIRCLE_cb_reduce_op' function. */ ++#undef HAVE_CIRCLE_CB_REDUCE_OP ++ + /* End additions for lib/intl */ + + #include "config-bot.h" +diff -Naur bash-4.3/configure.ac mpibash-4.3/configure.ac +--- bash-4.3/configure.ac 2014-02-11 08:37:53.000000000 -0700 ++++ mpibash-4.3/configure.ac 2014-05-13 11:27:37.302100179 -0600 +@@ -24,7 +24,7 @@ + AC_REVISION([for Bash 4.3, version 4.063])dnl + + define(bashvers, 4.3) +-define(relstatus, release) ++define(relstatus, MPI) + + AC_INIT([bash], bashvers-relstatus, [bug-bash@gnu.org]) + +@@ -813,6 +813,21 @@ + fi + ]) + ++dnl Ensure that we can find an MPI library. ++AC_CHECK_FUNCS([MPI_Init], [], [ ++ AC_MSG_ERROR([Cannot continue without MPI. Consider specifying CC=mpicc.])]) ++ ++dnl If we have Libcircle, use it, too. ++AC_SEARCH_LIBS([CIRCLE_cb_create], [circle], [AC_CHECK_HEADERS([libcircle.h])]) ++if test "x$ac_cv_header_libcircle_h" = xyes; then ++ libcircle_make_prefix="" ++ AC_DEFINE([HAVE_LIBCIRCLE], [1], [Define if you have the Libcircle header and library.]) ++ AC_CHECK_FUNCS([CIRCLE_cb_reduce_op]) ++else ++ libcircle_make_prefix="#" ++fi ++AC_SUBST([CIRCLE], [$libcircle_make_prefix]) ++ + BASH_CHECK_DECL(strtoimax) + BASH_CHECK_DECL(strtol) + BASH_CHECK_DECL(strtoll) +diff -Naur bash-4.3/Makefile.in mpibash-4.3/Makefile.in +--- bash-4.3/Makefile.in 2014-01-25 14:27:30.000000000 -0700 ++++ mpibash-4.3/Makefile.in 2014-05-13 11:27:37.314100671 -0600 +@@ -104,7 +104,7 @@ + VERSPROG = bashversion$(EXEEXT) + VERSOBJ = bashversion.$(OBJEXT) + +-Program = bash$(EXEEXT) ++Program = mpibash$(EXEEXT) + Version = @BASHVERS@ + PatchLevel = `$(BUILD_DIR)/$(VERSPROG) -p` + RELSTATUS = @RELSTATUS@ +diff -Naur bash-4.3/shell.c mpibash-4.3/shell.c +--- bash-4.3/shell.c 2014-01-14 06:04:32.000000000 -0700 ++++ mpibash-4.3/shell.c 2014-05-13 11:27:37.314100671 -0600 +@@ -107,6 +107,13 @@ + extern char *primary_prompt, *secondary_prompt; + extern char *this_command_name; + ++extern void initialize_mpi __P((int, char **)); ++extern void finalize_mpi __P((void)); ++#ifdef HAVE_LIBCIRCLE ++extern void initialize_libcircle __P((int, char **)); ++extern void finalize_libcircle __P((void)); ++#endif ++ + /* Non-zero means that this shell has already been run; i.e. you should + call shell_reinitialize () if you need to start afresh. */ + int shell_initialized = 0; +@@ -324,7 +331,7 @@ + static void init_interactive_script __P((void)); + + static void set_shell_name __P((char *)); +-static void shell_initialize __P((void)); ++static void shell_initialize __P((int, char **)); + static void shell_reinitialize __P((void)); + + static void show_shell_usage __P((FILE *, int)); +@@ -561,7 +568,7 @@ + + /* From here on in, the shell must be a normal functioning shell. + Variables from the environment are expected to be set, etc. */ +- shell_initialize (); ++ shell_initialize (argc, argv); + + set_default_lang (); + set_default_locale_vars (); +@@ -941,6 +948,12 @@ + end_job_control (); + #endif /* JOB_CONTROL */ + ++#ifdef HAVE_LIBCIRCLE ++ finalize_libcircle (); ++#else ++ finalize_mpi (); ++#endif ++ + /* Always return the exit status of the last command to our parent. */ + sh_exit (s); + } +@@ -1691,7 +1704,9 @@ + /* Do whatever is necessary to initialize the shell. + Put new initializations in here. */ + static void +-shell_initialize () ++shell_initialize (argc, argv) ++ int argc; ++ char **argv; + { + char hostname[256]; + +@@ -1760,6 +1775,17 @@ + initialize_shell_options (privileged_mode||running_setuid); + initialize_bashopts (privileged_mode||running_setuid); + #endif ++ ++ /* Initialize Libcircle and MPI. */ ++#ifdef HAVE_LIBCIRCLE ++ initialize_libcircle (argc, argv); ++ initialize_mpi (argc, argv); ++ bind_variable ("libcircle", "yes", 0); ++#else ++ initialize_mpi (argc, argv); ++ bind_variable ("libcircle", "no", 0); ++#endif ++ bind_variable ("mpibash", "yes", 0); + } + + /* Function called by main () when it appears that the shell has already diff --git a/var/spack/packages/mpibash/package.py b/var/spack/packages/mpibash/package.py new file mode 100644 index 0000000000..d0f6dafed6 --- /dev/null +++ b/var/spack/packages/mpibash/package.py @@ -0,0 +1,32 @@ +import os +from spack import * + +class Mpibash(Package): + """Parallel scripting right from the Bourne-Again Shell (Bash)""" + homepage = "http://www.ccs3.lanl.gov/~pakin/software/mpibash-4.3.html" + + version('4.3', '81348932d5da294953e15d4814c74dd1', + url="http://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz") + + # patch -p1 < ../mpibash-4.3.patch + patch('mpibash-4.3.patch', level=1, when='@4.3') + + # above patch modifies configure.ac + depends_on('autoconf') + + # uses MPI_Exscan which is in MPI-1.2 and later + depends_on('mpi@1.2:') + + depends_on('libcircle') + + def install(self, spec, prefix): + # run autoconf to rebuild configure + autoconf = which('autoconf') + autoconf() + + configure("--prefix=" + prefix, + "CC=mpicc") + + make(parallel=False) + + make("install") |