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 <alain@miniussi.net>
+
+// 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 <alain@miniussi.net>
+
+// 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 <alain@miniussi.net>
+
+// 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

