On Wed, 2012-11-28 at 14:22 -0600, Hal Finkel wrote: 
> > So, to summarize, we have 3 issues:
> > 1) syntax: lower vs upper case and mt->threading.
> > 2) throw an exception if the requested level is not available
> > 3) macro to control availability of MPI[1|2|3] features

In the attached patch:
1 -> done
3 -> not done, I think those macro should be introduced separately, not
in the same commit.
2 -> done, but more precisely:
 The ctors that took one level requirement now takes a preferred and a
required level. If the required level could not be provided, an
exception is thrown from the ctor *after* MPI_Finalize is call.
This seems necessary since otherwise, MPI_Abort would get called in the
dtor and the application would quit without MPI_Finalize getting called.
 Also, that behavior introduces an error that does not mirror an MPI
error (in the MPI standard). Seems to be the first one, which explain
that I modified the exception hierarchy: We now have a base generalist
exception class (which only take a message) and an derived api_exception
that correspond to the previous exception class (and that contains all
the info related with the MPI standard error). Since the code often ask
a corresponding MPI error code, I choose to bind it to MPI_SUCCESS by
default (indicating that as far as the MPI standard is concerned, there
is no problem) api_exception systematically overrides that code.

I also added a istream>>level operator, is nothing else, it will enable
lexical_cast.

Thanks for reading !

Alain


