$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r84678 - in trunk: boost/thread libs/thread/test/sync/futures/promise libs/thread/test/threads/thread/constr
From: vicente.botet_at_[hidden]
Date: 2013-06-07 15:03:49
Author: viboes
Date: 2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)
New Revision: 84678
URL: http://svn.boost.org/trac/boost/changeset/84678
Log:
Thread: fix promise set_at_..._thread_exit; Added preconditions.
Text files modified: 
   trunk/boost/thread/future.hpp                                                       |   148 +++++++++++++++++++++++++++++++-------- 
   trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp   |    19 ++++-                                   
   trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp |    25 +++++-                                  
   trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp  |     4                                         
   trunk/libs/thread/test/threads/thread/constr/FrvalueArgs_pass.cpp                   |    51 +++++++++++++                           
   5 files changed, 206 insertions(+), 41 deletions(-)
Modified: trunk/boost/thread/future.hpp
==============================================================================
--- trunk/boost/thread/future.hpp	Fri Jun  7 13:37:04 2013	(r84677)
+++ trunk/boost/thread/future.hpp	2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)	(r84678)
@@ -429,6 +429,7 @@
                   throw_exception(promise_already_satisfied());
               }
               exception=e;
+              this->is_constructed = true;
               get_current_thread_data()->make_ready_at_thread_exit(shared_from_this());
             }
 
@@ -1399,7 +1400,11 @@
         BOOST_THREAD_FUTURE<Rp>
         make_future_deferred_continuation_shared_state(boost::unique_lock<boost::mutex> &lock, F& f, BOOST_THREAD_FWD_REF(Fp) c);
 #endif
-
+#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
+        template <class F, class Rp>
+        typename BOOST_THREAD_FUTURE<Rp>::value_type
+        make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_FUTURE<Rp>& f);
+#endif
     }
 
     template <typename R>
@@ -1525,6 +1530,15 @@
         inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE&)>::type>
         then(launch policy, BOOST_THREAD_FWD_REF(F) func);
 #endif
+#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
+        inline
+        typename enable_if_c<
+          is_future<value_type>::value,
+          BOOST_THREAD_FUTURE<typename value_type::value_type>
+        >::type
+        unwrap();
+#endif
+
     };
 
     BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE<T> BOOST_THREAD_DCL_MOVABLE_END
@@ -1639,6 +1653,15 @@
         inline BOOST_THREAD_FUTURE<typename boost::result_of<F(shared_future&)>::type>
         then(launch policy, BOOST_THREAD_FWD_REF(F) func);
 #endif
+#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
+        inline
+        typename enable_if_c<
+          is_future<value_type>::value,
+          BOOST_THREAD_FUTURE<typename value_type::value_type>
+        >::type
+        unwrap();
+#endif
+
     };
 
     BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future<T> BOOST_THREAD_DCL_MOVABLE_END
@@ -1703,7 +1726,7 @@
             {
                 boost::unique_lock<boost::mutex> lock(future_->mutex);
 
-                if(!future_->done)
+                if(!future_->done && !future_->is_constructed)
                 {
                     future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
                 }
@@ -1785,7 +1808,11 @@
             }
             future_->mark_exceptional_finish_internal(p, lock);
         }
-
+        template <typename E>
+        void set_exception(E ex)
+        {
+          set_exception(copy_exception(ex));
+        }
         // setting the result with deferred notification
         void set_value_at_thread_exit(const R& r)
         {
@@ -1812,6 +1839,11 @@
           }
           future_->set_exception_at_thread_exit(e);
         }
+        template <typename E>
+        void set_exception_at_thread_exit(E ex)
+        {
+          set_exception_at_thread_exit(copy_exception(ex));
+        }
 
         template<typename F>
         void set_wait_callback(F f)
@@ -1872,7 +1904,7 @@
             {
                 boost::unique_lock<boost::mutex> lock(future_->mutex);
 
-                if(!future_->done)
+                if(!future_->done && !future_->is_constructed)
                 {
                     future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
                 }
@@ -1938,6 +1970,11 @@
             }
             future_->mark_exceptional_finish_internal(p, lock);
         }
