3831 if (os::win32::has_exit_bug()) { |
3832 if (os::win32::has_exit_bug()) { |
3832 // The array holds handles of the threads that have started exiting by calling |
3833 // The array holds handles of the threads that have started exiting by calling |
3833 // _endthreadex(). |
3834 // _endthreadex(). |
3834 // Should be large enough to avoid blocking the exiting thread due to lack of |
3835 // Should be large enough to avoid blocking the exiting thread due to lack of |
3835 // a free slot. |
3836 // a free slot. |
3836 static HANDLE handles[MAXIMUM_WAIT_OBJECTS]; |
3837 static HANDLE handles[MAXIMUM_THREADS_TO_KEEP]; |
3837 static int handle_count = 0; |
3838 static int handle_count = 0; |
3838 |
3839 |
3839 static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; |
3840 static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT; |
3840 static CRITICAL_SECTION crit_sect; |
3841 static CRITICAL_SECTION crit_sect; |
3841 static volatile jint process_exiting = 0; |
3842 static volatile jint process_exiting = 0; |
3845 |
3846 |
3846 // The first thread that reached this point, initializes the critical section. |
3847 // The first thread that reached this point, initializes the critical section. |
3847 if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { |
3848 if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) { |
3848 warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); |
3849 warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__); |
3849 } else if (OrderAccess::load_acquire(&process_exiting) == 0) { |
3850 } else if (OrderAccess::load_acquire(&process_exiting) == 0) { |
|
3851 if (what != EPT_THREAD) { |
|
3852 // Atomically set process_exiting before the critical section |
|
3853 // to increase the visibility between racing threads. |
|
3854 Atomic::cmpxchg((jint)GetCurrentThreadId(), &process_exiting, 0); |
|
3855 } |
3850 EnterCriticalSection(&crit_sect); |
3856 EnterCriticalSection(&crit_sect); |
3851 |
3857 |
3852 if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { |
3858 if (what == EPT_THREAD && OrderAccess::load_acquire(&process_exiting) == 0) { |
3853 // Remove from the array those handles of the threads that have completed exiting. |
3859 // Remove from the array those handles of the threads that have completed exiting. |
3854 for (i = 0, j = 0; i < handle_count; ++i) { |
3860 for (i = 0, j = 0; i < handle_count; ++i) { |
3865 } |
3871 } |
3866 } |
3872 } |
3867 |
3873 |
3868 // If there's no free slot in the array of the kept handles, we'll have to |
3874 // If there's no free slot in the array of the kept handles, we'll have to |
3869 // wait until at least one thread completes exiting. |
3875 // wait until at least one thread completes exiting. |
3870 if ((handle_count = j) == MAXIMUM_WAIT_OBJECTS) { |
3876 if ((handle_count = j) == MAXIMUM_THREADS_TO_KEEP) { |
3871 // Raise the priority of the oldest exiting thread to increase its chances |
3877 // Raise the priority of the oldest exiting thread to increase its chances |
3872 // to complete sooner. |
3878 // to complete sooner. |
3873 SetThreadPriority(handles[0], THREAD_PRIORITY_ABOVE_NORMAL); |
3879 SetThreadPriority(handles[0], THREAD_PRIORITY_ABOVE_NORMAL); |
3874 res = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, handles, FALSE, EXIT_TIMEOUT); |
3880 res = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, handles, FALSE, EXIT_TIMEOUT); |
3875 if (res >= WAIT_OBJECT_0 && res < (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) { |
3881 if (res >= WAIT_OBJECT_0 && res < (WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)) { |
3876 i = (res - WAIT_OBJECT_0); |
3882 i = (res - WAIT_OBJECT_0); |
3877 handle_count = MAXIMUM_WAIT_OBJECTS - 1; |
3883 handle_count = MAXIMUM_THREADS_TO_KEEP - 1; |
3878 for (; i < handle_count; ++i) { |
3884 for (; i < handle_count; ++i) { |
3879 handles[i] = handles[i + 1]; |
3885 handles[i] = handles[i + 1]; |
3880 } |
3886 } |
3881 } else { |
3887 } else { |
3882 warning("WaitForMultipleObjects %s (%u) in %s: %d\n", |
3888 warning("WaitForMultipleObjects %s (%u) in %s: %d\n", |
3883 (res == WAIT_FAILED ? "failed" : "timed out"), |
3889 (res == WAIT_FAILED ? "failed" : "timed out"), |
3884 GetLastError(), __FILE__, __LINE__); |
3890 GetLastError(), __FILE__, __LINE__); |
3885 // Don't keep handles, if we failed waiting for them. |
3891 // Don't keep handles, if we failed waiting for them. |
3886 for (i = 0; i < MAXIMUM_WAIT_OBJECTS; ++i) { |
3892 for (i = 0; i < MAXIMUM_THREADS_TO_KEEP; ++i) { |
3887 CloseHandle(handles[i]); |
3893 CloseHandle(handles[i]); |
3888 } |
3894 } |
3889 handle_count = 0; |
3895 handle_count = 0; |
3890 } |
3896 } |
3891 } |
3897 } |
3902 } |
3908 } |
3903 |
3909 |
3904 // The current exiting thread has stored its handle in the array, and now |
3910 // The current exiting thread has stored its handle in the array, and now |
3905 // should leave the critical section before calling _endthreadex(). |
3911 // should leave the critical section before calling _endthreadex(). |
3906 |
3912 |
3907 } else if (what != EPT_THREAD) { |
3913 } else if (what != EPT_THREAD && handle_count > 0) { |
3908 if (handle_count > 0) { |
3914 jlong start_time, finish_time, timeout_left; |
3909 // Before ending the process, make sure all the threads that had called |
3915 // Before ending the process, make sure all the threads that had called |
3910 // _endthreadex() completed. |
3916 // _endthreadex() completed. |
3911 |
3917 |
3912 // Set the priority level of the current thread to the same value as |
3918 // Set the priority level of the current thread to the same value as |
3913 // the priority level of exiting threads. |
3919 // the priority level of exiting threads. |
3914 // This is to ensure it will be given a fair chance to execute if |
3920 // This is to ensure it will be given a fair chance to execute if |
3915 // the timeout expires. |
3921 // the timeout expires. |
3916 hthr = GetCurrentThread(); |
3922 hthr = GetCurrentThread(); |
3917 SetThreadPriority(hthr, THREAD_PRIORITY_ABOVE_NORMAL); |
3923 SetThreadPriority(hthr, THREAD_PRIORITY_ABOVE_NORMAL); |
3918 for (i = 0; i < handle_count; ++i) { |
3924 start_time = os::javaTimeNanos(); |
3919 SetThreadPriority(handles[i], THREAD_PRIORITY_ABOVE_NORMAL); |
3925 finish_time = start_time + ((jlong)EXIT_TIMEOUT * 1000000L); |
|
3926 for (i = 0; ; ) { |
|
3927 int portion_count = handle_count - i; |
|
3928 if (portion_count > MAXIMUM_WAIT_OBJECTS) { |
|
3929 portion_count = MAXIMUM_WAIT_OBJECTS; |
3920 } |
3930 } |
3921 res = WaitForMultipleObjects(handle_count, handles, TRUE, EXIT_TIMEOUT); |
3931 for (j = 0; j < portion_count; ++j) { |
|
3932 SetThreadPriority(handles[i + j], THREAD_PRIORITY_ABOVE_NORMAL); |
|
3933 } |
|
3934 timeout_left = (finish_time - start_time) / 1000000L; |
|
3935 if (timeout_left < 0) { |
|
3936 timeout_left = 0; |
|
3937 } |
|
3938 res = WaitForMultipleObjects(portion_count, handles + i, TRUE, timeout_left); |
3922 if (res == WAIT_FAILED || res == WAIT_TIMEOUT) { |
3939 if (res == WAIT_FAILED || res == WAIT_TIMEOUT) { |
3923 warning("WaitForMultipleObjects %s (%u) in %s: %d\n", |
3940 warning("WaitForMultipleObjects %s (%u) in %s: %d\n", |
3924 (res == WAIT_FAILED ? "failed" : "timed out"), |
3941 (res == WAIT_FAILED ? "failed" : "timed out"), |
3925 GetLastError(), __FILE__, __LINE__); |
3942 GetLastError(), __FILE__, __LINE__); |
|
3943 // Reset portion_count so we close the remaining |
|
3944 // handles due to this error. |
|
3945 portion_count = handle_count - i; |
3926 } |
3946 } |
3927 for (i = 0; i < handle_count; ++i) { |
3947 for (j = 0; j < portion_count; ++j) { |
3928 CloseHandle(handles[i]); |
3948 CloseHandle(handles[i + j]); |
3929 } |
3949 } |
3930 handle_count = 0; |
3950 if ((i += portion_count) >= handle_count) { |
|
3951 break; |
|
3952 } |
|
3953 start_time = os::javaTimeNanos(); |
3931 } |
3954 } |
3932 |
3955 handle_count = 0; |
3933 OrderAccess::release_store(&process_exiting, 1); |
|
3934 } |
3956 } |
3935 |
3957 |
3936 LeaveCriticalSection(&crit_sect); |
3958 LeaveCriticalSection(&crit_sect); |
3937 } |
3959 } |
3938 |
3960 |
3939 if (what == EPT_THREAD) { |
3961 if (OrderAccess::load_acquire(&process_exiting) != 0 && |
3940 while (OrderAccess::load_acquire(&process_exiting) != 0) { |
3962 process_exiting != (jint)GetCurrentThreadId()) { |
3941 // Some other thread is about to call exit(), so we |
3963 // Some other thread is about to call exit(), so we |
3942 // don't let the current thread proceed to _endthreadex() |
3964 // don't let the current thread proceed to exit() or _endthreadex() |
|
3965 while (true) { |
3943 SuspendThread(GetCurrentThread()); |
3966 SuspendThread(GetCurrentThread()); |
3944 // Avoid busy-wait loop, if SuspendThread() failed. |
3967 // Avoid busy-wait loop, if SuspendThread() failed. |
3945 Sleep(EXIT_TIMEOUT); |
3968 Sleep(EXIT_TIMEOUT); |
3946 } |
3969 } |
3947 } |
3970 } |