> > 1) ok, I like it better, too :-)
> > 
> > 2) exceptions  -> if I understand, it is proposed that we consider
> > the
> > unavailability of the requested level as an error and let the flag
> > 'throw_on_error' decide what to do ?
> > A few small concerns
> >  * the MPI standard does not seems to consider this an error, so we
> >  do a
> 
> The standard does not consider it an error, but it also assumes that the 
> caller will check the provided level. This is a bad assumption, and we must 
> have a better option ;)
> 
> > semantic change (if I understand correctly 8.7 in MPI3)
> >  * it is not clear that we are allowed to query the available
> >  threading
> > support level (actually, 8.7 seems to indicated that we can't,
> > although
> > there is some weird text associated with the thread_level key of
> > INFO_ENV). That indicates that the user has no way of probing the
> > value
> > before initializing. So if we consider the use case of a user who
> > wants
> > to generally throw on error *and* is willing to adapt to the
> > available
> > threading level, such a change will make that impossible.
> 
> Okay, good point, and calling MPI_Init multiple times may not be safe. How 
> about this: have the constructors take both a 'preferred' and 'required' 
> level; call MPI_Init with the preferred level and throw the exception only if 
> the provided level is below the required level. This has the advantage of 
> being safe and easy, forcing the programming to think about the options, and 
> is not functionally limiting. If a program really has requirements that 
> cannot be expressed as a range in this way, they can always set the required 
> level to the lowest one and fall back to explicit post-construction tests.
> 
> >  * we can easily imagine ignoring the result of "provided" level (by
> > default, open MPI only support "single", so in theory, one should not
> > use threads at all with open MPI. Multiple must be explicitly
> > specified
> > during build, and is possibly slow, and there is nothing in between)
> 
> Yes; unfortunately, this is a (somewhat common, although certainly not 
> universal) implementation deficiency.
> 
> > - We cannot fix that with bit magic (allowing stuff like
> > threading::funneled|threadin::mandatory for example) since the
> > numerical
> > value are not specified by the standard.
> > - Adding a boolean flag would be clumsy (we already have one with
> > default value)
> > - we could allow runtime modification of the throw_on_error flag, but
> > then, it is not clear that the most common scenario (and the one
> > matching the MPI-C behavior) would be the easiest.
> > 
> > On the other hand, if the user wants to enforce the threading level:
> > mpi::environment env(threading::funneled, true);
> > assert(env.thread_level() >= threading::funneled); /* or an 'if'
> > expression, or we could add an overload to the boost mpi abort to
> > make
> > it more assert like:
> > env.assert(env.thread_level()>=threading::funneled, "requested ...
> > blahh"); */
> > which is basically one more line.
> 
> I don't think is good because it still makes it easier to write incorrect 
> code than it does to write correct code.
> 
> > 
> > Any thought ?
> > 
> > 3) Ok, actually the BOOST_MPI_HAS_NOARG_INITIALIZATION would fall in
> > that category (the feature is mandatory since MPI2 I think).
> > 
> > One last question: in my patch, I am still using MPI_Init instead of
> > the
> > supposedly equivalent MPI_Init(..single..) (keept for backward
> > compatibility) I propose to only use MPI_Init_thread in the
> > implementation.
> 
> This is fine with me, so long as we're not keeping compatibility with MPI 1 
> implementations. Are we?
> 
> Thanks again,
> Hal
> 
> > 
> > Thanks for reading !
> > 
> > Alain
> > 
> > 
> >  
> > 
> >    
> > 
> > On Wed, 2012-11-28 at 09:21 -0600, Hal Finkel wrote:
> > > ----- Original Message -----
> > > > From: "Matthias Troyer" <[email protected]>
> > > > To: "alain miniussi" <[email protected]>, "Discussion of
> > > > Boost.MPI development" <[email protected]>
> > > > Sent: Wednesday, November 28, 2012 8:25:18 AM
> > > > Subject: Re: [Boost-mpi] Thread API
> > > > 
> > > > Hi Alain,
> > > > 
> > > > 
> > > > On Nov 27, 2012, at 5:11 PM, Alain O Miniussi
> > > > <[email protected]>
> > > > wrote:
> > > > 
> > > > > Hi,
> > > > > 
> > > > > I have a tentative patch that is supposed to  provide binding
> > > > > to
> > > > > the MPI
> > > > > thread API. What is the best way to have it reviewed ?
> > > > 
> > > > Thank you for your work. I have a few stylistic comments - shall
> > > > I
> > > > send them to you off-list, or shall we discuss them on our new
> > > > mailing list?
> > > 
> > > If you don't mind, I'd prefer on-list reviews (even for stylistic
> > > matters). That way we can all benefit from your advice.
> > > 
> > > I also have a few comments:
> > > 
> > > +enum level {
> > > +  /** Only one thread will execute.
> > > +   */
> > > +  SINGLE     = MPI_THREAD_SINGLE,
> > > +  /** Only main thread will do MPI calls.
> > > 
> > > I think that we should use lower-case enum constant names (single
> > > instead of SINGLE).
> > > 
> > > +  mt::level mt_level = mt::MULTIPLE;
> > > +  boost::mpi::environment env(argc, argv, mt_level);
> > > +  mt::level provided = env.thread_level();
> > > +  std::cout << "Asked:" << mt_level << ", provided: " << provided
> > > << '\n';
> > > +  BOOST_CHECK((provided >= mt::SINGLE && provided <=
> > > mt::MULTIPLE));
> > > 
> > > I have a lot of code that looks like this ;) -- but I think that it
> > > could be greatly simplified. How about if the environment
> > > constructor throws an exception if the provided level is less than
> > > the requested level. This way, in the common case where the
> > > program has no fall-back provisions, we don't accidentally
> > > continue under an invalid environment (many programs don't
> > > explicitly check the provided level -- and this obviously leads to
> > > odd behavior and crashes).
> > > 
> > > Thanks for working on this!
> > > 
> > >  -Hal
> > > 
> > > > 
> > > > > It might be a ticket
> > > > > buthttps://svn.boost.org/trac/boost/report/15the
> > > > > referenced maintainer is Doug
> > > > > (https://svn.boost.org/trac/boost/report/15)
> > > > > and, probably since I have no userid in the tracker, I won't be
> > > > > able to
> > > > > change it.
> > > > 
> > > > I'll try to find out how to change it. Doug does not have time
> > > > anymore.
> > > > 
> > > > > Just in case, there is a patch in attachment (against rev 81596
> > > > > of
> > > > > trunk).
> > > > 
> > > > 
> > > > Thank you!
> > > > 
> > > > Matthias
> > > > 
> > > > _______________________________________________
> > > > Boost-mpi mailing list
> > > > [email protected]
> > > > http://lists.boost.org/mailman/listinfo.cgi/boost-mpi
> > > > 
> > > 
> > 
> > 
> > 
> 

-- 
Alain Miniussi
Responsable Tech. Centre de Calcul Haute Performance
Obs. de la Côte d'Azur |Mont Gros: +33 4 92 00 30 09
BP 4229                |Sophia :   +33 4 83 61 85 44
06304 Nice Cedex 4     |https://crimson.oca.eu
Index: boost/mpi/exception.hpp
===================================================================
--- boost/mpi/exception.hpp	(revision 81596)
+++ boost/mpi/exception.hpp	(working copy)
@@ -35,14 +35,9 @@
   /**
    * Build a new @c exception exception.
    *
-   *   @param routine The MPI routine in which the error
-   *   occurred. This should be a pointer to a string constant: it
-   *   will not be copied.
-   *
-   *   @param result_code The result code returned from the MPI
-   *   routine that aborted with an error.
+   *   @param message A descriptive message explaining the error.
    */
-  exception(const char* routine, int result_code);
+  exception(const std::string& msg);
 
   virtual ~exception() throw();
 
@@ -54,9 +49,46 @@
     return this->message.c_str();
   }
 
