--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Oct 29 09:19:59 2014 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Oct 29 09:53:56 2014 -0700
@@ -436,9 +436,9 @@
}
// Diagnostic code to investigate JDK-6573254
- int res = 90115; // non-java thread
+ int res = 50115; // non-java thread
if (thread->is_Java_thread()) {
- res = 60115; // java thread
+ res = 40115; // java thread
}
// Install a win32 structured exception handler around every thread created
@@ -3740,68 +3740,134 @@
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;
+#define MAX_EXIT_HANDLES 16
+#define EXIT_TIMEOUT 1000 /* 1 sec */
+
+static BOOL CALLBACK init_crit_sect_call(PINIT_ONCE, PVOID pcrit_sect, PVOID*) {
+ InitializeCriticalSection((CRITICAL_SECTION*)pcrit_sect);
return TRUE;
}
int os::win32::exit_process_or_thread(Ept what, int exit_code) {
+ // Basic approach:
+ // - Each exiting thread registers its intent to exit and then does so.
+ // - A thread trying to terminate the process must wait for all
+ // threads currently exiting to complete their exit.
+
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__);
+ // The array holds handles of the threads that have started exiting by calling
+ // _endthreadex().
+ // Should be large enough to avoid blocking the exiting thread due to lack of
+ // a free slot.
+ static HANDLE handles[MAX_EXIT_HANDLES];
+ static int handle_count = 0;
+
+ static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT;
+ static CRITICAL_SECTION crit_sect;
+ int i, j;
+ DWORD res;
+ HANDLE hproc, hthr;
+
+ // The first thread that reached this point, initializes the critical section.
+ if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) {
+ warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__);
+ } else {
+ EnterCriticalSection(&crit_sect);
+
+ if (what == EPT_THREAD) {
+ // Remove from the array those handles of the threads that have completed exiting.
+ for (i = 0, j = 0; i < handle_count; ++i) {
+ res = WaitForSingleObject(handles[i], 0 /* don't wait */);
+ if (res == WAIT_TIMEOUT) {
+ handles[j++] = handles[i];
+ } else {
+ if (res != WAIT_OBJECT_0) {
+ warning("WaitForSingleObject failed in %s: %d\n", __FILE__, __LINE__);
+ // Don't keep the handle, if we failed waiting for it.
+ }
+ CloseHandle(handles[i]);
+ }
+ }
+
+ // If there's no free slot in the array of the kept handles, we'll have to
+ // wait until at least one thread completes exiting.
+ if ((handle_count = j) == MAX_EXIT_HANDLES) {
+ res = WaitForMultipleObjects(MAX_EXIT_HANDLES, handles, FALSE, EXIT_TIMEOUT);
+ if (res >= WAIT_OBJECT_0 && res < (WAIT_OBJECT_0 + MAX_EXIT_HANDLES)) {
+ i = (res - WAIT_OBJECT_0);
+ handle_count = MAX_EXIT_HANDLES - 1;
+ for (; i < handle_count; ++i) {
+ handles[i] = handles[i + 1];
+ }
+ } else {
+ warning("WaitForMultipleObjects failed in %s: %d\n", __FILE__, __LINE__);
+ // Don't keep handles, if we failed waiting for them.
+ for (i = 0; i < MAX_EXIT_HANDLES; ++i) {
+ CloseHandle(handles[i]);
+ }
+ handle_count = 0;
+ }
+ }
+
+ // Store a duplicate of the current thread handle in the array of handles.
+ hproc = GetCurrentProcess();
+ hthr = GetCurrentThread();
+ if (!DuplicateHandle(hproc, hthr, hproc, &handles[handle_count],
+ 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ warning("DuplicateHandle failed in %s: %d\n", __FILE__, __LINE__);
+ } else {
+ ++handle_count;
+ }
+
+ // The current exiting thread has stored its handle in the array, and now
+ // should leave the critical section before calling _endthreadex().
+
+ } else { // what != EPT_THREAD
+ if (handle_count > 0) {
+ // Before ending the process, make sure all the threads that had called
+ // _endthreadex() completed.
+ res = WaitForMultipleObjects(handle_count, handles, TRUE, EXIT_TIMEOUT);
+ if (res == WAIT_FAILED) {
+ warning("WaitForMultipleObjects failed in %s: %d\n", __FILE__, __LINE__);
+ }
+ for (i = 0; i < handle_count; ++i) {
+ CloseHandle(handles[i]);
+ }
+ handle_count = 0;
+ }
+
+ // End the process, not leaving critical section.
+ // This makes sure no other thread executes exit-related code at the same
+ // time, thus a race is avoided.
+ if (what == EPT_PROCESS) {
+ ::exit(exit_code);
+ } else {
+ _exit(exit_code);
+ }
+ }
+
+ LeaveCriticalSection(&crit_sect);
}
}
- switch (what) {
- case EPT_THREAD:
+ // We are here if either
+ // - there's no 'race at exit' bug on this OS release;
+ // - initialization of the critical section failed (unlikely);
+ // - the current thread has stored its handle and left the critical section.
+ if (what == EPT_THREAD) {
_endthreadex((unsigned)exit_code);
- break;
-
- case EPT_PROCESS:
+ } else if (what == EPT_PROCESS) {
::exit(exit_code);
- break;
-
- case EPT_PROCESS_DIE:
+ } else {
_exit(exit_code);
- break;
- }
-
- // should not reach here
+ }
+
+ // Should not reach here
return exit_code;
}
-#undef MIN_EXIT_MUTEXES
-#undef MAX_EXIT_MUTEXES
+#undef MAX_EXIT_HANDLES
+#undef EXIT_TIMEOUT
void os::win32::setmode_streams() {
_setmode(_fileno(stdin), _O_BINARY);