[RISCV] Fix mgather -> riscv.masked.strided.load combine not extending indices (...
[llvm-project.git] / libcxx / test / std / thread / thread.threads / thread.thread.class / thread.thread.constr / F.pass.cpp
blob1c520652ba2297dec9e96e983b46223d4cade3a9
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 //===----------------------------------------------------------------------===//
9 // <thread>
11 // class thread
13 // template <class F, class ...Args> thread(F&& f, Args&&... args);
15 // UNSUPPORTED: no-threads
16 // UNSUPPORTED: sanitizer-new-delete
18 #include <thread>
19 #include <new>
20 #include <atomic>
21 #include <cstdlib>
22 #include <cassert>
23 #include <vector>
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;
34 do {
35 if (expected == 0) TEST_THROW(std::bad_alloc());
36 } while (!throw_one.compare_exchange_weak(expected, expected - 1));
37 ++outstanding_new;
38 void* ret = std::malloc(s);
39 if (!ret) {
40 std::abort(); // placate MSVC's unchecked malloc warning (assert() won't silence it)
42 return ret;
45 void operator delete(void* p) TEST_NOEXCEPT
47 if (!p) return;
48 --outstanding_new;
49 std::free(p);
52 bool f_run = false;
54 struct F {
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; }
59 F f;
61 class G
63 int alive_;
64 public:
65 static int n_alive;
66 static bool op_run;
68 G() : alive_(1) {++n_alive;}
69 G(const G& g) : alive_(g.alive_) {++n_alive;}
70 ~G() {alive_ = 0; --n_alive;}
72 void operator()()
74 assert(alive_ == 1);
75 assert(n_alive >= 1);
76 op_run = true;
79 void operator()(int i, double j)
81 assert(alive_ == 1);
82 assert(n_alive >= 1);
83 assert(i == 5);
84 assert(j == 5.5);
85 op_run = true;
89 int G::n_alive = 0;
90 bool G::op_run = false;
92 #if TEST_STD_VER >= 11
94 class MoveOnly
96 MoveOnly(const MoveOnly&);
97 public:
98 MoveOnly() {}
99 MoveOnly(MoveOnly&&) {}
101 void operator()(MoveOnly&&)
106 #endif
108 // Test throwing std::bad_alloc
109 //-----------------------------
110 // Concerns:
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
115 // memory.
116 // Plan:
117 // 1 Create a thread and count the number of allocations, 'numAllocs', it
118 // performs.
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.
126 int numAllocs;
128 void test_throwing_new_during_thread_creation() {
129 #ifndef TEST_HAS_NO_EXCEPTIONS
130 throw_one = 0xFFF;
132 std::thread t(f);
133 t.join();
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) {
138 throw_one = i;
139 f_run = false;
140 unsigned old_outstanding = outstanding_new;
141 try {
142 std::thread t(f);
143 assert(i == numAllocs); // Only final iteration will not throw.
144 t.join();
145 assert(f_run);
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)
152 f_run = false;
153 throw_one = 0xFFF;
154 #endif
157 int main(int, char**)
159 test_throwing_new_during_thread_creation();
161 std::thread t(f);
162 t.join();
163 assert(f_run == true);
167 assert(G::n_alive == 0);
168 assert(!G::op_run);
170 G g;
171 std::thread t(g);
172 t.join();
174 assert(G::n_alive == 0);
175 assert(G::op_run);
177 G::op_run = false;
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.
182 if (numAllocs > 0) {
185 throw_one = 0;
186 assert(G::n_alive == 0);
187 assert(!G::op_run);
188 std::thread t((G()));
189 assert(false);
191 catch (std::bad_alloc const&)
193 throw_one = 0xFFFF;
194 assert(G::n_alive == 0);
195 assert(!G::op_run);
198 #endif
199 #if TEST_STD_VER >= 11
201 assert(G::n_alive == 0);
202 assert(!G::op_run);
204 G g;
205 std::thread t(g, 5, 5.5);
206 t.join();
208 assert(G::n_alive == 0);
209 assert(G::op_run);
212 std::thread t = std::thread(MoveOnly(), MoveOnly());
213 t.join();
215 #endif
217 return 0;