Message ID | 20140514193707.GE10556@redhat.com |
---|---|
State | New |
Headers | show |
On 14/05/14 20:37 +0100, Jonathan Wakely wrote: >Failing to rethrow a __forced_unwind exception is very bad. > >This patch ensures we rethrow them in async tasks, and makes the >shared state ready with a broken_promise so that waiting threads >don't block forever. That seems reasonable to me, does anyone have any >better ideas? > >Tested x86_64-linux, will wait for feedback before committing. Committed to trunk. >commit 8d4a49e0391269380b160bd277339f740716de0c >Author: Jonathan Wakely <jwakely@redhat.com> >Date: Tue May 13 15:35:29 2014 +0100 > > * include/std/condition_variable (condition_variable_any::_Unlock): Do > not swallow __forced_unwind. > * include/std/future (__future_base::_Task_setter): Likewise. > (__future_base::_Async_state_impl): Turn __forced_unwind into broken > promise and rethrow. > * include/std/mutex (try_lock): Likewise. > * testsuite/30_threads/async/forced_unwind.cc: New. > * testsuite/30_threads/packaged_task/forced_unwind.cc: New. > >diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable >index fc111dd..921cb83 100644 >--- a/libstdc++-v3/include/std/condition_variable >+++ b/libstdc++-v3/include/std/condition_variable >@@ -189,7 +189,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > ~_Unlock() noexcept(false) > { > if (uncaught_exception()) >- __try { _M_lock.lock(); } __catch(...) { } >+ { >+ __try >+ { _M_lock.lock(); } >+ __catch(const __cxxabiv1::__forced_unwind&) >+ { __throw_exception_again; } >+ __catch(...) >+ { } >+ } > else > _M_lock.lock(); > } >diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future >index 717ce71..8972ecf 100644 >--- a/libstdc++-v3/include/std/future >+++ b/libstdc++-v3/include/std/future >@@ -1231,6 +1231,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > { > _M_result->_M_set(_M_fn()); > } >+ __catch(const __cxxabiv1::__forced_unwind&) >+ { >+ __throw_exception_again; // will cause broken_promise >+ } > __catch(...) > { > _M_result->_M_error = current_exception(); >@@ -1250,6 +1254,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > { > _M_fn(); > } >+ __catch(const __cxxabiv1::__forced_unwind&) >+ { >+ __throw_exception_again; // will cause broken_promise >+ } > __catch(...) > { > _M_result->_M_error = current_exception(); >@@ -1510,7 +1518,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > : _M_result(new _Result<_Res>()), _M_fn(std::move(__fn)) > { > _M_thread = std::thread{ [this] { >- _M_set_result(_S_task_setter(_M_result, _M_fn)); >+ __try >+ { >+ _M_set_result(_S_task_setter(_M_result, _M_fn)); >+ } >+ __catch (const __cxxabiv1::__forced_unwind&) >+ { >+ // make the shared state ready on thread cancellation >+ if (static_cast<bool>(_M_result)) >+ this->_M_break_promise(std::move(_M_result)); >+ __throw_exception_again; >+ } > } }; > } > >diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex >index 3d70754..f6b851c 100644 >--- a/libstdc++-v3/include/std/mutex >+++ b/libstdc++-v3/include/std/mutex >@@ -44,6 +44,7 @@ > #include <bits/functexcept.h> > #include <bits/gthr.h> > #include <bits/move.h> // for std::swap >+#include <bits/cxxabi_forced.h> > > #ifdef _GLIBCXX_USE_C99_STDINT_TR1 > >@@ -631,6 +632,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > auto __locks = std::tie(__l1, __l2, __l3...); > __try > { __try_lock_impl<0>::__do_try_lock(__locks, __idx); } >+ __catch(const __cxxabiv1::__forced_unwind&) >+ { __throw_exception_again; } > __catch(...) > { } > return __idx; >diff --git a/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc b/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc >new file mode 100644 >index 0000000..7b0a492 >--- /dev/null >+++ b/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc >@@ -0,0 +1,45 @@ >+// { dg-do run { target *-*-linux* *-*-gnu* } } >+// { dg-options " -std=gnu++11 -pthread" { target *-*-linux* *-*-gnu* } } >+// { dg-require-cstdint "" } >+// { dg-require-gthreads "" } >+// { dg-require-atomic-builtins "" } >+ >+// Copyright (C) 2014 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/>. >+ >+// Test (non-standard) handling of __forced_unwind exception. >+ >+#include <future> >+#include <stdexcept> >+#include <pthread.h> >+#include <testsuite_hooks.h> >+ >+void f() { pthread_exit(nullptr); } >+ >+int main() >+{ >+ auto fut = std::async(std::launch::async, f); >+ try >+ { >+ fut.get(); >+ throw std::logic_error("Unreachable"); >+ } >+ catch (const std::future_error& e) >+ { >+ VERIFY( e.code() == std::future_errc::broken_promise ); >+ } >+} >diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc >new file mode 100644 >index 0000000..235ab17 >--- /dev/null >+++ b/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc >@@ -0,0 +1,48 @@ >+// { dg-do run { target *-*-linux* *-*-gnu* } } >+// { dg-options " -std=gnu++11 -pthread" { target *-*-linux* *-*-gnu* } } >+// { dg-require-cstdint "" } >+// { dg-require-gthreads "" } >+// { dg-require-atomic-builtins "" } >+ >+// Copyright (C) 2014 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/>. >+ >+// Test (non-standard) handling of __forced_unwind exception. >+ >+#include <future> >+#include <stdexcept> >+#include <pthread.h> >+#include <testsuite_hooks.h> >+ >+void f() { pthread_exit(nullptr); } >+ >+int main() >+{ >+ std::packaged_task<void()> p(f); >+ auto fut = p.get_future(); >+ std::thread t(std::move(p)); >+ try >+ { >+ fut.get(); >+ throw std::logic_error("Unreachable"); >+ } >+ catch (const std::future_error& e) >+ { >+ VERIFY( e.code() == std::future_errc::broken_promise ); >+ } >+ t.join(); >+}
commit 8d4a49e0391269380b160bd277339f740716de0c Author: Jonathan Wakely <jwakely@redhat.com> Date: Tue May 13 15:35:29 2014 +0100 * include/std/condition_variable (condition_variable_any::_Unlock): Do not swallow __forced_unwind. * include/std/future (__future_base::_Task_setter): Likewise. (__future_base::_Async_state_impl): Turn __forced_unwind into broken promise and rethrow. * include/std/mutex (try_lock): Likewise. * testsuite/30_threads/async/forced_unwind.cc: New. * testsuite/30_threads/packaged_task/forced_unwind.cc: New. diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index fc111dd..921cb83 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -189,7 +189,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ~_Unlock() noexcept(false) { if (uncaught_exception()) - __try { _M_lock.lock(); } __catch(...) { } + { + __try + { _M_lock.lock(); } + __catch(const __cxxabiv1::__forced_unwind&) + { __throw_exception_again; } + __catch(...) + { } + } else _M_lock.lock(); } diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index 717ce71..8972ecf 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -1231,6 +1231,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _M_result->_M_set(_M_fn()); } + __catch(const __cxxabiv1::__forced_unwind&) + { + __throw_exception_again; // will cause broken_promise + } __catch(...) { _M_result->_M_error = current_exception(); @@ -1250,6 +1254,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { _M_fn(); } + __catch(const __cxxabiv1::__forced_unwind&) + { + __throw_exception_again; // will cause broken_promise + } __catch(...) { _M_result->_M_error = current_exception(); @@ -1510,7 +1518,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_result(new _Result<_Res>()), _M_fn(std::move(__fn)) { _M_thread = std::thread{ [this] { - _M_set_result(_S_task_setter(_M_result, _M_fn)); + __try + { + _M_set_result(_S_task_setter(_M_result, _M_fn)); + } + __catch (const __cxxabiv1::__forced_unwind&) + { + // make the shared state ready on thread cancellation + if (static_cast<bool>(_M_result)) + this->_M_break_promise(std::move(_M_result)); + __throw_exception_again; + } } }; } diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index 3d70754..f6b851c 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -44,6 +44,7 @@ #include <bits/functexcept.h> #include <bits/gthr.h> #include <bits/move.h> // for std::swap +#include <bits/cxxabi_forced.h> #ifdef _GLIBCXX_USE_C99_STDINT_TR1 @@ -631,6 +632,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION auto __locks = std::tie(__l1, __l2, __l3...); __try { __try_lock_impl<0>::__do_try_lock(__locks, __idx); } + __catch(const __cxxabiv1::__forced_unwind&) + { __throw_exception_again; } __catch(...) { } return __idx; diff --git a/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc b/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc new file mode 100644 index 0000000..7b0a492 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/async/forced_unwind.cc @@ -0,0 +1,45 @@ +// { dg-do run { target *-*-linux* *-*-gnu* } } +// { dg-options " -std=gnu++11 -pthread" { target *-*-linux* *-*-gnu* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } +// { dg-require-atomic-builtins "" } + +// Copyright (C) 2014 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/>. + +// Test (non-standard) handling of __forced_unwind exception. + +#include <future> +#include <stdexcept> +#include <pthread.h> +#include <testsuite_hooks.h> + +void f() { pthread_exit(nullptr); } + +int main() +{ + auto fut = std::async(std::launch::async, f); + try + { + fut.get(); + throw std::logic_error("Unreachable"); + } + catch (const std::future_error& e) + { + VERIFY( e.code() == std::future_errc::broken_promise ); + } +} diff --git a/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc b/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc new file mode 100644 index 0000000..235ab17 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/packaged_task/forced_unwind.cc @@ -0,0 +1,48 @@ +// { dg-do run { target *-*-linux* *-*-gnu* } } +// { dg-options " -std=gnu++11 -pthread" { target *-*-linux* *-*-gnu* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } +// { dg-require-atomic-builtins "" } + +// Copyright (C) 2014 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/>. + +// Test (non-standard) handling of __forced_unwind exception. + +#include <future> +#include <stdexcept> +#include <pthread.h> +#include <testsuite_hooks.h> + +void f() { pthread_exit(nullptr); } + +int main() +{ + std::packaged_task<void()> p(f); + auto fut = p.get_future(); + std::thread t(std::move(p)); + try + { + fut.get(); + throw std::logic_error("Unreachable"); + } + catch (const std::future_error& e) + { + VERIFY( e.code() == std::future_errc::broken_promise ); + } + t.join(); +}