summaryrefslogtreecommitdiffstats
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-17 13:01:11 +0000
committerredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-17 13:01:11 +0000
commit83760b1a11d36a0bbb64553fda530113db2c78f7 (patch)
treeb91e204df2c1fd0cd59ee823e9bfa8c7ee5e88e8 /libstdc++-v3
parent577d6f503c544c18d80d883760ff9a84eb922f9d (diff)
downloadppe42-gcc-83760b1a11d36a0bbb64553fda530113db2c78f7.tar.gz
ppe42-gcc-83760b1a11d36a0bbb64553fda530113db2c78f7.zip
PR libstdc++/60966
* include/std/future (__future_base::_State_baseV2::_M_set_result): Signal condition variable after call_once returns. (__future_base::_State_baseV2::_M_do_set): Do not signal here. (promise::set_value, promise::set_exception): Increment the reference count on the shared state until the function returns. * testsuite/30_threads/promise/60966.cc: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_9-branch@210557 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog10
-rw-r--r--libstdc++-v3/include/std/future29
-rw-r--r--libstdc++-v3/testsuite/30_threads/promise/60966.cc67
3 files changed, 96 insertions, 10 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index b78daca58ca..3ade6310e4e 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,13 @@
+2014-05-16 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/60966
+ * include/std/future (__future_base::_State_baseV2::_M_set_result):
+ Signal condition variable after call_once returns.
+ (__future_base::_State_baseV2::_M_do_set): Do not signal here.
+ (promise::set_value, promise::set_exception): Increment the reference
+ count on the shared state until the function returns.
+ * testsuite/30_threads/promise/60966.cc: New.
+
2014-05-08 Joshua Gay <jgay@gnu.org>
PR libstdc++/61117
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index 717ce7105df..998e90a9856 100644
--- a/libstdc++-v3/include/std/future
+++ b/libstdc++-v3/include/std/future
@@ -365,12 +365,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
_M_set_result(function<_Ptr_type()> __res, bool __ignore_failure = false)
{
- bool __set = __ignore_failure;
+ bool __set = false;
// all calls to this function are serialized,
// side-effects of invoking __res only happen once
call_once(_M_once, &_State_baseV2::_M_do_set, this, ref(__res),
ref(__set));
- if (!__set)
+ if (__set)
+ _M_cond.notify_all();
+ else if (!__ignore_failure)
__throw_future_error(int(future_errc::promise_already_satisfied));
}
@@ -485,7 +487,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
lock_guard<mutex> __lock(_M_mutex);
_M_result.swap(__res);
}
- _M_cond.notify_all();
__set = true;
}
@@ -495,6 +496,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual void _M_complete_async() { }
// Return true if state contains a deferred function.
+ // Caller must own _M_mutex.
virtual bool _M_has_deferred() const { return false; }
};
@@ -1007,22 +1009,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
set_value(const _Res& __r)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(this, __r);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
void
set_value(_Res&& __r)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(this, std::move(__r));
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
void
set_exception(exception_ptr __p)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(__p, this);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
};
@@ -1105,15 +1110,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
set_value(_Res& __r)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(this, __r);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
void
set_exception(exception_ptr __p)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(__p, this);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
};
@@ -1190,8 +1197,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void
set_exception(exception_ptr __p)
{
+ auto __future = _M_future;
auto __setter = _State::__setter(__p, this);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
};
@@ -1217,8 +1225,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
promise<void>::set_value()
{
+ auto __future = _M_future;
auto __setter = _State::__setter(this);
- _M_future->_M_set_result(std::move(__setter));
+ __future->_M_set_result(std::move(__setter));
}
diff --git a/libstdc++-v3/testsuite/30_threads/promise/60966.cc b/libstdc++-v3/testsuite/30_threads/promise/60966.cc
new file mode 100644
index 00000000000..269268b989b
--- /dev/null
+++ b/libstdc++-v3/testsuite/30_threads/promise/60966.cc
@@ -0,0 +1,67 @@
+// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-gnu* *-*-solaris* *-*-cygwin *-*-darwin* powerpc-ibm-aix* } }
+// { dg-options " -std=gnu++11 -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-gnu* powerpc-ibm-aix* } }
+// { dg-options " -std=gnu++11 -pthreads" { target *-*-solaris* } }
+// { dg-options " -std=gnu++11 " { target *-*-cygwin *-*-darwin* } }
+// { 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/>.
+
+// libstdc++/60966
+// This test hangs if std::promise::~promise() destroys the
+// shared state before std::promise::set_value() finishes using it.
+
+#include <future>
+#include <thread>
+#include <vector>
+
+const int THREADS = 10;
+
+void run_task(std::promise<void>* pr)
+{
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ pr->set_value();
+}
+
+int main()
+{
+ std::vector<std::promise<void>*> tasks(THREADS);
+ std::vector<std::thread> threads(THREADS);
+ std::vector<std::future<void>> futures(THREADS);
+
+ for (int i = 0; i < THREADS; ++i)
+ {
+ std::promise<void>* task = new std::promise<void>;
+ tasks[i] = task;
+ futures[i] = task->get_future();
+ threads[i] = std::thread(run_task, task);
+ }
+
+ for (int i = 0; i < THREADS; ++i)
+ {
+ // the temporary future releases the state as soon as wait() returns
+ std::future<void>(std::move(futures[i])).wait();
+ // state is ready, should now be safe to delete promise, so it
+ // releases the shared state too
+ delete tasks[i];
+ }
+
+ for (auto& t : threads)
+ t.join();
+}
OpenPOWER on IntegriCloud