+        template <typename E>
+        void set_exception(E ex)
+        {
+          set_exception(copy_exception(ex));
+        }
 
         // setting the result with deferred notification
         void set_value_at_thread_exit(R& r)
@@ -1957,6 +1994,11 @@
           }
           future_->set_exception_at_thread_exit(e);
         }
+        template <typename E>
+        void set_exception_at_thread_exit(E ex)
+        {
+          set_exception_at_thread_exit(copy_exception(ex));
+        }
 
         template<typename F>
         void set_wait_callback(F f)
@@ -2014,7 +2056,7 @@
             {
                 boost::unique_lock<boost::mutex> lock(future_->mutex);
 
-                if(!future_->done)
+                if(!future_->done && !future_->is_constructed)
                 {
                     future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock);
                 }
@@ -2083,6 +2125,11 @@
             }
             future_->mark_exceptional_finish_internal(p,lock);
         }
+        template <typename E>
+        void set_exception(E ex)
+        {
+          set_exception(copy_exception(ex));
+        }
 
         // setting the result with deferred notification
         void set_value_at_thread_exit()
@@ -2102,6 +2149,11 @@
           }
           future_->set_exception_at_thread_exit(e);
         }
+        template <typename E>
+        void set_exception_at_thread_exit(E ex)
+        {
+          set_exception_at_thread_exit(copy_exception(ex));
+        }
 
         template<typename F>
         void set_wait_callback(F f)
@@ -3607,12 +3659,13 @@
   {
 
     typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>&)>::type future_type;
+    BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
 
-    if (this->future_==0)
-    {
-      // fixme what to do when the future has no associated state?
-      return BOOST_THREAD_FUTURE<future_type>();
-    }
+//    if (this->future_==0)
+//    {
+//      // fixme what to do when the future has no associated state?
+//      return BOOST_THREAD_FUTURE<future_type>();
+//    }
 
     boost::unique_lock<boost::mutex> lock(this->future_->mutex);
     if (int(policy) & int(launch::async))
@@ -3630,7 +3683,8 @@
     else
     {
       // fixme what to do when the policy is invalid?
-      return BOOST_THREAD_FUTURE<future_type>();
+      BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
+      //return BOOST_THREAD_FUTURE<future_type>();
     }
 
   }
@@ -3641,13 +3695,14 @@
   {
 
     typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>&)>::type future_type;
+    BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
 
-    if (this->future_==0)
-    {
-      //BOOST_THREAD_LOG << "ERROR future::then " << this << BOOST_THREAD_END_LOG;
-      // fixme what to do when the future has no associated state?
-      return BOOST_THREAD_FUTURE<future_type>();
-    }
+//    if (this->future_==0)
+//    {
+//      //BOOST_THREAD_LOG << "ERROR future::then " << this << BOOST_THREAD_END_LOG;
+//      // fixme what to do when the future has no associated state?
+//      return BOOST_THREAD_FUTURE<future_type>();
+//    }
 
     boost::unique_lock<boost::mutex> lock(this->future_->mutex);
     if (int(this->launch_policy()) & int(launch::async))
@@ -3666,7 +3721,8 @@
     else
     {
       // fixme what to do when the policy is invalid?
-      return BOOST_THREAD_FUTURE<future_type>();
+      BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
+      //return BOOST_THREAD_FUTURE<future_type>();
     }
   }
 
@@ -3731,12 +3787,13 @@
   {
 
     typedef typename boost::result_of<F(shared_future<R>&)>::type future_type;
+    BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
 
-    if (this->future_==0)
-    {
-      // fixme what to do when the future has no associated state?
-      return BOOST_THREAD_FUTURE<future_type>();
-    }
+//    if (this->future_==0)
+//    {
+//      // fixme what to do when the future has no associated state?
+//      return BOOST_THREAD_FUTURE<future_type>();
+//    }
 
     boost::unique_lock<boost::mutex> lock(this->future_->mutex);
     if (int(policy) & int(launch::async))
@@ -3754,7 +3811,8 @@
     else
     {
       // fixme what to do when the policy is invalid?
-      return BOOST_THREAD_FUTURE<future_type>();
+      BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
+      //return BOOST_THREAD_FUTURE<future_type>();
     }
 
   }