+  /**
+   * @brief Retrieve the result code returned from the MPI routine
+   * that reported the error, if any. Sub classes should redefine this
+   * as necessary.
+   */
+  virtual int result_code() const { return MPI_SUCCESS; }
+
+ protected:
+  /// The formatted error message
+  std::string message;
+};
+
+/** @brief Catch-all exception class for MPI errors.
+ *
+ * Instances of this class will be thrown when an MPI error
+ * occurs. MPI failures that trigger these exceptions may or may not
+ * be recoverable, depending on the underlying MPI
+ * implementation. Consult the documentation for your MPI
+ * implementation to determine the effect of MPI errors.
+ */
+class BOOST_MPI_DECL api_exception : public exception
+{
+ public:
+  /**
+   * Build a new @c exception exception.
+   *
+   *   @param routine The MPI routine in which the error
+   *   occurred. This should be a pointer to a string constant: it
+   *   will not be copied.
+   *
+   *   @param result_code The result code returned from the MPI
+   *   routine that aborted with an error.
+   */
+  api_exception(const char* routine, int result_code);
+
+  virtual ~api_exception() throw();
+
   /** Retrieve the name of the MPI routine that reported the error. */
   const char* routine() const { return routine_; }
-
+  
   /**
    * @brief Retrieve the result code returned from the MPI routine
    * that reported the error.
@@ -80,9 +112,6 @@
 
   /// The failed result code reported by the MPI implementation.
   int result_code_;
-
-  /// The formatted error message
-  std::string message;
 };
 
 /**
@@ -95,8 +124,8 @@
  {                                                                      \
    int _check_result = MPIFunc Args;                                    \
    if (_check_result != MPI_SUCCESS)                                    \
-     boost::throw_exception(boost::mpi::exception(#MPIFunc,   \
-                                                             _check_result)); \
+     boost::throw_exception(boost::mpi::api_exception(#MPIFunc,             \
+                                                      _check_result));  \
  }
 
 } } // end namespace boost::mpi
Index: boost/mpi/nonblocking.hpp
===================================================================
--- boost/mpi/nonblocking.hpp	(revision 81596)
+++ boost/mpi/nonblocking.hpp	(working copy)
@@ -91,7 +91,7 @@
         // We don't have a notion of empty requests or status objects,
         // so this is an error.
         if (index == MPI_UNDEFINED)
-          boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
+          boost::throw_exception(api_exception("MPI_Waitany", MPI_ERR_REQUEST));
 
         // Find the iterator corresponding to the completed request.
         current = first;
Index: boost/mpi/environment.hpp
===================================================================
--- boost/mpi/environment.hpp	(revision 81596)
+++ boost/mpi/environment.hpp	(working copy)
@@ -17,9 +17,47 @@
 #include <boost/noncopyable.hpp>
 #include <boost/optional.hpp>
 #include <string>
+#include <iosfwd>
 
 namespace boost { namespace mpi {
+namespace threading {
+/** @brief specify the supported threading level.
+ * 
+ * Based on MPI 2 standard/8.7.3
+ */
+enum level {
+  /** Only one thread will execute. 
+   */
+  single     = MPI_THREAD_SINGLE,
+  /** Only main thread will do MPI calls.
+   * 
+   * The process may be multi-threaded, but only the main 
+   * thread will make MPI calls (all MPI calls are ``funneled''
+   * to the main thread).
+   */
+  funneled   = MPI_THREAD_FUNNELED,
+  /** Only one thread at the time do MPI calls.
+   * 
+   * The process may be multi-threaded, and multiple 
+   * threads may make MPI calls, but only one at a time:
+   * MPI calls are not made concurrently from two distinct 
+   * threads (all MPI calls are ``serialized'').
+   */
+  serialized = MPI_THREAD_SERIALIZED,
+  /** Multiple thread may do MPI calls.
+   * 
+   * Multiple threads may call MPI, with no restrictions.
+   */
+  multiple   = MPI_THREAD_MULTIPLE
+};
 
+/** Formated output for threading level. */
+std::ostream& operator<<(std::ostream& out, level l);
+
+/** Formated output for threading level. */
+std::istream& operator>>(std::istream& in, level l);
+
+} // namespace threading
 /** @brief Initialize, finalize, and query the MPI environment.
  *
  *  The @c environment class is used to initialize, finalize, and
@@ -62,6 +100,29 @@
    *  program if it is destructed due to an uncaught exception.
    */
   explicit environment(bool abort_on_exception = true);
