Home | History | Annotate | Download | only in thread.thread.constr
      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