diff -r eb5f1b4f01e1 -r 7fce477785a3 hotspot/src/os/windows/vm/os_windows.cpp --- 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);