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