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