151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov Copyright (c) 2005-2022 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
1751c0b2f7Stbbdev #define DOCTEST_CONFIG_IMPLEMENT
1849e08aacStbbdev #include "common/test.h"
1951c0b2f7Stbbdev
2051c0b2f7Stbbdev #include "common/utils.h"
2151c0b2f7Stbbdev #include "common/utils_report.h"
2251c0b2f7Stbbdev
2351c0b2f7Stbbdev #include "tbb/global_control.h"
2451c0b2f7Stbbdev #include "tbb/task_arena.h"
2551c0b2f7Stbbdev #include "tbb/scalable_allocator.h"
2651c0b2f7Stbbdev
2751c0b2f7Stbbdev
2851c0b2f7Stbbdev // Lets slow down the main thread on exit
2951c0b2f7Stbbdev static constexpr int MAX_DELAY = 5;
3051c0b2f7Stbbdev struct GlobalObject {
~GlobalObjectGlobalObject3151c0b2f7Stbbdev ~GlobalObject() {
3251c0b2f7Stbbdev utils::Sleep(rand( ) % MAX_DELAY);
3351c0b2f7Stbbdev }
3451c0b2f7Stbbdev } go;
3551c0b2f7Stbbdev
allocatorRandomThrashing()3651c0b2f7Stbbdev void allocatorRandomThrashing() {
3751c0b2f7Stbbdev const int ARRAY_SIZE = 1000;
3851c0b2f7Stbbdev const int MAX_ITER = 10000;
3951c0b2f7Stbbdev const int MAX_ALLOC = 10 * 1024 * 1024;
4051c0b2f7Stbbdev
4157f524caSIlya Isaev void *arr[ARRAY_SIZE] = {nullptr};
4251c0b2f7Stbbdev for (int i = 0; i < rand() % MAX_ITER; ++i) {
4351c0b2f7Stbbdev // Random allocation size for random arrays
4451c0b2f7Stbbdev for (int j = 0; j < rand() % ARRAY_SIZE; ++j) {
4551c0b2f7Stbbdev arr[j] = scalable_malloc(rand() % MAX_ALLOC);
4651c0b2f7Stbbdev }
4751c0b2f7Stbbdev // Deallocate everything
4851c0b2f7Stbbdev for (int j = 0; j < ARRAY_SIZE; ++j) {
4951c0b2f7Stbbdev scalable_free(arr[j]);
5057f524caSIlya Isaev arr[j] = nullptr;
5151c0b2f7Stbbdev }
5251c0b2f7Stbbdev }
5351c0b2f7Stbbdev }
5451c0b2f7Stbbdev
hangOnExitReproducer()5551c0b2f7Stbbdev void hangOnExitReproducer() {
5651c0b2f7Stbbdev const int P = tbb::global_control::max_allowed_parallelism;
5751c0b2f7Stbbdev tbb::task_arena test_arena;
5851c0b2f7Stbbdev for (int i = 0; i < P-1; i++) {
5951c0b2f7Stbbdev test_arena.enqueue(allocatorRandomThrashing);
6051c0b2f7Stbbdev }
6151c0b2f7Stbbdev }
6251c0b2f7Stbbdev
6351c0b2f7Stbbdev #if (_WIN32 || _WIN64) && !__TBB_WIN8UI_SUPPORT
6451c0b2f7Stbbdev #include <process.h> // _spawnl
processSpawn(const char * self)6551c0b2f7Stbbdev void processSpawn(const char* self) {
6657f524caSIlya Isaev _spawnl(_P_WAIT, self, self, "1", nullptr);
6751c0b2f7Stbbdev }
68734f0bc0SPablo Romero #elif __unix__ || __APPLE__
6951c0b2f7Stbbdev #include <unistd.h> // fork/exec
7051c0b2f7Stbbdev #include <sys/wait.h> // waitpid
processSpawn(const char * self)7151c0b2f7Stbbdev void processSpawn(const char* self) {
7251c0b2f7Stbbdev pid_t pid = fork();
7351c0b2f7Stbbdev if (pid == -1) {
7451c0b2f7Stbbdev REPORT("ERROR: fork failed.\n");
7551c0b2f7Stbbdev } else if (pid == 0) { // child
7657f524caSIlya Isaev execl(self, self, "1", nullptr);
7751c0b2f7Stbbdev REPORT("ERROR: exec never returns\n");
7851c0b2f7Stbbdev exit(1);
7951c0b2f7Stbbdev } else { // parent
8051c0b2f7Stbbdev int status;
8151c0b2f7Stbbdev waitpid(pid, &status, 0);
8251c0b2f7Stbbdev }
8351c0b2f7Stbbdev }
8451c0b2f7Stbbdev #else
processSpawn(const char *)8551c0b2f7Stbbdev void processSpawn(const char* /*self*/) {
8651c0b2f7Stbbdev REPORT("Known issue: no support for process spawn on this platform.\n");
8751c0b2f7Stbbdev REPORT("done\n");
8851c0b2f7Stbbdev exit(0);
8951c0b2f7Stbbdev }
9051c0b2f7Stbbdev #endif
9151c0b2f7Stbbdev
9251c0b2f7Stbbdev #if _MSC_VER && !__INTEL_COMPILER
9351c0b2f7Stbbdev #pragma warning (push)
9451c0b2f7Stbbdev #pragma warning (disable: 4702) /* Unreachable code */
9551c0b2f7Stbbdev #endif
9651c0b2f7Stbbdev
9751c0b2f7Stbbdev //! \brief \ref error_guessing
9851c0b2f7Stbbdev TEST_CASE("testing shutdown hang") {
9951c0b2f7Stbbdev hangOnExitReproducer();
10051c0b2f7Stbbdev CHECK(true); // just to notify that test has assertions
10151c0b2f7Stbbdev }
10251c0b2f7Stbbdev
10351c0b2f7Stbbdev DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182
10451c0b2f7Stbbdev DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4447)
main(int argc,char * argv[])10551c0b2f7Stbbdev int main(int argc, char* argv[]) {
10651c0b2f7Stbbdev // Executed from child processes
10751c0b2f7Stbbdev if (argc == 2 && strcmp(argv[1],"1") == 0) {
10851c0b2f7Stbbdev return doctest::Context(argc, argv).run();
10951c0b2f7Stbbdev }
11051c0b2f7Stbbdev
11151c0b2f7Stbbdev // The number of executions is a tradeoff
11251c0b2f7Stbbdev // between execution time and NBTS statistics
11351c0b2f7Stbbdev const int EXEC_TIMES = 100;
11451c0b2f7Stbbdev const char* self = argv[0];
11551c0b2f7Stbbdev for (int i = 0; i < EXEC_TIMES; i++) {
11651c0b2f7Stbbdev processSpawn(self);
11751c0b2f7Stbbdev }
11851c0b2f7Stbbdev
11951c0b2f7Stbbdev #if _MSC_VER && !__INTEL_COMPILER
12051c0b2f7Stbbdev #pragma warning (pop)
12151c0b2f7Stbbdev #endif
12251c0b2f7Stbbdev }
12351c0b2f7Stbbdev DOCTEST_MSVC_SUPPRESS_WARNING_POP
124