Skip to content

Commit d25ee68

Browse files
committed
[libc++] Fix std::future not waiting until the thread is finished to clean up
1 parent 0123ee5 commit d25ee68

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

libcxx/include/future

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,16 @@ template <class _Rp, class _Fp>
18231823
_LIBCPP_HIDE_FROM_ABI future<_Rp> __make_async_assoc_state(_Fp&& __f) {
18241824
unique_ptr<__async_assoc_state<_Rp, _Fp>, __release_shared_count> __h(
18251825
new __async_assoc_state<_Rp, _Fp>(std::forward<_Fp>(__f)));
1826-
std::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach();
1826+
#if _LIBCPP_HAS_EXCEPTIONS
1827+
try {
1828+
#endif
1829+
std::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach();
1830+
#if _LIBCPP_HAS_EXCEPTIONS
1831+
} catch (...) {
1832+
__h->__make_ready();
1833+
throw;
1834+
}
1835+
#endif
18271836
return future<_Rp>(__h.get());
18281837
}
18291838

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// UNSUPPORTED: no-threads, no-exceptions
10+
11+
// ASan seems to try to create threadsm which obviouly doesn't work in this test.
12+
// UNSUPPORTED: asan
13+
14+
// UNSUPPORTED: c++03
15+
16+
// There is no way to limit the number of threads on windows
17+
// UNSUPPORTED: windows
18+
19+
// AIX and macOS seem to limit the number of processes, not threads via RLIMIT_NPROC
20+
// XFAIL: target={{.+}}-aix{{.*}}
21+
// XFAIL: target={{.+}}-apple-{{.*}}
22+
23+
// This test makes sure that we fail gracefully in care the thread creation fails. This is only reliably possible on
24+
// systems that allow limiting the number of threads that can be created. See https://llvm.org/PR125428 for more details
25+
26+
#include <cassert>
27+
#include <future>
28+
#include <system_error>
29+
30+
#if __has_include(<sys/resource.h>)
31+
# include <sys/resource.h>
32+
# ifdef RLIMIT_NPROC
33+
void force_thread_creation_failure() {
34+
rlimit lim = {1, 1};
35+
assert(setrlimit(RLIMIT_NPROC, &lim) == 0);
36+
}
37+
# else
38+
# error "No known way to force only one thread being available"
39+
# endif
40+
#else
41+
# error "No known way to force only one thread being available"
42+
#endif
43+
44+
int main(int, char**) {
45+
force_thread_creation_failure();
46+
47+
try {
48+
std::future<int> fut = std::async(std::launch::async, [] { return 1; });
49+
assert(false);
50+
} catch (const std::system_error&) {
51+
}
52+
53+
try {
54+
std::future<void> fut = std::async(std::launch::async, [] { return; });
55+
assert(false);
56+
} catch (const std::system_error&) {
57+
}
58+
59+
return 0;
60+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// UNSUPPORTED: no-threads
10+
// UNSUPPORTED: c++03
11+
12+
// This test uses std::atomic interfaces that are only available in C++20
13+
// UNSUPPORTED: c++11, c++14, c++17
14+
15+
// Make sure that the `future` destructor keeps the data alive until the thread finished. This test fails by triggering
16+
// TSan. It may not be observable by normal means.
17+
18+
#include <atomic>
19+
#include <future>
20+
#include <mutex>
21+
22+
std::mutex mux;
23+
24+
int main() {
25+
using namespace std::chrono_literals;
26+
std::unique_lock lock(mux);
27+
std::atomic<bool> in_async = false;
28+
auto v = std::async(std::launch::async, [&in_async, value = 1]() mutable {
29+
in_async = true;
30+
in_async.notify_all();
31+
std::scoped_lock thread_lock(mux);
32+
value = 4;
33+
(void)value;
34+
});
35+
in_async.wait(true);
36+
lock.unlock();
37+
}

0 commit comments

Comments
 (0)