+  /** Initialize the MPI environment. 
+   *
+   *  If the MPI environment has not already been initialized,
+   *  initializes MPI with a call to @c MPI_Init_thread. Since this
+   *  constructor does not take command-line arguments (@c argc and @c
+   *  argv), it is only available when the underlying MPI
+   *  implementation supports calling @c MPI_Init with @c NULL
+   *  arguments, indicated by the macro @c
+   *  BOOST_MPI_HAS_NOARG_INITIALIZATION.
+   *
+   *  If the required threading support level cannot be provided, 
+   *  construction will throw and mpi will be finalized.
+   *
+   *  @param prefered the prefered level of threading support, will 
+   *         try to meet that request if possible.
+   *
+   *  @param required the minimal level of threading support.
+   *
+   *  @param abort_on_exception When true, this object will abort the
+   *  program if it is destructed due to an uncaught exception.
+   */
+  explicit environment(threading::level prefered, threading::level required,
+                       bool abort_on_exception = true);
 #endif
 
   /** Initialize the MPI environment.
@@ -80,6 +141,33 @@
    */
   environment(int& argc, char** &argv, bool abort_on_exception = true);
 
+  /** Initialize the MPI environment.
+   *
+   *  If the MPI environment has not already been initialized,
+   *  initializes MPI with a call to @c MPI_Init_thread.
+   *
+   *  If the required threading support level cannot be provided, 
+   *  construction will throw and mpi will be finalized.
+   *
+   *  @param argc The number of arguments provided in @p argv, as
+   *  passed into the program's @c main function.
+   *
+   *  @param argv The array of argument strings passed to the program
+   *  via @c main.
+   *
+   *  @param prefered the prefered level of threading support, will 
+   *         try to meet that request if possible.
+   *
+   *  @param required the minimal level of threading support, this constructor 
+   *         will throw if the requirement is not fulfilled.
+   *
+   *  @param abort_on_exception When true, this object will abort the
+   *  program if it is destructed due to an uncaught exception.
+   */
+  environment(int& argc, char** &argv, 
+              threading::level prefered, threading::level required,
+              bool abort_on_exception = true);
+
   /** Shuts down the MPI environment.
    *
    *  If this @c environment object was used to initialize the MPI
@@ -185,13 +273,26 @@
    */
   static std::string processor_name();
 
