Return deferred future if thread cannot be run
authorJonathan Wakely <jwakely@redhat.com>
Sat, 24 Oct 2015 21:36:50 +0000 (22:36 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Sat, 24 Oct 2015 21:36:50 +0000 (22:36 +0100)
* include/std/future (async): Use deferred function on exception.
* testsuite/30_threads/async/except.cc: New.

From-SVN: r229289

libstdc++-v3/ChangeLog
libstdc++-v3/include/std/future
libstdc++-v3/testsuite/30_threads/async/except.cc [new file with mode: 0644]

index 9444dd308d2210b7a46e1d9c1a89da79dca9c0f8..4f0a4bd53955c01d7d086a1c9bdc20a3aea785eb 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-24  Jonathan Wakely  <jwakely@redhat.com>
+
+       * include/std/future (async): Use deferred function on exception.
+       * testsuite/30_threads/async/except.cc: New.
+
 2015-10-21  Jonathan Wakely  <jwakely@redhat.com>
 
        * include/std/type_traits (__cpp_lib_bool_constant): Define.
index 216a921796af4e2f99ffc4a43d6ba58f5eff95d0..93889cd49d222244cc1fb5e6ba8de47148d160d2 100644 (file)
@@ -1711,10 +1711,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       std::shared_ptr<__future_base::_State_base> __state;
       if ((__policy & launch::async) == launch::async)
        {
-         __state = __future_base::_S_make_async_state(std::__bind_simple(
-              std::forward<_Fn>(__fn), std::forward<_Args>(__args)...));
+         __try
+           {
+             __state = __future_base::_S_make_async_state(std::__bind_simple(
+                 std::forward<_Fn>(__fn), std::forward<_Args>(__args)...));
+           }
+#if __cpp_exceptions
+         catch(const system_error& __e)
+           {
+             if (__e.code() != errc::resource_unavailable_try_again
+                 || (__policy & launch::deferred) != launch::deferred)
+               throw;
+           }
+#endif
        }
-      else
+      if (!__state)
        {
          __state = __future_base::_S_make_deferred_state(std::__bind_simple(
               std::forward<_Fn>(__fn), std::forward<_Args>(__args)...));
diff --git a/libstdc++-v3/testsuite/30_threads/async/except.cc b/libstdc++-v3/testsuite/30_threads/async/except.cc
new file mode 100644 (file)
index 0000000..fda08dc
--- /dev/null
@@ -0,0 +1,70 @@
+// { dg-do run { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-rtems* *-*-darwin* powerpc-ibm-aix* } }
+// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-dragonfly* *-*-netbsd* *-*-linux* *-*-gnu* powerpc-ibm-aix* } }
+// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } }
+// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-rtems* *-*-darwin* } }
+// { dg-require-cstdint "" }
+// { dg-require-gthreads "" }
+// { dg-require-atomic-builtins "" }
+
+// Copyright (C) 2010-2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+
+#include <future>
+#include <testsuite_hooks.h>
+
+struct Chucky
+{
+  Chucky() : copied(false) { }
+
+  Chucky(const Chucky& other) : copied(true)
+  {
+    if (other.copied)
+      return;
+    other.copied = true;
+    using namespace std;
+    // Throw on first DECAY_COPY to simulate inability to start a new thread.
+    throw system_error(make_error_code(errc::resource_unavailable_try_again));
+  }
+
+  void operator()() const { }
+
+  mutable bool copied;
+};
+
+void test01()
+{
+  bool test __attribute__((unused)) = true;
+
+  using namespace std;
+
+  future<void> f = async(Chucky{});
+  VERIFY( f.wait_for(chrono::seconds(100)) == future_status::deferred );
+
+  bool caught = false;
+  try {
+    f = async(launch::async, Chucky{});
+  } catch (const system_error&) {
+    caught = true;
+  }
+  VERIFY( caught );
+}
+
+int main()
+{
+  test01();
+}