@@ -3766,12 +3824,13 @@
 
     typedef typename boost::result_of<F(shared_future<R>&)>::type future_type;
 
-    if (this->future_==0)
-    {
-      //BOOST_THREAD_LOG << "ERROR future::then " << this << BOOST_THREAD_END_LOG;
-      // fixme what to do when the future has no associated state?
-      return BOOST_THREAD_FUTURE<future_type>();
-    }
+    BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
+//    if (this->future_==0)
+//    {
+//      //BOOST_THREAD_LOG << "ERROR future::then " << this << BOOST_THREAD_END_LOG;
+//      // fixme what to do when the future has no associated state?
+//      return BOOST_THREAD_FUTURE<future_type>();
+//    }
 
     boost::unique_lock<boost::mutex> lock(this->future_->mutex);
     if (int(this->launch_policy()) & int(launch::async))
@@ -3790,11 +3849,36 @@
     else
     {
       // fixme what to do when the policy is invalid?
-      return BOOST_THREAD_FUTURE<future_type>();
+      BOOST_THREAD_ASSERT_PRECONDITION(false && "invalid launch parameter", std::logic_error("invalid launch parameter"));
+      //return BOOST_THREAD_FUTURE<future_type>();
     }
   }
 #endif
-
+#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
+  namespace detail
+  {
+    template <class Rp>
+    typename BOOST_THREAD_FUTURE<Rp>::value_type
+    make_future_unwrap_shared_state(boost::unique_lock<boost::mutex> &lock, BOOST_THREAD_FUTURE<Rp>& f)
+    {
+      shared_ptr<future_unwrap_shared_state<Rp> >
+          h(new future_unwrap_shared_state<Rp>(f, boost::forward<Fp>(c)));
+      f.future_->set_continuation_ptr(h, lock);
+      return BOOST_THREAD_FUTURE<Rp>(h);
+    }
+  }
+  template <typename R>
+  typename enable_if_c<
+    is_future<value_type>::value,
+    value_type>
+  >::type
+  future<R>::unwrap()
+  {
+    BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized())
+    boost::unique_lock<boost::mutex> lock(this->future_->mutex);
+    return boost::detail::make_future_unwrap_shared_state(lock, *this);
+  }
+#endif
 }
 
 #endif // BOOST_NO_EXCEPTION
Modified: trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp
==============================================================================
--- trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp	Fri Jun  7 13:37:04 2013	(r84677)
+++ trunk/libs/thread/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp	2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)	(r84678)
@@ -44,10 +44,14 @@
   }
 }
 
-//void func(boost::promise<int> p)
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+void func(boost::promise<int> p)
+#else
 boost::promise<int> p;
 void func()
+#endif
 {
+  //p.set_exception(boost::make_exception_ptr(3));
   p.set_exception_at_thread_exit(boost::make_exception_ptr(3));
 }
 
