• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)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 
operator delete(void * p)43 void  operator delete(void* p) TEST_NOEXCEPT
44 {
45     --outstanding_new;
46     std::free(p);
47 }
48 
49 bool f_run = false;
50 
f()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 
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()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 
main()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         std::thread t((G()));
161         t.join();
162         assert(G::n_alive == 0);
163         assert(G::op_run);
164     }
165     G::op_run = false;
166 #ifndef TEST_HAS_NO_EXCEPTIONS
167     {
168         try
169         {
170             throw_one = 0;
171             assert(G::n_alive == 0);
172             assert(!G::op_run);
173             std::thread t((G()));
174             assert(false);
175         }
176         catch (...)
177         {
178             throw_one = 0xFFFF;
179             assert(G::n_alive == 0);
180             assert(!G::op_run);
181         }
182     }
183 #endif
184 #if TEST_STD_VER >= 11
185     {
186         assert(G::n_alive == 0);
187         assert(!G::op_run);
188         std::thread t(G(), 5, 5.5);
189         t.join();
190         assert(G::n_alive == 0);
191         assert(G::op_run);
192     }
193     {
194         std::thread t = std::thread(MoveOnly(), MoveOnly());
195         t.join();
196     }
197 #endif
198 }
199