1 /* 2 Copyright (c) 2005-2021 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 #define DOCTEST_CONFIG_IMPLEMENT 18 #include "common/test.h" 19 20 #include "common/utils.h" 21 #include "common/utils_report.h" 22 23 #include "tbb/global_control.h" 24 #include "tbb/task_arena.h" 25 #include "tbb/scalable_allocator.h" 26 27 28 // Lets slow down the main thread on exit 29 static constexpr int MAX_DELAY = 5; 30 struct GlobalObject { 31 ~GlobalObject() { 32 utils::Sleep(rand( ) % MAX_DELAY); 33 } 34 } go; 35 36 void allocatorRandomThrashing() { 37 const int ARRAY_SIZE = 1000; 38 const int MAX_ITER = 10000; 39 const int MAX_ALLOC = 10 * 1024 * 1024; 40 41 void *arr[ARRAY_SIZE] = {0}; 42 for (int i = 0; i < rand() % MAX_ITER; ++i) { 43 // Random allocation size for random arrays 44 for (int j = 0; j < rand() % ARRAY_SIZE; ++j) { 45 arr[j] = scalable_malloc(rand() % MAX_ALLOC); 46 } 47 // Deallocate everything 48 for (int j = 0; j < ARRAY_SIZE; ++j) { 49 scalable_free(arr[j]); 50 arr[j] = NULL; 51 } 52 } 53 } 54 55 void hangOnExitReproducer() { 56 const int P = tbb::global_control::max_allowed_parallelism; 57 tbb::task_arena test_arena; 58 for (int i = 0; i < P-1; i++) { 59 test_arena.enqueue(allocatorRandomThrashing); 60 } 61 } 62 63 #if (_WIN32 || _WIN64) && !__TBB_WIN8UI_SUPPORT 64 #include <process.h> // _spawnl 65 void processSpawn(const char* self) { 66 _spawnl(_P_WAIT, self, self, "1", NULL); 67 } 68 #elif __unix__ || __APPLE__ 69 #include <unistd.h> // fork/exec 70 #include <sys/wait.h> // waitpid 71 void processSpawn(const char* self) { 72 pid_t pid = fork(); 73 if (pid == -1) { 74 REPORT("ERROR: fork failed.\n"); 75 } else if (pid == 0) { // child 76 execl(self, self, "1", NULL); 77 REPORT("ERROR: exec never returns\n"); 78 exit(1); 79 } else { // parent 80 int status; 81 waitpid(pid, &status, 0); 82 } 83 } 84 #else 85 void processSpawn(const char* /*self*/) { 86 REPORT("Known issue: no support for process spawn on this platform.\n"); 87 REPORT("done\n"); 88 exit(0); 89 } 90 #endif 91 92 #if _MSC_VER && !__INTEL_COMPILER 93 #pragma warning (push) 94 #pragma warning (disable: 4702) /* Unreachable code */ 95 #endif 96 97 //! \brief \ref error_guessing 98 TEST_CASE("testing shutdown hang") { 99 hangOnExitReproducer(); 100 CHECK(true); // just to notify that test has assertions 101 } 102 103 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 104 DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4447) 105 int main(int argc, char* argv[]) { 106 // Executed from child processes 107 if (argc == 2 && strcmp(argv[1],"1") == 0) { 108 return doctest::Context(argc, argv).run(); 109 } 110 111 // The number of executions is a tradeoff 112 // between execution time and NBTS statistics 113 const int EXEC_TIMES = 100; 114 const char* self = argv[0]; 115 for (int i = 0; i < EXEC_TIMES; i++) { 116 processSpawn(self); 117 } 118 119 #if _MSC_VER && !__INTEL_COMPILER 120 #pragma warning (pop) 121 #endif 122 } 123 DOCTEST_MSVC_SUPPRESS_WARNING_POP 124