+  /** Query the current level of thread support.
+   */
+  static threading::level thread_level();
+
+  /** Are we in the main thread?
+   */
+  static bool main_thread();
+
 private:
+  /// Code factorization on ctor.
+  void call_mpi_init(int* argc, char*** argv,
+                     threading::level prefered, threading::level required);
+
+private:
   /// Whether this environment object called MPI_Init
   bool i_initialized;
 
   /// Whether we should abort if the destructor is
   bool abort_on_exception;
-
+  
   /// The number of reserved tags.
   static const int num_reserved_tags = 1;
 };
Index: libs/mpi/test/mt_level_test.cpp
===================================================================
--- libs/mpi/test/mt_level_test.cpp	(revision 0)
+++ libs/mpi/test/mt_level_test.cpp	(revision 0)
@@ -0,0 +1,26 @@
+// Copyright (C) 2005-2006 Douglas Gregor <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent 
+// on the underlying implementation those threading 
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/test/minimal.hpp>
+
+using namespace boost::mpi;
+using namespace std;
+
+int test_main(int argc, char* argv[])
+{
+  using namespace boost::mpi::threading;
+  BOOST_CHECK((single < funneled));
+  BOOST_CHECK((funneled < serialized));
+  BOOST_CHECK((serialized < multiple));
+
+  return 0;
+}
Index: libs/mpi/test/mt_init_failed_test.cpp
===================================================================
--- libs/mpi/test/mt_init_failed_test.cpp	(revision 0)
+++ libs/mpi/test/mt_init_failed_test.cpp	(revision 0)
@@ -0,0 +1,37 @@
+// Copyright (C) 2005-2006 Alain Miniussi <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent 
+// on the underlying implementation those threading 
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/exception.hpp>
+#include <boost/test/minimal.hpp>
+
+namespace mpi = boost::mpi;
+namespace th  = boost::mpi::threading;
+using namespace std;
+
+bool do_init(int argc, char* argv[])
+{
+  bool success = false;
+  bool clean_failure = false;
+  try {
+    mpi::environment env(argc, argv, th::multiple, th::multiple);
+    success = env.thread_level() == th::multiple;
+  } catch (mpi::exception& e) {
+    clean_failure = true;
+  }
+  return success || clean_failure;
+}
+
+int test_main(int argc, char* argv[])
+{
+  BOOST_CHECK(do_init(argc,argv));
+  return 0;
+}
Index: libs/mpi/test/Jamfile.v2
===================================================================
--- libs/mpi/test/Jamfile.v2	(revision 81596)
+++ libs/mpi/test/Jamfile.v2	(working copy)
@@ -23,6 +23,9 @@
   [ mpi-test broadcast_test  : : : 2 17 ]
   [ mpi-test gather_test  ]
   [ mpi-test is_mpi_op_test : : : 1 ]
+  [ mpi-test mt_level_test : : : 1 4 ]
+  [ mpi-test mt_init_test : : : 1 4 ]
+  [ mpi-test mt_init_failed_test : : : 1 4 ]
   # Note: Microsoft MPI fails nonblocking_test on 1 processor
   [ mpi-test nonblocking_test ]
   [ mpi-test reduce_test  ]
