1 /* 2 Copyright (c) 2020 Intel Corporation 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "tbb/parallel_for.h" 18 #include "tbb/global_control.h" 19 20 #include "common/test.h" 21 #include "common/utils.h" 22 23 #include <atomic> 24 #include <condition_variable> 25 #include <thread> 26 #include <vector> 27 28 //! \file test_eh_thread.cpp 29 //! \brief Test for [internal] functionality 30 31 // On Windows there is no real thread number limit beside available memory. 32 // Therefore, the test for thread limit is unreasonable. 33 #if TBB_USE_EXCEPTIONS && !_WIN32 34 35 static bool g_exception_caught = false; 36 static std::mutex m; 37 static std::condition_variable cv; 38 static std::atomic<bool> stop{ false }; 39 40 static void* thread_routine(void*) 41 { 42 std::unique_lock<std::mutex> lock(m); 43 cv.wait(lock, [] { return stop == true; }); 44 return 0; 45 } 46 47 class Thread { 48 pthread_t mHandle{}; 49 bool mValid{}; 50 public: 51 Thread() { 52 mValid = false; 53 pthread_attr_t attr; 54 // Limit the stack size not to consume all virtual memory on 32 bit platforms. 55 if (pthread_attr_init(&attr) == 0 && pthread_attr_setstacksize(&attr, 100*1024) == 0) { 56 mValid = pthread_create(&mHandle, &attr, thread_routine, /* arg = */ nullptr) == 0; 57 } 58 } 59 bool isValid() const { return mValid; } 60 void join() { 61 pthread_join(mHandle, nullptr); 62 } 63 }; 64 65 //! Test for exception when too many threads 66 //! \brief \ref resource_usage 67 TEST_CASE("Too many threads") { 68 std::thread /* isolate test */ ([] { 69 std::vector<Thread> threads; 70 stop = false; 71 for (;;) { 72 Thread thread; 73 if (!thread.isValid()) { 74 break; 75 } 76 threads.push_back(thread); 77 } 78 g_exception_caught = false; 79 try { 80 // Initialize the library to create worker threads 81 tbb::parallel_for(0, 2, [](int) {}); 82 } catch (const std::exception & e) { 83 g_exception_caught = true; 84 // Do not CHECK to avoid memory allocation (we can be out of memory) 85 if (e.what()== nullptr) { 86 FAIL("Exception does not have description"); 87 } 88 } 89 // Do not CHECK to avoid memory allocation (we can be out of memory) 90 if (!g_exception_caught) { 91 FAIL("No exception was caught"); 92 } 93 stop = true; 94 cv.notify_all(); 95 for (auto& t : threads) { 96 t.join(); 97 } 98 }).join(); 99 } 100 #endif 101