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 // 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 
     32 void* 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 
     43 void  operator delete(void* p) TEST_NOEXCEPT
     44 {
     45     --outstanding_new;
     46     std::free(p);
     47 }
     48 
     49 bool f_run = false;
     50 
     51 void 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 
     63     G() : alive_(1) {++n_alive;}
     64     G(const G& g) : alive_(g.alive_) {++n_alive;}
     65     ~G() {alive_ = 0; --n_alive;}
     66 
     67     void operator()()
     68     {
     69         assert(alive_ == 1);
     70         assert(n_alive >= 1);
     71         op_run = true;
     72     }
     73 
     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:
     93     MoveOnly() {}
     94     MoveOnly(MoveOnly&&) {}
     95 
     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.
    119 void 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 
    148 int 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