Index: libs/mpi/test/mt_init_test.cpp
===================================================================
--- libs/mpi/test/mt_init_test.cpp	(revision 0)
+++ libs/mpi/test/mt_init_test.cpp	(revision 0)
@@ -0,0 +1,26 @@
+// Copyright (C) 2005-2006 Alain Miniussi <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent 
+// on the underlying implementation those threading 
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/test/minimal.hpp>
+
+using namespace boost::mpi;
+using namespace std;
+
+int test_main(int argc, char* argv[])
+{
+  // just test for one value, I could not find the doc in mpi.jam 
+  // to pass params through argc/argv
+  namespace th = threading;
+  boost::mpi::environment env(argc, argv, th::multiple, th::single);
+  BOOST_CHECK((env.thread_level() >= th::single));
+  return 0;
+}
Index: libs/mpi/src/request.cpp
===================================================================
--- libs/mpi/src/request.cpp	(revision 81596)
+++ libs/mpi/src/request.cpp	(working copy)
@@ -42,13 +42,13 @@
       // one when throwing the exception.
       if (stats[0].MPI_ERROR == MPI_SUCCESS 
           || stats[0].MPI_ERROR == MPI_ERR_PENDING)
-        boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
+        boost::throw_exception(api_exception("MPI_Waitall", stats[1].MPI_ERROR));
       else
-        boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
+        boost::throw_exception(api_exception("MPI_Waitall", stats[0].MPI_ERROR));
     } else if (error_code != MPI_SUCCESS) {
       // There was an error somewhere in the MPI_Waitall call; throw
       // an exception for it.
-      boost::throw_exception(exception("MPI_Waitall", error_code));
+      boost::throw_exception(api_exception("MPI_Waitall", error_code));
     } 
 
     // No errors. Returns the first status structure.
@@ -85,13 +85,13 @@
       // one when throwing the exception.
       if (stats[0].MPI_ERROR == MPI_SUCCESS 
           || stats[0].MPI_ERROR == MPI_ERR_PENDING)
-        boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
+        boost::throw_exception(api_exception("MPI_Testall", stats[1].MPI_ERROR));
       else
-        boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
+        boost::throw_exception(api_exception("MPI_Testall", stats[0].MPI_ERROR));
     } else if (error_code != MPI_SUCCESS) {
       // There was an error somewhere in the MPI_Testall call; throw
       // an exception for it.
-      boost::throw_exception(exception("MPI_Testall", error_code));
+      boost::throw_exception(api_exception("MPI_Testall", error_code));
     }
 
     // No errors. Returns the second status structure if the send has
Index: libs/mpi/src/exception.cpp
===================================================================
--- libs/mpi/src/exception.cpp	(revision 81596)
+++ libs/mpi/src/exception.cpp	(working copy)
@@ -10,20 +10,27 @@
 
 namespace boost { namespace mpi {
 
-exception::exception(const char* routine, int result_code)
-  : routine_(routine), result_code_(result_code)
+exception::exception(const std::string& msg)
+  : message(msg)
 {
+}
+
+exception::~exception() throw() { }
+
+
+api_exception::api_exception(const char* routine, int result_code)
+  : exception(routine), routine_(routine), result_code_(result_code)
+{
   // Query the MPI implementation for its reason for failure
   char buffer[MPI_MAX_ERROR_STRING];
   int len;
   MPI_Error_string(result_code, buffer, &len);
 
   // Construct the complete error message
-  message.append(routine_);
   message.append(": ");
   message.append(buffer, len);
 }
 
-exception::~exception() throw() { }
+api_exception::~api_exception() throw() { }
 
 } } // end namespace boost::mpi
Index: libs/mpi/src/environment.cpp
===================================================================
--- libs/mpi/src/environment.cpp	(revision 81596)
+++ libs/mpi/src/environment.cpp	(working copy)
@@ -8,23 +8,102 @@
 #include <boost/mpi/environment.hpp>
 #include <boost/mpi/exception.hpp>
 #include <boost/mpi/detail/mpi_datatype_cache.hpp>
+#include <boost/algorithm/string.hpp>
 #include <cassert>
 #include <exception>
 #include <stdexcept>
