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 return std::malloc(s); 40 } 41 42 void operator delete(void* p) throw() 43 { 44 --outstanding_new; 45 std::free(p); 46 } 47 48 bool f_run = false; 49 50 void f() 51 { 52 f_run = true; 53 } 54 55 class G 56 { 57 int alive_; 58 public: 59 static int n_alive; 60 static bool op_run; 61 62 G() : alive_(1) {++n_alive;} 63 G(const G& g) : alive_(g.alive_) {++n_alive;} 64 ~G() {alive_ = 0; --n_alive;} 65 66 void operator()() 67 { 68 assert(alive_ == 1); 69 assert(n_alive >= 1); 70 op_run = true; 71 } 72 73 void operator()(int i, double j) 74 { 75 assert(alive_ == 1); 76 assert(n_alive >= 1); 77 assert(i == 5); 78 assert(j == 5.5); 79 op_run = true; 80 } 81 }; 82 83 int G::n_alive = 0; 84 bool G::op_run = false; 85 86 #if TEST_STD_VER >= 11 87 88 class MoveOnly 89 { 90 MoveOnly(const MoveOnly&); 91 public: 92 MoveOnly() {} 93 MoveOnly(MoveOnly&&) {} 94 95 void operator()(MoveOnly&&) 96 { 97 } 98 }; 99 100 #endif 101 102 // Test throwing std::bad_alloc 103 //----------------------------- 104 // Concerns: 105 // A Each allocation performed during thread construction should be performed 106 // in the parent thread so that std::terminate is not called if 107 // std::bad_alloc is thrown by new. 108 // B std::threads constructor should properly handle exceptions and not leak 109 // memory. 110 // Plan: 111 // 1 Create a thread and count the number of allocations, 'N', it performs. 112 // 2 For each allocation performed run a test where that allocation throws. 113 // 2.1 check that the exception can be caught in the parent thread. 114 // 2.2 Check that the functor has not been called. 115 // 2.3 Check that no memory allocated by the creation of the thread is leaked. 116 // 3 Finally check that a thread runs successfully if we throw after 'N+1' 117 // allocations. 118 void test_throwing_new_during_thread_creation() { 119 throw_one = 0xFFF; 120 { 121 std::thread t(f); 122 t.join(); 123 } 124 const int numAllocs = 0xFFF - throw_one; 125 // i <= numAllocs means the last iteration is expected not to throw. 126 for (int i=0; i <= numAllocs; ++i) { 127 throw_one = i; 128 f_run = false; 129 unsigned old_outstanding = outstanding_new; 130 try { 131 std::thread t(f); 132 assert(i == numAllocs); // Only final iteration will not throw. 133 t.join(); 134 assert(f_run); 135 } catch (std::bad_alloc const&) { 136 assert(i < numAllocs); 137 assert(!f_run); // (2.2) 138 } 139 assert(old_outstanding == outstanding_new); // (2.3) 140 } 141 f_run = false; 142 throw_one = 0xFFF; 143 } 144 145 int main() 146 { 147 test_throwing_new_during_thread_creation(); 148 { 149 std::thread t(f); 150 t.join(); 151 assert(f_run == true); 152 } 153 154 { 155 assert(G::n_alive == 0); 156 assert(!G::op_run); 157 std::thread t((G())); 158 t.join(); 159 assert(G::n_alive == 0); 160 assert(G::op_run); 161 } 162 G::op_run = false; 163 { 164 try 165 { 166 throw_one = 0; 167 assert(G::n_alive == 0); 168 assert(!G::op_run); 169 std::thread t((G())); 170 assert(false); 171 } 172 catch (...) 173 { 174 throw_one = 0xFFFF; 175 assert(G::n_alive == 0); 176 assert(!G::op_run); 177 } 178 } 179 #if TEST_STD_VER >= 11 180 { 181 assert(G::n_alive == 0); 182 assert(!G::op_run); 183 std::thread t(G(), 5, 5.5); 184 t.join(); 185 assert(G::n_alive == 0); 186 assert(G::op_run); 187 } 188 { 189 std::thread t = std::thread(MoveOnly(), MoveOnly()); 190 t.join(); 191 } 192 #endif 193 } 194