xref: /oneTBB/test/tbb/test_eh_thread.cpp (revision ab7f370c)
151c0b2f7Stbbdev /*
2*ab7f370cSPavel Kumbrasev     Copyright (c) 2020-2023 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
178b6f831cStbbdev #include "common/config.h"
188b6f831cStbbdev 
1951c0b2f7Stbbdev #include "tbb/parallel_for.h"
2051c0b2f7Stbbdev #include "tbb/global_control.h"
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev #include "common/test.h"
2351c0b2f7Stbbdev #include "common/utils.h"
248b6f831cStbbdev #include "common/utils_concurrency_limit.h"
2551c0b2f7Stbbdev 
2651c0b2f7Stbbdev #include <atomic>
2751c0b2f7Stbbdev #include <condition_variable>
2851c0b2f7Stbbdev #include <thread>
2951c0b2f7Stbbdev #include <vector>
3051c0b2f7Stbbdev 
3151c0b2f7Stbbdev //! \file test_eh_thread.cpp
3251c0b2f7Stbbdev //! \brief Test for [internal] functionality
3351c0b2f7Stbbdev 
3451c0b2f7Stbbdev // On Windows there is no real thread number limit beside available memory.
3551c0b2f7Stbbdev // Therefore, the test for thread limit is unreasonable.
36a080baf9SAlex // TODO: enable limitThreads with sanitizer under docker
37a080baf9SAlex #if TBB_USE_EXCEPTIONS && !_WIN32 && !__ANDROID__
38a080baf9SAlex 
39013035b4SVladislav Shchapov #include <limits.h>
40a080baf9SAlex #include <sys/types.h>
41a080baf9SAlex #include <sys/time.h>
42a080baf9SAlex #include <sys/resource.h>
43a080baf9SAlex 
limitThreads(size_t limit)44a080baf9SAlex void limitThreads(size_t limit)
45a080baf9SAlex {
46a080baf9SAlex     rlimit rlim;
47a080baf9SAlex 
48a080baf9SAlex     int ret = getrlimit(RLIMIT_NPROC, &rlim);
49a080baf9SAlex     CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
50a080baf9SAlex 
51a080baf9SAlex     rlim.rlim_cur = (rlim.rlim_max == (rlim_t)RLIM_INFINITY) ? limit : utils::min(limit, rlim.rlim_max);
52a080baf9SAlex 
53a080baf9SAlex     ret = setrlimit(RLIMIT_NPROC, &rlim);
54a080baf9SAlex     CHECK_MESSAGE(0 == ret, "setrlimit has returned an error");
55a080baf9SAlex }
5651c0b2f7Stbbdev 
getThreadLimit()57ceacd220SIlya Isaev size_t getThreadLimit() {
58ceacd220SIlya Isaev     rlimit rlim;
59ceacd220SIlya Isaev 
60ceacd220SIlya Isaev     int ret = getrlimit(RLIMIT_NPROC, &rlim);
61ceacd220SIlya Isaev     CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
62ceacd220SIlya Isaev     return rlim.rlim_cur;
63ceacd220SIlya Isaev }
6451c0b2f7Stbbdev 
thread_routine(void *)6551c0b2f7Stbbdev static void* thread_routine(void*)
6651c0b2f7Stbbdev {
6757f524caSIlya Isaev     return nullptr;
6851c0b2f7Stbbdev }
6951c0b2f7Stbbdev 
7051c0b2f7Stbbdev class Thread {
7151c0b2f7Stbbdev     pthread_t mHandle{};
7251c0b2f7Stbbdev     bool mValid{};
7351c0b2f7Stbbdev public:
Thread()7451c0b2f7Stbbdev     Thread() {
7551c0b2f7Stbbdev         mValid = false;
7651c0b2f7Stbbdev         pthread_attr_t attr;
7751c0b2f7Stbbdev         // Limit the stack size not to consume all virtual memory on 32 bit platforms.
78*ab7f370cSPavel Kumbrasev         std::size_t stacksize = utils::max(std::size_t(128*1024), std::size_t(PTHREAD_STACK_MIN));
79013035b4SVladislav Shchapov         if (pthread_attr_init(&attr) == 0 && pthread_attr_setstacksize(&attr, stacksize) == 0) {
8051c0b2f7Stbbdev             mValid = pthread_create(&mHandle, &attr, thread_routine, /* arg = */ nullptr) == 0;
8151c0b2f7Stbbdev         }
8251c0b2f7Stbbdev     }
isValid() const8351c0b2f7Stbbdev     bool isValid() const { return mValid; }
join()8451c0b2f7Stbbdev     void join() {
8551c0b2f7Stbbdev         pthread_join(mHandle, nullptr);
8651c0b2f7Stbbdev     }
8751c0b2f7Stbbdev };
8851c0b2f7Stbbdev 
8951c0b2f7Stbbdev //! Test for exception when too many threads
9051c0b2f7Stbbdev //! \brief \ref resource_usage
9151c0b2f7Stbbdev TEST_CASE("Too many threads") {
928b6f831cStbbdev     if (utils::get_platform_max_threads() < 2) {
938b6f831cStbbdev         // The test expects that the scheduler will try to create at least one thread.
948b6f831cStbbdev         return;
958b6f831cStbbdev     }
96a080baf9SAlex 
97a080baf9SAlex     // Some systems set really big limit (e.g. >45К) for the number of processes/threads
98ceacd220SIlya Isaev     limitThreads(1);
99ceacd220SIlya Isaev     if (getThreadLimit() == 1) {
100ceacd220SIlya Isaev         for (int attempt = 0; attempt < 5; ++attempt) {
10151c0b2f7Stbbdev             Thread thread;
102ceacd220SIlya Isaev             if (thread.isValid()) {
103ceacd220SIlya Isaev                 WARN_MESSAGE(false, "We were able to create a thread. setrlimit seems having no effect");
104ceacd220SIlya Isaev                 thread.join();
105a080baf9SAlex                 return;
106a080baf9SAlex             }
10751c0b2f7Stbbdev         }
108ceacd220SIlya Isaev         bool g_exception_caught = false;
10951c0b2f7Stbbdev         try {
11051c0b2f7Stbbdev             // Initialize the library to create worker threads
__anond362a48e0102(int) 11151c0b2f7Stbbdev             tbb::parallel_for(0, 2, [](int) {});
11251c0b2f7Stbbdev         } catch (const std::exception & e) {
11351c0b2f7Stbbdev             g_exception_caught = true;
11451c0b2f7Stbbdev             // Do not CHECK to avoid memory allocation (we can be out of memory)
11551c0b2f7Stbbdev             if (e.what()== nullptr) {
11651c0b2f7Stbbdev                 FAIL("Exception does not have description");
11751c0b2f7Stbbdev             }
11851c0b2f7Stbbdev         }
11951c0b2f7Stbbdev         // Do not CHECK to avoid memory allocation (we can be out of memory)
12051c0b2f7Stbbdev         if (!g_exception_caught) {
121ceacd220SIlya Isaev             FAIL("No exception was thrown on library initialization");
12251c0b2f7Stbbdev         }
123ceacd220SIlya Isaev     } else {
124ceacd220SIlya Isaev         WARN_MESSAGE(false, "setrlimit seems having no effect");
125ceacd220SIlya Isaev     }
12651c0b2f7Stbbdev }
12751c0b2f7Stbbdev #endif
128