1 /*
2 Copyright (c) 2020-2023 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 "common/config.h"
18
19 #include "tbb/parallel_for.h"
20 #include "tbb/global_control.h"
21
22 #include "common/test.h"
23 #include "common/utils.h"
24 #include "common/utils_concurrency_limit.h"
25
26 #include <atomic>
27 #include <condition_variable>
28 #include <thread>
29 #include <vector>
30
31 //! \file test_eh_thread.cpp
32 //! \brief Test for [internal] functionality
33
34 // On Windows there is no real thread number limit beside available memory.
35 // Therefore, the test for thread limit is unreasonable.
36 // TODO: enable limitThreads with sanitizer under docker
37 #if TBB_USE_EXCEPTIONS && !_WIN32 && !__ANDROID__
38
39 #include <limits.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/resource.h>
43
limitThreads(size_t limit)44 void limitThreads(size_t limit)
45 {
46 rlimit rlim;
47
48 int ret = getrlimit(RLIMIT_NPROC, &rlim);
49 CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
50
51 rlim.rlim_cur = (rlim.rlim_max == (rlim_t)RLIM_INFINITY) ? limit : utils::min(limit, rlim.rlim_max);
52
53 ret = setrlimit(RLIMIT_NPROC, &rlim);
54 CHECK_MESSAGE(0 == ret, "setrlimit has returned an error");
55 }
56
getThreadLimit()57 size_t getThreadLimit() {
58 rlimit rlim;
59
60 int ret = getrlimit(RLIMIT_NPROC, &rlim);
61 CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
62 return rlim.rlim_cur;
63 }
64
thread_routine(void *)65 static void* thread_routine(void*)
66 {
67 return nullptr;
68 }
69
70 class Thread {
71 pthread_t mHandle{};
72 bool mValid{};
73 public:
Thread()74 Thread() {
75 mValid = false;
76 pthread_attr_t attr;
77 // Limit the stack size not to consume all virtual memory on 32 bit platforms.
78 std::size_t stacksize = utils::max(std::size_t(128*1024), std::size_t(PTHREAD_STACK_MIN));
79 if (pthread_attr_init(&attr) == 0 && pthread_attr_setstacksize(&attr, stacksize) == 0) {
80 mValid = pthread_create(&mHandle, &attr, thread_routine, /* arg = */ nullptr) == 0;
81 }
82 }
isValid() const83 bool isValid() const { return mValid; }
join()84 void join() {
85 pthread_join(mHandle, nullptr);
86 }
87 };
88
89 //! Test for exception when too many threads
90 //! \brief \ref resource_usage
91 TEST_CASE("Too many threads") {
92 if (utils::get_platform_max_threads() < 2) {
93 // The test expects that the scheduler will try to create at least one thread.
94 return;
95 }
96
97 // Some systems set really big limit (e.g. >45К) for the number of processes/threads
98 limitThreads(1);
99 if (getThreadLimit() == 1) {
100 for (int attempt = 0; attempt < 5; ++attempt) {
101 Thread thread;
102 if (thread.isValid()) {
103 WARN_MESSAGE(false, "We were able to create a thread. setrlimit seems having no effect");
104 thread.join();
105 return;
106 }
107 }
108 bool g_exception_caught = false;
109 try {
110 // Initialize the library to create worker threads
__anond362a48e0102(int) 111 tbb::parallel_for(0, 2, [](int) {});
112 } catch (const std::exception & e) {
113 g_exception_caught = true;
114 // Do not CHECK to avoid memory allocation (we can be out of memory)
115 if (e.what()== nullptr) {
116 FAIL("Exception does not have description");
117 }
118 }
119 // Do not CHECK to avoid memory allocation (we can be out of memory)
120 if (!g_exception_caught) {
121 FAIL("No exception was thrown on library initialization");
122 }
123 } else {
124 WARN_MESSAGE(false, "setrlimit seems having no effect");
125 }
126 }
127 #endif
128