@@ -55,10 +59,14 @@
 {
   {
     typedef int T;
-    //boost::promise<T> p;
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+    boost::promise<T> p;
+    boost::future<T> f = p.get_future();
+    boost::thread(func, boost::move(p)).detach();
+#else
     boost::future<T> f = p.get_future();
-    //boost::thread(func, boost::move(p)).detach();
     boost::thread(func).detach();
+#endif
     try
     {
       f.get();
@@ -77,9 +85,12 @@
     typedef int T;
     boost::promise<T> p2;
     boost::future<T> f = p2.get_future();
-    //boost::thread(func, boost::move(p)).detach();
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+    boost::thread(func, boost::move(p2)).detach();
+#else
     p = boost::move(p2);
     boost::thread(func).detach();
+#endif
     try
     {
       f.get();
Modified: trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp
==============================================================================
--- trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp	Fri Jun  7 13:37:04 2013	(r84677)
+++ trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp	2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)	(r84678)
@@ -23,9 +23,12 @@
 #include <boost/thread/future.hpp>
 #include <boost/detail/lightweight_test.hpp>
 
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+void func(boost::promise<int> p)
+#else
 boost::promise<int> p;
-//void func(boost::promise<int> p)
 void func()
+#endif
 {
   const int i = 5;
   p.set_value_at_thread_exit(i);
@@ -34,18 +37,32 @@
 int main()
 {
   {
-    //boost::promise<int> p;
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+    boost::promise<int> p;
+    boost::future<int> f = p.get_future();
+    boost::thread(func, boost::move(p)).detach();
+#else
     boost::future<int> f = p.get_future();
-    //boost::thread(func, boost::move(p)).detach();
     boost::thread(func).detach();
-    BOOST_TEST(f.get() == 5);
+#endif
+    try
+    {
+      BOOST_TEST(f.get() == 5);
+    }
+    catch (...)
+    {
+      BOOST_TEST(false);
+    }
   }
   {
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
+#else
     boost::promise<int> p2;
     boost::future<int> f = p2.get_future();
     p = boost::move(p2);
     boost::thread(func).detach();
     BOOST_TEST(f.get() == 5);
+#endif
   }
   return boost::report_errors();
 }
Modified: trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp
==============================================================================
--- trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp	Fri Jun  7 13:37:04 2013	(r84677)
+++ trunk/libs/thread/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp	2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)	(r84678)
@@ -32,7 +32,8 @@
   i = 1;
 }
 
-void func2_mv(BOOST_THREAD_RV_REF(boost::promise<void>) p2)
+//void func2_mv(BOOST_THREAD_RV_REF(boost::promise<void>) p2)
+void func2_mv(boost::promise<void> p2)
 {
   p2.set_value_at_thread_exit();
   i = 2;
@@ -92,6 +93,7 @@
     boost::thread(func2, &p2).detach();
 #endif
     f.wait();
+    f.get();
     BOOST_TEST(i == 2);
   }
   catch(std::exception& ex)
Modified: trunk/libs/thread/test/threads/thread/constr/FrvalueArgs_pass.cpp
==============================================================================
--- trunk/libs/thread/test/threads/thread/constr/FrvalueArgs_pass.cpp	Fri Jun  7 13:37:04 2013	(r84677)
+++ trunk/libs/thread/test/threads/thread/constr/FrvalueArgs_pass.cpp	2013-06-07 15:03:49 EDT (Fri, 07 Jun 2013)	(r84678)
@@ -40,6 +40,51 @@
   }
 };
 
+class M
+{
+
+public:
+  long data_;
+  static int n_moves;
+
+  BOOST_THREAD_MOVABLE_ONLY(M)
+  static void reset() {
+    n_moves=0;
+  }
+  explicit M(long i) : data_(i)
+  {
+  }
+  M(BOOST_THREAD_RV_REF(M) a) : data_(BOOST_THREAD_RV(a).data_)
+  {
+    BOOST_THREAD_RV(a).data_ = -1;
+    ++n_moves;
+  }
+  M& operator=(BOOST_THREAD_RV_REF(M) a)
+  {
+    data_ = BOOST_THREAD_RV(a).data_;
+    BOOST_THREAD_RV(a).data_ = -1;
+    ++n_moves;
+    return *this;
+  }
+  ~M()
+  {
+  }
+
+  void operator()(int) const
+  { }
+  long operator()() const
+  { return data_;}
+  long operator()(long i, long j) const
+  { return data_ + i + j;}
+};
+
+int M::n_moves = 0;
+
+void fct(BOOST_THREAD_RV_REF(M) v)
+{
+  BOOST_TEST_EQ(v.data_, 1);
+}
+
 int main()
 {
 #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -47,6 +92,12 @@
     boost::thread t = boost::thread( MoveOnly(), MoveOnly() );
     t.join();
   }
+  {
+    M::reset();
+    boost::thread t = boost::thread( fct, M(1) );
+    t.join();
+    BOOST_TEST_EQ(M::n_moves, 2);
+  }
 #endif
   return boost::report_errors();
 }