123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- //===----------------------------------------------------------------------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is dual licensed under the MIT and the University of Illinois Open
- // Source Licenses. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // UNSUPPORTED: libcpp-has-no-threads
- // <thread>
- // class thread
- // template <class F, class ...Args> thread(F&& f, Args&&... args);
- // UNSUPPORTED: sanitizer-new-delete
- #include <thread>
- #include <new>
- #include <atomic>
- #include <cstdlib>
- #include <cassert>
- #include "test_macros.h"
- std::atomic<unsigned> throw_one(0xFFFF);
- std::atomic<unsigned> outstanding_new(0);
- void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
- {
- if (throw_one == 0)
- TEST_THROW(std::bad_alloc());
- --throw_one;
- ++outstanding_new;
- void* ret = std::malloc(s);
- if (!ret) std::abort(); // placate MSVC's unchecked malloc warning
- return ret;
- }
- void operator delete(void* p) TEST_NOEXCEPT
- {
- --outstanding_new;
- std::free(p);
- }
- bool f_run = false;
- void f()
- {
- f_run = true;
- }
- class G
- {
- int alive_;
- public:
- static int n_alive;
- static bool op_run;
- G() : alive_(1) {++n_alive;}
- G(const G& g) : alive_(g.alive_) {++n_alive;}
- ~G() {alive_ = 0; --n_alive;}
- void operator()()
- {
- assert(alive_ == 1);
- assert(n_alive >= 1);
- op_run = true;
- }
- void operator()(int i, double j)
- {
- assert(alive_ == 1);
- assert(n_alive >= 1);
- assert(i == 5);
- assert(j == 5.5);
- op_run = true;
- }
- };
- int G::n_alive = 0;
- bool G::op_run = false;
- #if TEST_STD_VER >= 11
- class MoveOnly
- {
- MoveOnly(const MoveOnly&);
- public:
- MoveOnly() {}
- MoveOnly(MoveOnly&&) {}
- void operator()(MoveOnly&&)
- {
- }
- };
- #endif
- // Test throwing std::bad_alloc
- //-----------------------------
- // Concerns:
- // A Each allocation performed during thread construction should be performed
- // in the parent thread so that std::terminate is not called if
- // std::bad_alloc is thrown by new.
- // B std::threads constructor should properly handle exceptions and not leak
- // memory.
- // Plan:
- // 1 Create a thread and count the number of allocations, 'N', it performs.
- // 2 For each allocation performed run a test where that allocation throws.
- // 2.1 check that the exception can be caught in the parent thread.
- // 2.2 Check that the functor has not been called.
- // 2.3 Check that no memory allocated by the creation of the thread is leaked.
- // 3 Finally check that a thread runs successfully if we throw after 'N+1'
- // allocations.
- void test_throwing_new_during_thread_creation() {
- #ifndef TEST_HAS_NO_EXCEPTIONS
- throw_one = 0xFFF;
- {
- std::thread t(f);
- t.join();
- }
- const int numAllocs = 0xFFF - throw_one;
- // i <= numAllocs means the last iteration is expected not to throw.
- for (int i=0; i <= numAllocs; ++i) {
- throw_one = i;
- f_run = false;
- unsigned old_outstanding = outstanding_new;
- try {
- std::thread t(f);
- assert(i == numAllocs); // Only final iteration will not throw.
- t.join();
- assert(f_run);
- } catch (std::bad_alloc const&) {
- assert(i < numAllocs);
- assert(!f_run); // (2.2)
- }
- assert(old_outstanding == outstanding_new); // (2.3)
- }
- f_run = false;
- throw_one = 0xFFF;
- #endif
- }
- int main()
- {
- test_throwing_new_during_thread_creation();
- {
- std::thread t(f);
- t.join();
- assert(f_run == true);
- }
- {
- assert(G::n_alive == 0);
- assert(!G::op_run);
- std::thread t((G()));
- t.join();
- assert(G::n_alive == 0);
- assert(G::op_run);
- }
- G::op_run = false;
- #ifndef TEST_HAS_NO_EXCEPTIONS
- {
- try
- {
- throw_one = 0;
- assert(G::n_alive == 0);
- assert(!G::op_run);
- std::thread t((G()));
- assert(false);
- }
- catch (...)
- {
- throw_one = 0xFFFF;
- assert(G::n_alive == 0);
- assert(!G::op_run);
- }
- }
- #endif
- #if TEST_STD_VER >= 11
- {
- assert(G::n_alive == 0);
- assert(!G::op_run);
- std::thread t(G(), 5, 5.5);
- t.join();
- assert(G::n_alive == 0);
- assert(G::op_run);
- }
- {
- std::thread t = std::thread(MoveOnly(), MoveOnly());
- t.join();
- }
- #endif
- }
|