1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
13 // template <class F, class ...Args> thread(F&& f, Args&&... args);
15 // UNSUPPORTED: no-threads
16 // UNSUPPORTED: sanitizer-new-delete
25 #include "test_macros.h"
27 std::atomic
<unsigned> throw_one(0xFFFF);
28 std::atomic
<unsigned> outstanding_new(0);
31 void* operator new(std::size_t s
) TEST_THROW_SPEC(std::bad_alloc
)
33 unsigned expected
= throw_one
;
35 if (expected
== 0) TEST_THROW(std::bad_alloc());
36 } while (!throw_one
.compare_exchange_weak(expected
, expected
- 1));
38 void* ret
= std::malloc(s
);
40 std::abort(); // placate MSVC's unchecked malloc warning (assert() won't silence it)
45 void operator delete(void* p
) TEST_NOEXCEPT
55 std::vector
<int> v_
; // so f's copy-ctor calls operator new
56 explicit F() : v_(10) {}
57 void operator()() const { f_run
= true; }
68 G() : alive_(1) {++n_alive
;}
69 G(const G
& g
) : alive_(g
.alive_
) {++n_alive
;}
70 ~G() {alive_
= 0; --n_alive
;}
79 void operator()(int i
, double j
)
90 bool G::op_run
= false;
92 #if TEST_STD_VER >= 11
96 MoveOnly(const MoveOnly
&);
99 MoveOnly(MoveOnly
&&) {}
101 void operator()(MoveOnly
&&)
108 // Test throwing std::bad_alloc
109 //-----------------------------
111 // A Each allocation performed during thread construction should be performed
112 // in the parent thread so that std::terminate is not called if
113 // std::bad_alloc is thrown by new.
114 // B std::thread's constructor should properly handle exceptions and not leak
117 // 1 Create a thread and count the number of allocations, 'numAllocs', it
119 // 2 For each allocation performed run a test where that allocation throws.
120 // 2.1 check that the exception can be caught in the parent thread.
121 // 2.2 Check that the functor has not been called.
122 // 2.3 Check that no memory allocated by the creation of the thread is leaked.
123 // 3 Finally check that a thread runs successfully if we throw after
124 // 'numAllocs + 1' allocations.
128 void test_throwing_new_during_thread_creation() {
129 #ifndef TEST_HAS_NO_EXCEPTIONS
135 numAllocs
= 0xFFF - throw_one
;
136 // i <= numAllocs means the last iteration is expected not to throw.
137 for (int i
=0; i
<= numAllocs
; ++i
) {
140 unsigned old_outstanding
= outstanding_new
;
143 assert(i
== numAllocs
); // Only final iteration will not throw.
146 } catch (std::bad_alloc
const&) {
147 assert(i
< numAllocs
);
148 assert(!f_run
); // (2.2)
150 ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(old_outstanding
== outstanding_new
); // (2.3)
157 int main(int, char**)
159 test_throwing_new_during_thread_creation();
163 assert(f_run
== true);
167 assert(G::n_alive
== 0);
174 assert(G::n_alive
== 0);
178 #ifndef TEST_HAS_NO_EXCEPTIONS
179 // The test below expects `std::thread` to call `new`, which may not be the
180 // case for all implementations.
181 LIBCPP_ASSERT(numAllocs
> 0); // libc++ should call new.
186 assert(G::n_alive
== 0);
188 std::thread
t((G()));
191 catch (std::bad_alloc
const&)
194 assert(G::n_alive
== 0);
199 #if TEST_STD_VER >= 11
201 assert(G::n_alive
== 0);
205 std::thread
t(g
, 5, 5.5);
208 assert(G::n_alive
== 0);
212 std::thread t
= std::thread(MoveOnly(), MoveOnly());