mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8057744: (process) Synchronize exiting of threads and process [win]
Reviewed-by: dholmes, dcubed, sla
This commit is contained in:
parent
3ad47cdbeb
commit
497f5c44a6
9 changed files with 112 additions and 30 deletions
|
@ -269,4 +269,8 @@ inline bool os::supports_monotonic_clock() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void os::exit(int num) {
|
||||||
|
::exit(num);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // OS_AIX_VM_OS_AIX_INLINE_HPP
|
#endif // OS_AIX_VM_OS_AIX_INLINE_HPP
|
||||||
|
|
|
@ -274,4 +274,8 @@ inline bool os::supports_monotonic_clock() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void os::exit(int num) {
|
||||||
|
::exit(num);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // OS_BSD_VM_OS_BSD_INLINE_HPP
|
#endif // OS_BSD_VM_OS_BSD_INLINE_HPP
|
||||||
|
|
|
@ -263,4 +263,8 @@ inline bool os::supports_monotonic_clock() {
|
||||||
return Linux::_clock_gettime != NULL;
|
return Linux::_clock_gettime != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void os::exit(int num) {
|
||||||
|
::exit(num);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
|
#endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
|
||||||
|
|
|
@ -157,4 +157,8 @@ inline bool os::supports_monotonic_clock() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void os::exit(int num) {
|
||||||
|
::exit(num);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
|
#endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Must be at least Windows 2000 or XP to use IsDebuggerPresent
|
// Must be at least Windows Vista or Server 2008 to use InitOnceExecuteOnce
|
||||||
#define _WIN32_WINNT 0x500
|
#define _WIN32_WINNT 0x0600
|
||||||
|
|
||||||
// no precompiled headers
|
// no precompiled headers
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
|
@ -409,8 +409,6 @@ struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
|
||||||
|
|
||||||
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
|
LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo);
|
||||||
|
|
||||||
extern jint volatile vm_getting_terminated;
|
|
||||||
|
|
||||||
// Thread start routine for all new Java threads
|
// Thread start routine for all new Java threads
|
||||||
static unsigned __stdcall java_start(Thread* thread) {
|
static unsigned __stdcall java_start(Thread* thread) {
|
||||||
// Try to randomize the cache line index of hot stack frames.
|
// Try to randomize the cache line index of hot stack frames.
|
||||||
|
@ -432,13 +430,10 @@ static unsigned __stdcall java_start(Thread* thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostic code to investigate JDK-6573254 (Part I)
|
// Diagnostic code to investigate JDK-6573254
|
||||||
unsigned res = 90115; // non-java thread
|
int res = 90115; // non-java thread
|
||||||
if (thread->is_Java_thread()) {
|
if (thread->is_Java_thread()) {
|
||||||
JavaThread* java_thread = (JavaThread*)thread;
|
res = 60115; // java thread
|
||||||
res = java_lang_Thread::is_daemon(java_thread->threadObj())
|
|
||||||
? 70115 // java daemon thread
|
|
||||||
: 80115; // java non-daemon thread
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Install a win32 structured exception handler around every thread created
|
// Install a win32 structured exception handler around every thread created
|
||||||
|
@ -458,12 +453,9 @@ static unsigned __stdcall java_start(Thread* thread) {
|
||||||
Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count);
|
Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diagnostic code to investigate JDK-6573254 (Part II)
|
// Thread must not return from exit_process_or_thread(), but if it does,
|
||||||
if (OrderAccess::load_acquire(&vm_getting_terminated)) {
|
// let it proceed to exit normally
|
||||||
return res;
|
return (unsigned)os::win32::exit_process_or_thread(os::win32::EPT_THREAD, res);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) {
|
static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, int thread_id) {
|
||||||
|
@ -1062,17 +1054,15 @@ void os::check_or_create_dump(void* exceptionRecord, void* contextRecord, char*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void os::abort(bool dump_core) {
|
||||||
void os::abort(bool dump_core)
|
|
||||||
{
|
|
||||||
os::shutdown();
|
os::shutdown();
|
||||||
// no core dump on Windows
|
// 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.
|
// Die immediately, no exit hook, no abort hook, no cleanup.
|
||||||
void os::die() {
|
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
|
// Directory routines copied from src/win32/native/java/io/dirent_md.c
|
||||||
|
@ -3632,6 +3622,10 @@ bool os::win32::_is_nt = false;
|
||||||
bool os::win32::_is_windows_2003 = false;
|
bool os::win32::_is_windows_2003 = false;
|
||||||
bool os::win32::_is_windows_server = 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;
|
bool os::win32::_has_performance_count = 0;
|
||||||
|
|
||||||
void os::win32::initialize_system_info() {
|
void os::win32::initialize_system_info() {
|
||||||
|
@ -3728,6 +3722,69 @@ HINSTANCE os::win32::load_Windows_dll(const char* name, char *ebuf, int ebuflen)
|
||||||
return NULL;
|
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() {
|
void os::win32::setmode_streams() {
|
||||||
_setmode(_fileno(stdin), _O_BINARY);
|
_setmode(_fileno(stdin), _O_BINARY);
|
||||||
_setmode(_fileno(stdout), _O_BINARY);
|
_setmode(_fileno(stdout), _O_BINARY);
|
||||||
|
|
|
@ -36,6 +36,7 @@ static const char* path_separator() { return ";"; }
|
||||||
|
|
||||||
class win32 {
|
class win32 {
|
||||||
friend class os;
|
friend class os;
|
||||||
|
friend unsigned __stdcall java_start(class Thread*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static int _vm_page_size;
|
static int _vm_page_size;
|
||||||
|
@ -47,6 +48,7 @@ class win32 {
|
||||||
static bool _is_nt;
|
static bool _is_nt;
|
||||||
static bool _is_windows_2003;
|
static bool _is_windows_2003;
|
||||||
static bool _is_windows_server;
|
static bool _is_windows_server;
|
||||||
|
static bool _has_exit_bug;
|
||||||
static bool _has_performance_count;
|
static bool _has_performance_count;
|
||||||
|
|
||||||
static void print_windows_version(outputStream* st);
|
static void print_windows_version(outputStream* st);
|
||||||
|
@ -69,8 +71,12 @@ class win32 {
|
||||||
// load dll from Windows system directory or Windows directory
|
// load dll from Windows system directory or Windows directory
|
||||||
static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
|
static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void initialize_performance_counter();
|
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:
|
public:
|
||||||
// Generic interface:
|
// Generic interface:
|
||||||
|
@ -88,6 +94,9 @@ class win32 {
|
||||||
// Tells whether the platform is Windows 2003
|
// Tells whether the platform is Windows 2003
|
||||||
static bool is_windows_2003() { return _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
|
// Returns the byte size of a virtual memory page
|
||||||
static int vm_page_size() { return _vm_page_size; }
|
static int vm_page_size() { return _vm_page_size; }
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,10 @@ inline bool os::supports_monotonic_clock() {
|
||||||
return win32::_has_performance_count;
|
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) \
|
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \
|
||||||
os::win32::call_test_func_with_wrapper(f)
|
os::win32::call_test_func_with_wrapper(f)
|
||||||
|
|
||||||
|
|
|
@ -430,8 +430,6 @@ extern "C" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jint volatile vm_getting_terminated = 0;
|
|
||||||
|
|
||||||
// Note: before_exit() can be executed only once, if more than one threads
|
// 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
|
// are trying to shutdown the VM at the same time, only one thread
|
||||||
// can run before_exit() and all other threads must wait.
|
// can run before_exit() and all other threads must wait.
|
||||||
|
@ -462,8 +460,6 @@ void before_exit(JavaThread * thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OrderAccess::release_store(&vm_getting_terminated, 1);
|
|
||||||
|
|
||||||
// The only difference between this and Win32's _onexit procs is that
|
// The only difference between this and Win32's _onexit procs is that
|
||||||
// this version is invoked before any threads get killed.
|
// this version is invoked before any threads get killed.
|
||||||
ExitProc* current = exit_procs;
|
ExitProc* current = exit_procs;
|
||||||
|
@ -587,7 +583,7 @@ void notify_vm_shutdown() {
|
||||||
void vm_direct_exit(int code) {
|
void vm_direct_exit(int code) {
|
||||||
notify_vm_shutdown();
|
notify_vm_shutdown();
|
||||||
os::wait_for_keypress_at_exit();
|
os::wait_for_keypress_at_exit();
|
||||||
::exit(code);
|
os::exit(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_perform_shutdown_actions() {
|
void vm_perform_shutdown_actions() {
|
||||||
|
|
|
@ -482,8 +482,8 @@ class os: AllStatic {
|
||||||
// run cmd in a separate process and return its exit code; or -1 on failures
|
// run cmd in a separate process and return its exit code; or -1 on failures
|
||||||
static int fork_and_exec(char *cmd);
|
static int fork_and_exec(char *cmd);
|
||||||
|
|
||||||
// os::exit() is merged with vm_exit()
|
// Call ::exit() on all platforms but Windows
|
||||||
// static void exit(int num);
|
static void exit(int num);
|
||||||
|
|
||||||
// Terminate the VM, but don't exit the process
|
// Terminate the VM, but don't exit the process
|
||||||
static void shutdown();
|
static void shutdown();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue