1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <stdlib.h> 28 #ifdef __APPLE__ 29 # include <dlfcn.h> 30 #endif 31 32 #ifdef _WIN32 33 #include <windows.h> 34 #else 35 #include <pthread.h> 36 #endif 37 38 #include "prims/jni.h" 39 #include "unittest.hpp" 40 41 // Default value for -new-thread option: true on AIX because we run into 42 // problems when attempting to initialize the JVM on the primordial thread. 43 #ifdef _AIX 44 const static bool DEFAULT_SPAWN_IN_NEW_THREAD = true; 45 #else 46 const static bool DEFAULT_SPAWN_IN_NEW_THREAD = false; 47 #endif 48 49 static bool is_prefix(const char* prefix, const char* str) { 50 return strncmp(str, prefix, strlen(prefix)) == 0; 51 } 52 53 static bool is_suffix(const char* suffix, const char* str) { 54 size_t suffix_len = strlen(suffix); 55 size_t str_len = strlen(str); 56 if (str_len < suffix_len) { 57 return false; 58 } 59 return strncmp(str + (str_len - suffix_len), suffix, suffix_len) == 0; 60 } 61 62 63 static int init_jvm(int argc, char **argv, bool disable_error_handling) { 64 // don't care about the program name 65 argc--; 66 argv++; 67 68 int extra_jvm_args = disable_error_handling ? 4 : 2; 69 int num_jvm_options = argc + extra_jvm_args; 70 71 JavaVMOption* options = new JavaVMOption[num_jvm_options]; 72 options[0].optionString = (char*) "-Dsun.java.launcher.is_altjvm=true"; 73 options[1].optionString = (char*) "-XX:+ExecutingUnitTests"; 74 75 if (disable_error_handling) { 76 // don't create core files or hs_err files executing assert tests 77 options[2].optionString = (char*) "-XX:+SuppressFatalErrorMessage"; 78 options[3].optionString = (char*) "-XX:-CreateCoredumpOnCrash"; 79 } 80 81 for (int i = 0; i < argc; i++) { 82 options[extra_jvm_args + i].optionString = argv[i]; 83 } 84 85 JavaVMInitArgs args; 86 args.version = JNI_VERSION_1_8; 87 args.nOptions = num_jvm_options; 88 args.options = options; 89 90 JavaVM* jvm; 91 JNIEnv* env; 92 93 return JNI_CreateJavaVM(&jvm, (void**)&env, &args); 94 } 95 96 class JVMInitializerListener : public ::testing::EmptyTestEventListener { 97 private: 98 int _argc; 99 char** _argv; 100 bool _is_initialized; 101 102 void initialize_jvm() { 103 } 104 105 public: 106 JVMInitializerListener(int argc, char** argv) : 107 _argc(argc), _argv(argv), _is_initialized(false) { 108 } 109 110 virtual void OnTestStart(const ::testing::TestInfo& test_info) { 111 const char* name = test_info.name(); 112 if (!_is_initialized && is_suffix("_test_vm", name)) { 113 // we want to have hs_err and core files when we execute regular tests 114 ASSERT_EQ(0, init_jvm(_argc, _argv, false)) << "Could not initialize the JVM"; 115 _is_initialized = true; 116 } 117 } 118 }; 119 120 static char* get_java_home_arg(int argc, char** argv) { 121 for (int i = 0; i < argc; i++) { 122 if (strncmp(argv[i], "-jdk", strlen(argv[i])) == 0) { 123 return argv[i+1]; 124 } 125 if (is_prefix("--jdk=", argv[i])) { 126 return argv[i] + strlen("--jdk="); 127 } 128 if (is_prefix("-jdk:", argv[i])) { 129 return argv[i] + strlen("-jdk:"); 130 } 131 } 132 return NULL; 133 } 134 135 static bool get_spawn_new_main_thread_arg(int argc, char** argv) { 136 // -new-thread[=(true|false)] 137 for (int i = 0; i < argc; i++) { 138 if (is_prefix("-new-thread", argv[i])) { 139 const char* v = argv[i] + strlen("-new-thread"); 140 if (strlen(v) == 0) { 141 return true; 142 } else { 143 if (strcmp(v, "=true") == 0) { 144 return true; 145 } else if (strcmp(v, "=false") == 0) { 146 return false; 147 } else { 148 fprintf(stderr, "Invalid value for -new-thread (%s)", v); 149 } 150 } 151 } 152 } 153 return DEFAULT_SPAWN_IN_NEW_THREAD; 154 } 155 156 static int num_args_to_skip(char* arg) { 157 if (strcmp(arg, "-jdk") == 0) { 158 return 2; // skip the argument after -jdk as well 159 } 160 if (is_prefix("--jdk=", arg)) { 161 return 1; 162 } 163 if (is_prefix("-jdk:", arg)) { 164 return 1; 165 } 166 if (is_prefix("-new-thread", arg)) { 167 return 1; 168 } 169 return 0; 170 } 171 172 static char** remove_test_runner_arguments(int* argcp, char **argv) { 173 int argc = *argcp; 174 char** new_argv = (char**) malloc(sizeof(char*) * argc); 175 int new_argc = 0; 176 177 int i = 0; 178 while (i < argc) { 179 int args_to_skip = num_args_to_skip(argv[i]); 180 if (args_to_skip == 0) { 181 new_argv[new_argc] = argv[i]; 182 i++; 183 new_argc++; 184 } else { 185 i += num_args_to_skip(argv[i]); 186 } 187 } 188 189 *argcp = new_argc; 190 return new_argv; 191 } 192 193 static void runUnitTestsInner(int argc, char** argv) { 194 ::testing::InitGoogleTest(&argc, argv); 195 ::testing::GTEST_FLAG(death_test_style) = "threadsafe"; 196 197 bool is_vmassert_test = false; 198 bool is_othervm_test = false; 199 // death tests facility is used for both regular death tests, other vm and vmassert tests 200 if (::testing::internal::GTEST_FLAG(internal_run_death_test).length() > 0) { 201 // when we execute death test, filter value equals to test name 202 const char* test_name = ::testing::GTEST_FLAG(filter).c_str(); 203 const char* const othervm_suffix = "_other_vm_test"; // TEST_OTHER_VM 204 const char* const vmassert_suffix = "_vm_assert_test"; // TEST_VM_ASSERT(_MSG) 205 if (is_suffix(othervm_suffix, test_name)) { 206 is_othervm_test = true; 207 } else if (is_suffix(vmassert_suffix, test_name)) { 208 is_vmassert_test = true; 209 } 210 } 211 212 char* java_home = get_java_home_arg(argc, argv); 213 if (java_home == NULL) { 214 fprintf(stderr, "ERROR: You must specify a JDK to use for running the unit tests.\n"); 215 exit(1); 216 } 217 #ifndef _WIN32 218 int overwrite = 1; // overwrite an eventual existing value for JAVA_HOME 219 setenv("JAVA_HOME", java_home, overwrite); 220 221 // workaround for JDK-7131356 222 #ifdef __APPLE__ 223 size_t len = strlen(java_home) + strlen("/lib/jli/libjli.dylib") + 1; 224 char* path = new char[len]; 225 snprintf(path, len, "%s/lib/jli/libjli.dylib", java_home); 226 dlopen(path, RTLD_NOW | RTLD_GLOBAL); 227 #endif // __APPLE__ 228 229 #else // _WIN32 230 char* java_home_var = "_ALT_JAVA_HOME_DIR"; 231 size_t len = strlen(java_home) + strlen(java_home_var) + 2; 232 char * envString = new char[len]; 233 sprintf_s(envString, len, "%s=%s", java_home_var, java_home); 234 _putenv(envString); 235 #endif // _WIN32 236 argv = remove_test_runner_arguments(&argc, argv); 237 238 if (is_vmassert_test || is_othervm_test) { 239 // both vmassert and other vm tests require inited jvm 240 // but only vmassert tests disable hs_err and core file generation 241 if (init_jvm(argc, argv, is_vmassert_test) != 0) { 242 abort(); 243 } 244 } else { 245 ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); 246 listeners.Append(new JVMInitializerListener(argc, argv)); 247 } 248 249 int result = RUN_ALL_TESTS(); 250 if (result != 0) { 251 fprintf(stderr, "ERROR: RUN_ALL_TESTS() failed. Error %d\n", result); 252 exit(2); 253 } 254 } 255 256 // Thread support for -new-thread option 257 258 struct args_t { 259 int argc; char** argv; 260 }; 261 262 #define STACK_SIZE 0x200000 263 264 #ifdef _WIN32 265 266 static DWORD WINAPI thread_wrapper(void* p) { 267 const args_t* const p_args = (const args_t*) p; 268 runUnitTestsInner(p_args->argc, p_args->argv); 269 return 0; 270 } 271 272 static void run_in_new_thread(const args_t* args) { 273 HANDLE hdl; 274 hdl = CreateThread(NULL, STACK_SIZE, thread_wrapper, (void*)args, 0, NULL); 275 if (hdl == NULL) { 276 fprintf(stderr, "Failed to create main thread\n"); 277 exit(2); 278 } 279 WaitForSingleObject(hdl, INFINITE); 280 } 281 282 #else 283 284 extern "C" void* thread_wrapper(void* p) { 285 const args_t* const p_args = (const args_t*) p; 286 runUnitTestsInner(p_args->argc, p_args->argv); 287 return 0; 288 } 289 290 static void run_in_new_thread(const args_t* args) { 291 pthread_t tid; 292 pthread_attr_t attr; 293 294 pthread_attr_init(&attr); 295 pthread_attr_setstacksize(&attr, STACK_SIZE); 296 297 if (pthread_create(&tid, &attr, thread_wrapper, (void*)args) != 0) { 298 fprintf(stderr, "Failed to create main thread\n"); 299 exit(2); 300 } 301 302 if (pthread_join(tid, NULL) != 0) { 303 fprintf(stderr, "Failed to join main thread\n"); 304 exit(2); 305 } 306 } 307 308 #endif 309 310 extern "C" 311 JNIEXPORT void JNICALL runUnitTests(int argc, char** argv) { 312 const bool spawn_new_main_thread = get_spawn_new_main_thread_arg(argc, argv); 313 if (spawn_new_main_thread) { 314 args_t args; 315 args.argc = argc; 316 args.argv = argv; 317 run_in_new_thread(&args); 318 } else { 319 runUnitTestsInner(argc, argv); 320 } 321 } 322