8057744: (process) Synchronize exiting of threads and process [win]
Reviewed-by: dholmes, dcubed, sla
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -269,4 +269,8 @@
return true;
}
+inline void os::exit(int num) {
+ ::exit(num);
+}
+
#endif // OS_AIX_VM_OS_AIX_INLINE_HPP
--- a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -274,4 +274,8 @@
#endif
}
+inline void os::exit(int num) {
+ ::exit(num);
+}
+
#endif // OS_BSD_VM_OS_BSD_INLINE_HPP
--- a/hotspot/src/os/linux/vm/os_linux.inline.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.inline.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -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
--- a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -157,4 +157,8 @@
return true;
}
+inline void os::exit(int num) {
+ ::exit(num);
+}
+
#endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Sep 10 09:52:41 2014 -0700
@@ -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
@@ -3632,6 +3622,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() {
@@ -3728,6 +3722,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);
--- a/hotspot/src/os/windows/vm/os_windows.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -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; }
--- a/hotspot/src/os/windows/vm/os_windows.inline.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -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)
--- a/hotspot/src/share/vm/runtime/java.cpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp Wed Sep 10 09:52:41 2014 -0700
@@ -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() {
--- a/hotspot/src/share/vm/runtime/os.hpp Wed Sep 10 07:06:37 2014 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Sep 10 09:52:41 2014 -0700
@@ -482,8 +482,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();