diff options
Diffstat (limited to 'test/std/thread/thread.threads/thread.thread.class')
6 files changed, 95 insertions, 98 deletions
diff --git a/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp b/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp index 3de15af8929b..5dd6a40a0eb7 100644 --- a/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp +++ b/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp @@ -20,23 +20,30 @@ #include <thread> #include <new> +#include <atomic> #include <cstdlib> #include <cassert> #include "test_macros.h" -unsigned throw_one = 0xFFFF; +std::atomic<unsigned> throw_one(0xFFFF); +std::atomic<unsigned> outstanding_new(0); + void* operator new(std::size_t s) throw(std::bad_alloc) { if (throw_one == 0) throw std::bad_alloc(); --throw_one; - return std::malloc(s); + ++outstanding_new; + void* ret = std::malloc(s); + if (!ret) std::abort(); // placate MSVC's unchecked malloc warning + return ret; } void operator delete(void* p) throw() { + --outstanding_new; std::free(p); } @@ -94,27 +101,58 @@ public: #endif -int main() -{ +// 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() { + throw_one = 0xFFF; { std::thread t(f); t.join(); - assert(f_run == true); } - f_run = false; - { - try - { - throw_one = 0; + 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(false); - } - catch (...) - { - throw_one = 0xFFFF; - assert(!f_run); + 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; +} + +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); diff --git a/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/constr.fail.cpp b/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/constr.fail.cpp index a331add96263..54fc0b80280c 100644 --- a/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/constr.fail.cpp +++ b/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/constr.fail.cpp @@ -12,7 +12,7 @@ // class thread // template <class _Fp, class ..._Args, // explicit thread(_Fp&& __f, _Args&&... __args); -// This constructor shall not participate in overload resolution +// This constructor shall not participate in overload resolution // if decay<F>::type is the same type as std::thread. diff --git a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/detach.pass.cpp b/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/detach.pass.cpp index 726395d99044..3dd7c6a6014c 100644 --- a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/detach.pass.cpp +++ b/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/detach.pass.cpp @@ -17,8 +17,11 @@ #include <thread> #include <atomic> +#include <system_error> #include <cassert> +#include "test_macros.h" + std::atomic_bool done(false); class G @@ -57,6 +60,8 @@ public: int G::n_alive = 0; bool G::op_run = false; +void foo() {} + int main() { { @@ -70,4 +75,16 @@ int main() assert(G::n_alive == 1); } assert(G::n_alive == 0); +#ifndef TEST_HAS_NO_EXCEPTIONS + { + std::thread t0(foo); + assert(t0.joinable()); + t0.detach(); + assert(!t0.joinable()); + try { + t0.detach(); + } catch (std::system_error const&) { + } + } +#endif } diff --git a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/join.pass.cpp b/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/join.pass.cpp index 0512e49dcb33..f0c3ef74c9ab 100644 --- a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/join.pass.cpp +++ b/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/join.pass.cpp @@ -19,6 +19,9 @@ #include <new> #include <cstdlib> #include <cassert> +#include <system_error> + +#include "test_macros.h" class G { @@ -42,6 +45,8 @@ public: int G::n_alive = 0; bool G::op_run = false; +void foo() {} + int main() { { @@ -50,5 +55,23 @@ int main() assert(t0.joinable()); t0.join(); assert(!t0.joinable()); +#ifndef TEST_HAS_NO_EXCEPTIONS + try { + t0.join(); + assert(false); + } catch (std::system_error const&) { + } +#endif + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + std::thread t0(foo); + t0.detach(); + try { + t0.join(); + assert(false); + } catch (std::system_error const&) { + } } +#endif } diff --git a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp b/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp deleted file mode 100644 index c8807a965c44..000000000000 --- a/test/std/thread/thread.threads/thread.thread.class/thread.thread.member/native_handle.pass.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 - -// native_handle_type native_handle(); - -#include <thread> -#include <new> -#include <cstdlib> -#include <cassert> - -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; - } -}; - -int G::n_alive = 0; -bool G::op_run = false; - -int main() -{ - { - G g; - std::thread t0(g); - pthread_t pid = t0.native_handle(); - assert(pid != 0); - t0.join(); - } -} diff --git a/test/std/thread/thread.threads/thread.thread.class/types.pass.cpp b/test/std/thread/thread.threads/thread.thread.class/types.pass.cpp deleted file mode 100644 index a5bf77031cca..000000000000 --- a/test/std/thread/thread.threads/thread.thread.class/types.pass.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// { -// public: -// typedef pthread_t native_handle_type; -// ... -// }; - -#include <thread> -#include <type_traits> - -int main() -{ - static_assert((std::is_same<std::thread::native_handle_type, pthread_t>::value), ""); -} |