--- old/src/os/aix/vm/os_aix.inline.hpp 2014-09-07 09:54:00.971990429 +0400 +++ new/src/os/aix/vm/os_aix.inline.hpp 2014-09-07 09:54:00.863937788 +0400 @@ -269,4 +269,8 @@ return true; } +inline void os::exit(int num) { + ::exit(num); +} + #endif // OS_AIX_VM_OS_AIX_INLINE_HPP --- old/src/os/bsd/vm/os_bsd.inline.hpp 2014-09-07 09:54:01.460228294 +0400 +++ new/src/os/bsd/vm/os_bsd.inline.hpp 2014-09-07 09:54:01.356177601 +0400 @@ -274,4 +274,8 @@ #endif } +inline void os::exit(int num) { + ::exit(num); +} + #endif // OS_BSD_VM_OS_BSD_INLINE_HPP --- old/src/os/linux/vm/os_linux.inline.hpp 2014-09-07 09:54:01.920452512 +0400 +++ new/src/os/linux/vm/os_linux.inline.hpp 2014-09-07 09:54:01.820403768 +0400 @@ -263,4 +263,8 @@ return Linux::_clock_gettime != NULL; } +inline void os::exit(int num) { + ::exit(num); +} + #endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP --- old/src/os/solaris/vm/os_solaris.inline.hpp 2014-09-07 09:54:02.380676730 +0400 +++ new/src/os/solaris/vm/os_solaris.inline.hpp 2014-09-07 09:54:02.276626038 +0400 @@ -157,4 +157,8 @@ return true; } +inline void os::exit(int num) { + ::exit(num); +} + #endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP --- old/src/os/windows/vm/os_windows.cpp 2014-09-07 09:54:02.864912646 +0400 +++ new/src/os/windows/vm/os_windows.cpp 2014-09-07 09:54:02.740852203 +0400 @@ -22,8 +22,8 @@ * */ -// Must be at least Windows 2000 or XP to use IsDebuggerPresent -#define _WIN32_WINNT 0x500 +// Must be at least Windows Vista or Server 2008 to use InitOnceExecuteOnce +#define _WIN32_WINNT 0x0600 // no precompiled headers #include "classfile/classLoader.hpp" @@ -409,8 +409,6 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo); -extern jint volatile vm_getting_terminated; - // Thread start routine for all new Java threads static unsigned __stdcall java_start(Thread* thread) { // Try to randomize the cache line index of hot stack frames. @@ -432,13 +430,10 @@ } } - // Diagnostic code to investigate JDK-6573254 (Part I) - unsigned res = 90115; // non-java thread + // Diagnostic code to investigate JDK-6573254 + int res = 90115; // non-java thread if (thread->is_Java_thread()) { - JavaThread* java_thread = (JavaThread*)thread; - res = java_lang_Thread::is_daemon(java_thread->threadObj()) - ? 70115 // java daemon thread - : 80115; // java non-daemon thread + res = 60115; // java thread } // Install a win32 structured exception handler around every thread created @@ -458,12 +453,9 @@ Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count); } - // Diagnostic code to investigate JDK-6573254 (Part II) - if (OrderAccess::load_acquire(&vm_getting_terminated)) { - return res; - } - - return 0; + // Thread must not return from exit_process_or_thread(), but if it does, + // let it proceed to exit normally + return (unsigned)os::win32::exit_process_or_thread(os::win32::EPT_THREAD, res); } static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) { @@ -1062,17 +1054,15 @@ } - -void os::abort(bool dump_core) -{ +void os::abort(bool dump_core) { os::shutdown(); // no core dump on Windows - ::exit(1); + win32::exit_process_or_thread(win32::EPT_PROCESS, 1); } // Die immediately, no exit hook, no abort hook, no cleanup. void os::die() { - _exit(-1); + win32::exit_process_or_thread(win32::EPT_PROCESS_DIE, -1); } // Directory routines copied from src/win32/native/java/io/dirent_md.c @@ -3623,6 +3613,10 @@ bool os::win32::_is_windows_2003 = false; bool os::win32::_is_windows_server = false; +// 6573254 +// Currently, the bug is observed across all the supported Windows releases, +// including the latest one (as of this writing - Windows Server 2012 R2) +bool os::win32::_has_exit_bug = true; bool os::win32::_has_performance_count = 0; void os::win32::initialize_system_info() { @@ -3719,6 +3713,69 @@ return NULL; } +#define MIN_EXIT_MUTEXES 1 +#define MAX_EXIT_MUTEXES 16 + +struct ExitMutexes { + DWORD count; + HANDLE handles[MAX_EXIT_MUTEXES]; +}; + +static BOOL CALLBACK init_muts_call(PINIT_ONCE, PVOID ppmuts, PVOID*) { + static ExitMutexes muts; + + muts.count = os::processor_count(); + if (muts.count < MIN_EXIT_MUTEXES) { + muts.count = MIN_EXIT_MUTEXES; + } else if (muts.count > MAX_EXIT_MUTEXES) { + muts.count = MAX_EXIT_MUTEXES; + } + + for (DWORD i = 0; i < muts.count; ++i) { + muts.handles[i] = CreateMutex(NULL, FALSE, NULL); + if (muts.handles[i] == NULL) { + return FALSE; + } + } + *((ExitMutexes**)ppmuts) = &muts; + return TRUE; +} + +int os::win32::exit_process_or_thread(Ept what, int exit_code) { + if (os::win32::has_exit_bug()) { + static INIT_ONCE init_once_muts = INIT_ONCE_STATIC_INIT; + static ExitMutexes* pmuts; + + if (!InitOnceExecuteOnce(&init_once_muts, init_muts_call, &pmuts, NULL)) { + warning("ExitMutex initialization failed in %s: %d\n", __FILE__, __LINE__); + } else if (WaitForMultipleObjects(pmuts->count, pmuts->handles, + (what != EPT_THREAD), // exiting process waits for all mutexes + INFINITE) == WAIT_FAILED) { + warning("ExitMutex acquisition failed in %s: %d\n", __FILE__, __LINE__); + } + } + + switch (what) { + case EPT_THREAD: + _endthreadex((unsigned)exit_code); + break; + + case EPT_PROCESS: + ::exit(exit_code); + break; + + case EPT_PROCESS_DIE: + _exit(exit_code); + break; + } + + // should not reach here + return exit_code; +} + +#undef MIN_EXIT_MUTEXES +#undef MAX_EXIT_MUTEXES + void os::win32::setmode_streams() { _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); --- old/src/os/windows/vm/os_windows.hpp 2014-09-07 09:54:03.457201202 +0400 +++ new/src/os/windows/vm/os_windows.hpp 2014-09-07 09:54:03.357152459 +0400 @@ -36,6 +36,7 @@ class win32 { friend class os; + friend unsigned __stdcall java_start(class Thread*); protected: static int _vm_page_size; @@ -47,6 +48,7 @@ static bool _is_nt; static bool _is_windows_2003; static bool _is_windows_server; + static bool _has_exit_bug; static bool _has_performance_count; static void print_windows_version(outputStream* st); @@ -69,8 +71,12 @@ // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); - private: - static void initialize_performance_counter(); + private: + enum Ept { EPT_THREAD, EPT_PROCESS, EPT_PROCESS_DIE }; + // Wrapper around _endthreadex(), exit() and _exit() + static int exit_process_or_thread(Ept what, int exit_code); + + static void initialize_performance_counter(); public: // Generic interface: @@ -88,6 +94,9 @@ // Tells whether the platform is Windows 2003 static bool is_windows_2003() { return _is_windows_2003; } + // Tells whether there can be the race bug during process exit on this platform + static bool has_exit_bug() { return _has_exit_bug; } + // Returns the byte size of a virtual memory page static int vm_page_size() { return _vm_page_size; } --- old/src/os/windows/vm/os_windows.inline.hpp 2014-09-07 09:54:03.941437119 +0400 +++ new/src/os/windows/vm/os_windows.inline.hpp 2014-09-07 09:54:03.821378626 +0400 @@ -100,6 +100,10 @@ return win32::_has_performance_count; } +inline void os::exit(int num) { + win32::exit_process_or_thread(win32::EPT_PROCESS, num); +} + #define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \ os::win32::call_test_func_with_wrapper(f) --- old/src/share/vm/runtime/java.cpp 2014-09-07 09:54:04.537727625 +0400 +++ new/src/share/vm/runtime/java.cpp 2014-09-07 09:54:04.401661334 +0400 @@ -430,8 +430,6 @@ } } -jint volatile vm_getting_terminated = 0; - // Note: before_exit() can be executed only once, if more than one threads // are trying to shutdown the VM at the same time, only one thread // can run before_exit() and all other threads must wait. @@ -462,8 +460,6 @@ } } - OrderAccess::release_store(&vm_getting_terminated, 1); - // The only difference between this and Win32's _onexit procs is that // this version is invoked before any threads get killed. ExitProc* current = exit_procs; @@ -587,7 +583,7 @@ void vm_direct_exit(int code) { notify_vm_shutdown(); os::wait_for_keypress_at_exit(); - ::exit(code); + os::exit(code); } void vm_perform_shutdown_actions() { --- old/src/share/vm/runtime/os.hpp 2014-09-07 09:54:04.989947943 +0400 +++ new/src/share/vm/runtime/os.hpp 2014-09-07 09:54:04.885897251 +0400 @@ -481,8 +481,8 @@ // run cmd in a separate process and return its exit code; or -1 on failures static int fork_and_exec(char *cmd); - // os::exit() is merged with vm_exit() - // static void exit(int num); + // Call ::exit() on all platforms but Windows + static void exit(int num); // Terminate the VM, but don't exit the process static void shutdown();