128 lines
3.9 KiB
C++
128 lines
3.9 KiB
C++
/*
|
||
Copyright (c) 2020-2023 Intel Corporation
|
||
|
||
Licensed under the Apache License, Version 2.0 (the "License");
|
||
you may not use this file except in compliance with the License.
|
||
You may obtain a copy of the License at
|
||
|
||
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
||
Unless required by applicable law or agreed to in writing, software
|
||
distributed under the License is distributed on an "AS IS" BASIS,
|
||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
See the License for the specific language governing permissions and
|
||
limitations under the License.
|
||
*/
|
||
|
||
#include "common/config.h"
|
||
|
||
#include "tbb/parallel_for.h"
|
||
#include "tbb/global_control.h"
|
||
|
||
#include "common/test.h"
|
||
#include "common/utils.h"
|
||
#include "common/utils_concurrency_limit.h"
|
||
|
||
#include <atomic>
|
||
#include <condition_variable>
|
||
#include <thread>
|
||
#include <vector>
|
||
|
||
//! \file test_eh_thread.cpp
|
||
//! \brief Test for [internal] functionality
|
||
|
||
// On Windows there is no real thread number limit beside available memory.
|
||
// Therefore, the test for thread limit is unreasonable.
|
||
// TODO: enable limitThreads with sanitizer under docker
|
||
#if TBB_USE_EXCEPTIONS && !_WIN32 && !__ANDROID__
|
||
|
||
#include <limits.h>
|
||
#include <sys/types.h>
|
||
#include <sys/time.h>
|
||
#include <sys/resource.h>
|
||
|
||
void limitThreads(size_t limit)
|
||
{
|
||
rlimit rlim;
|
||
|
||
int ret = getrlimit(RLIMIT_NPROC, &rlim);
|
||
CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
|
||
|
||
rlim.rlim_cur = (rlim.rlim_max == (rlim_t)RLIM_INFINITY) ? limit : utils::min(limit, rlim.rlim_max);
|
||
|
||
ret = setrlimit(RLIMIT_NPROC, &rlim);
|
||
CHECK_MESSAGE(0 == ret, "setrlimit has returned an error");
|
||
}
|
||
|
||
size_t getThreadLimit() {
|
||
rlimit rlim;
|
||
|
||
int ret = getrlimit(RLIMIT_NPROC, &rlim);
|
||
CHECK_MESSAGE(0 == ret, "getrlimit has returned an error");
|
||
return rlim.rlim_cur;
|
||
}
|
||
|
||
static void* thread_routine(void*)
|
||
{
|
||
return nullptr;
|
||
}
|
||
|
||
class Thread {
|
||
pthread_t mHandle{};
|
||
bool mValid{};
|
||
public:
|
||
Thread() {
|
||
mValid = false;
|
||
pthread_attr_t attr;
|
||
// Limit the stack size not to consume all virtual memory on 32 bit platforms.
|
||
std::size_t stacksize = utils::max(std::size_t(128*1024), std::size_t(PTHREAD_STACK_MIN));
|
||
if (pthread_attr_init(&attr) == 0 && pthread_attr_setstacksize(&attr, stacksize) == 0) {
|
||
mValid = pthread_create(&mHandle, &attr, thread_routine, /* arg = */ nullptr) == 0;
|
||
}
|
||
}
|
||
bool isValid() const { return mValid; }
|
||
void join() {
|
||
pthread_join(mHandle, nullptr);
|
||
}
|
||
};
|
||
|
||
//! Test for exception when too many threads
|
||
//! \brief \ref resource_usage
|
||
TEST_CASE("Too many threads") {
|
||
if (utils::get_platform_max_threads() < 2) {
|
||
// The test expects that the scheduler will try to create at least one thread.
|
||
return;
|
||
}
|
||
|
||
// Some systems set really big limit (e.g. >45К) for the number of processes/threads
|
||
limitThreads(1);
|
||
if (getThreadLimit() == 1) {
|
||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||
Thread thread;
|
||
if (thread.isValid()) {
|
||
WARN_MESSAGE(false, "We were able to create a thread. setrlimit seems having no effect");
|
||
thread.join();
|
||
return;
|
||
}
|
||
}
|
||
bool g_exception_caught = false;
|
||
try {
|
||
// Initialize the library to create worker threads
|
||
tbb::parallel_for(0, 2, [](int) {});
|
||
} catch (const std::exception & e) {
|
||
g_exception_caught = true;
|
||
// Do not CHECK to avoid memory allocation (we can be out of memory)
|
||
if (e.what()== nullptr) {
|
||
FAIL("Exception does not have description");
|
||
}
|
||
}
|
||
// Do not CHECK to avoid memory allocation (we can be out of memory)
|
||
if (!g_exception_caught) {
|
||
FAIL("No exception was thrown on library initialization");
|
||
}
|
||
} else {
|
||
WARN_MESSAGE(false, "setrlimit seems having no effect");
|
||
}
|
||
}
|
||
#endif
|