+#include <ostream>
+#include <sstream>
 
 namespace boost { namespace mpi {
+namespace threading {
+std::ostream&
+operator<<(std::ostream& out, level l)
+{
+  switch(l) {
+  case single:
+    out << "single";
+    break;
+  case funneled:
+    out << "funneled";
+    break;
+  case serialized:
+    out << "serialized";
+    break;
+  case multiple:
+    out << "multiple";
+    break;
+  default:
+    out << "<level error>[" << int(l) << ']';
+    break;
+  }
+  return out;
+}
 
+std::istream&
+operator>>(std::istream& in, level l)
+{
+  std::string buf;
+  in >> buf;
+  if (in.good()) {
+    boost::to_upper(buf);
+    if (buf == "SINGLE") {
+      l = single;
+    } else if (buf == "FUNNELED") {
+      l = funneled;
+    } else if (buf == "SERIALIZED") {
+      l = serialized;
+    } else if (buf == "MULTIPLE") {
+      l = multiple;
+    } else {
+      in.setstate(std::ios_base::failbit);
+    }
+  }
+  return in;
+}
+} // namespace threading
+
+void
+environment::call_mpi_init(int* argc, char*** argv,
+                           threading::level prefered, threading::level required)
+{
+  BOOST_ASSERT(required <= prefered);
+  if (!initialized()) {
+    int provided;
+    BOOST_MPI_CHECK_RESULT(MPI_Init_thread, 
+                           (argc, argv, int(prefered), &provided ));
+    if (threading::level(provided) < required) {
+      // no cleanup necessary in dtor
+      i_initialized = false;
+      // we need to finalize right here so that the
+      // the aplication does not leave without finalization.
+      BOOST_MPI_CHECK_RESULT(MPI_Finalize, ());
+      std::ostringstream fmt;
+      fmt << "Asked for prefered threading support level '" 
+          << prefered << "' with minimum required '" 
+          << required << "', got '" << threading::level(provided) << "'\n";
+      boost::throw_exception(boost::mpi::exception(fmt.str()));
+    } else {
+      i_initialized = true;
+    }
+  }
+  MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+}
+
 #ifdef BOOST_MPI_HAS_NOARG_INITIALIZATION
 environment::environment(bool abort_on_exception)
   : i_initialized(false),
     abort_on_exception(abort_on_exception)
 {
-  if (!initialized()) {
-    BOOST_MPI_CHECK_RESULT(MPI_Init, (0, 0));
-    i_initialized = true;
-  }
+  call_mpi_init(0, 0, threading::single, threading::single);
+}
 
-  MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+environment::environment(threading::level prefered, threading::level required,
+                         bool abort_on_exception)
+  : i_initialized(false),
+    abort_on_exception(abort_on_exception)
+{
+  call_mpi_init(0, 0, prefered, required);
 }
 #endif
 
@@ -32,12 +111,16 @@
   : i_initialized(false),
     abort_on_exception(abort_on_exception)
 {
-  if (!initialized()) {
-    BOOST_MPI_CHECK_RESULT(MPI_Init, (&argc, &argv));
-    i_initialized = true;
-  }
+  call_mpi_init(&argc, &argv, threading::single, threading::single);
+}
 
-  MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+environment::environment(int& argc, char** &argv,
+                         threading::level prefered, threading::level required,
+                         bool abort_on_exception)
+  : i_initialized(false),
+    abort_on_exception(abort_on_exception)
+{
+  call_mpi_init(&argc, &argv, prefered, required);
 }
 
 environment::~environment()
@@ -122,4 +205,20 @@
   return std::string(name, len);
 }
 
+threading::level environment::thread_level()
+{
+  int level;
+
+  BOOST_MPI_CHECK_RESULT(MPI_Query_thread, (&level));
+  return static_cast<threading::level>(level);
+}
+
+bool environment::main_thread()
+{
+  int isit;
+
+  BOOST_MPI_CHECK_RESULT(MPI_Is_thread_main, (&isit));
+  return bool(isit);
+}
+
 } } // end namespace boost::mpi
_______________________________________________
Boost-mpi mailing list
[email protected]
http://lists.boost.org/mailman/listinfo.cgi/boost-mpi

Reply via email to