1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // UNSUPPORTED: libcpp-has-no-threads 11 12 // <thread> 13 14 // class thread 15 16 // template <class F, class ...Args> thread(F&& f, Args&&... args); 17 18 // UNSUPPORTED: sanitizer-new-delete 19 20 #include <thread> 21 #include <new> 22 #include <atomic> 23 #include <cstdlib> 24 #include <cassert> 25 26 #include "test_macros.h" 27 28 std::atomic<unsigned> throw_one(0xFFFF); 29 std::atomic<unsigned> outstanding_new(0); 30 31 operator new(std::size_t s)32void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) 33 { 34 if (throw_one == 0) 35 TEST_THROW(std::bad_alloc()); 36 --throw_one; 37 ++outstanding_new; 38 void* ret = std::malloc(s); 39 if (!ret) std::abort(); // placate MSVC's unchecked malloc warning 40 return ret; 41 } 42 operator delete(void * p)43void operator delete(void* p) TEST_NOEXCEPT 44 { 45 --outstanding_new; 46 std::free(p); 47 } 48 49 bool f_run = false; 50 f()51void f() 52 { 53 f_run = true; 54 } 55 56 class G 57 { 58 int alive_; 59 public: 60 static int n_alive; 61 static bool op_run; 62 G()63 G() : alive_(1) {++n_alive;} G(const G & g)64 G(const G& g) : alive_(g.alive_) {++n_alive;} ~G()65 ~G() {alive_ = 0; --n_alive;} 66 operator ()()67 void operator()() 68 { 69 assert(alive_ == 1); 70 assert(n_alive >= 1); 71 op_run = true; 72 } 73 operator ()(int i,double j)74 void operator()(int i, double j) 75 { 76 assert(alive_ == 1); 77 assert(n_alive >= 1); 78 assert(i == 5); 79 assert(j == 5.5); 80 op_run = true; 81 } 82 }; 83 84 int G::n_alive = 0; 85 bool G::op_run = false; 86 87 #if TEST_STD_VER >= 11 88 89 class MoveOnly 90 { 91 MoveOnly(const MoveOnly&); 92 public: MoveOnly()93 MoveOnly() {} MoveOnly(MoveOnly &&)94 MoveOnly(MoveOnly&&) {} 95 operator ()(MoveOnly &&)96 void operator()(MoveOnly&&) 97 { 98 } 99 }; 100 101 #endif 102 103 // Test throwing std::bad_alloc 104 //----------------------------- 105 // Concerns: 106 // A Each allocation performed during thread construction should be performed 107 // in the parent thread so that std::terminate is not called if 108 // std::bad_alloc is thrown by new. 109 // B std::thread's constructor should properly handle exceptions and not leak 110 // memory. 111 // Plan: 112 // 1 Create a thread and count the number of allocations, 'N', it performs. 113 // 2 For each allocation performed run a test where that allocation throws. 114 // 2.1 check that the exception can be caught in the parent thread. 115 // 2.2 Check that the functor has not been called. 116 // 2.3 Check that no memory allocated by the creation of the thread is leaked. 117 // 3 Finally check that a thread runs successfully if we throw after 'N+1' 118 // allocations. test_throwing_new_during_thread_creation()119void test_throwing_new_during_thread_creation() { 120 #ifndef TEST_HAS_NO_EXCEPTIONS 121 throw_one = 0xFFF; 122 { 123 std::thread t(f); 124 t.join(); 125 } 126 const int numAllocs = 0xFFF - throw_one; 127 // i <= numAllocs means the last iteration is expected not to throw. 128 for (int i=0; i <= numAllocs; ++i) { 129 throw_one = i; 130 f_run = false; 131 unsigned old_outstanding = outstanding_new; 132 try { 133 std::thread t(f); 134 assert(i == numAllocs); // Only final iteration will not throw. 135 t.join(); 136 assert(f_run); 137 } catch (std::bad_alloc const&) { 138 assert(i < numAllocs); 139 assert(!f_run); // (2.2) 140 } 141 assert(old_outstanding == outstanding_new); // (2.3) 142 } 143 f_run = false; 144 throw_one = 0xFFF; 145 #endif 146 } 147 main()148int main() 149 { 150 test_throwing_new_during_thread_creation(); 151 { 152 std::thread t(f); 153 t.join(); 154 assert(f_run == true); 155 } 156 157 { 158 assert(G::n_alive == 0); 159 assert(!G::op_run); 160 { 161 G g; 162 std::thread t(g); 163 t.join(); 164 } 165 assert(G::n_alive == 0); 166 assert(G::op_run); 167 } 168 G::op_run = false; 169 #ifndef TEST_HAS_NO_EXCEPTIONS 170 { 171 try 172 { 173 throw_one = 0; 174 assert(G::n_alive == 0); 175 assert(!G::op_run); 176 std::thread t((G())); 177 assert(false); 178 } 179 catch (...) 180 { 181 throw_one = 0xFFFF; 182 assert(G::n_alive == 0); 183 assert(!G::op_run); 184 } 185 } 186 #endif 187 #if TEST_STD_VER >= 11 188 { 189 assert(G::n_alive == 0); 190 assert(!G::op_run); 191 { 192 G g; 193 std::thread t(g, 5, 5.5); 194 t.join(); 195 } 196 assert(G::n_alive == 0); 197 assert(G::op_run); 198 } 199 { 200 std::thread t = std::thread(MoveOnly(), MoveOnly()); 201 t.join(); 202 } 203 #endif 204 } 205