From 120367d947c297709134167d3e4d8e1b91fe97f3 Mon Sep 17 00:00:00 2001
From: z30010524 <zhangyunbo7@huawei.com>
Date: Tue, 14 Mar 2023 19:17:50 +0800
Subject: [PATCH 10/15] 8057743: (process) Synchronize exiting of threads and
 process [win]

DTS/AR: DTS2023031516597
Summary: <JDK> :8057744: (process) Synchronize exiting of threads and process [win]
LLT: NA
Patch Type: backport
Bug url: https://bugs.openjdk.org/browse/JDK-8057744
---
 hotspot/src/os/aix/vm/os_aix.inline.hpp       |  5 ++
 hotspot/src/os/bsd/vm/os_bsd.inline.hpp       |  4 +
 hotspot/src/os/linux/vm/os_linux.inline.hpp   |  4 +
 .../src/os/solaris/vm/os_solaris.inline.hpp   |  5 ++
 hotspot/src/os/windows/vm/os_windows.cpp      | 87 +++++++++++++++++--
 hotspot/src/os/windows/vm/os_windows.hpp      | 10 +++
 .../src/os/windows/vm/os_windows.inline.hpp   |  4 +
 hotspot/src/share/vm/runtime/java.cpp         |  2 +-
 hotspot/src/share/vm/runtime/os.hpp           |  4 +-
 9 files changed, 115 insertions(+), 10 deletions(-)

diff --git a/hotspot/src/os/aix/vm/os_aix.inline.hpp b/hotspot/src/os/aix/vm/os_aix.inline.hpp
index 421ea342e..afa034411 100644
--- a/hotspot/src/os/aix/vm/os_aix.inline.hpp
+++ b/hotspot/src/os/aix/vm/os_aix.inline.hpp
@@ -245,4 +245,9 @@ inline int os::set_sock_opt(int fd, int level, int optname,
                             const char* optval, socklen_t optlen) {
   return ::setsockopt(fd, level, optname, optval, optlen);
 }
+
+inline void os::exit(int num) {
+  ::exit(num);
+}
+
 #endif // OS_AIX_VM_OS_AIX_INLINE_HPP
diff --git a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
index c35abf486..1eff6b724 100644
--- a/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
+++ b/hotspot/src/os/bsd/vm/os_bsd.inline.hpp
@@ -247,4 +247,8 @@ inline int os::set_sock_opt(int fd, int level, int optname,
   return ::setsockopt(fd, level, optname, optval, optlen);
 }
 
+inline void os::exit(int num) {
+  ::exit(num);
+}
+
 #endif // OS_BSD_VM_OS_BSD_INLINE_HPP
diff --git a/hotspot/src/os/linux/vm/os_linux.inline.hpp b/hotspot/src/os/linux/vm/os_linux.inline.hpp
index a23bd5631..eb8c8ca1b 100644
--- a/hotspot/src/os/linux/vm/os_linux.inline.hpp
+++ b/hotspot/src/os/linux/vm/os_linux.inline.hpp
@@ -240,4 +240,8 @@ inline int os::set_sock_opt(int fd, int level, int optname,
   return ::setsockopt(fd, level, optname, optval, optlen);
 }
 
+inline void os::exit(int num) {
+  ::exit(num);
+}
+
 #endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
diff --git a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp
index 8e095ab69..aad6debf9 100644
--- a/hotspot/src/os/solaris/vm/os_solaris.inline.hpp
+++ b/hotspot/src/os/solaris/vm/os_solaris.inline.hpp
@@ -223,4 +223,9 @@ inline int os::set_sock_opt(int fd, int level, int optname,
                             const char *optval, socklen_t optlen) {
   return ::setsockopt(fd, level, optname, optval, optlen);
 }
+
+inline void os::exit(int num) {
+  ::exit(num);
+}
+
 #endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
index 11bd14f6f..f0bc733c2 100644
--- a/hotspot/src/os/windows/vm/os_windows.cpp
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
@@ -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"
@@ -432,6 +432,11 @@ static unsigned __stdcall java_start(Thread* thread) {
     }
   }
 
+  // Diagnostic code to investigate JDK-6573254
+  int res = 90115;  // non-java thread
+  if (thread->is_Java_thread()) {
+    res = 60115;    // java thread
+  }
 
   // Install a win32 structured exception handler around every thread created
   // by VM, so VM can genrate error dump when an exception occurred in non-
@@ -450,7 +455,9 @@ static unsigned __stdcall java_start(Thread* thread) {
     Atomic::dec_ptr((intptr_t*)&os::win32::_os_thread_count);
   }
 
-  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) {
@@ -1082,15 +1089,13 @@ void os::abort(bool dump_core, void* siginfo, void* context) {
   win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
 }
 
-
-void os::abort(bool dump_core)
-{
+void os::abort(bool dump_core) {
   abort(dump_core, NULL, NULL);
 }
 
 // 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
@@ -3857,6 +3862,11 @@ bool   os::win32::_is_nt              = false;
 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;
+
 void os::win32::initialize_system_info() {
   SYSTEM_INFO si;
   GetSystemInfo(&si);
@@ -3951,6 +3961,69 @@ HINSTANCE os::win32::load_Windows_dll(const char* name, char *ebuf, int ebuflen)
   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);
diff --git a/hotspot/src/os/windows/vm/os_windows.hpp b/hotspot/src/os/windows/vm/os_windows.hpp
index 20e2ca2f5..3fdc9bcd6 100644
--- a/hotspot/src/os/windows/vm/os_windows.hpp
+++ b/hotspot/src/os/windows/vm/os_windows.hpp
@@ -31,6 +31,7 @@ static bool zero_page_read_protected() { return true; }
 
 class win32 {
   friend class os;
+  friend unsigned __stdcall java_start(class Thread*);
 
  protected:
   static int    _vm_page_size;
@@ -42,6 +43,7 @@ class win32 {
   static bool   _is_nt;
   static bool   _is_windows_2003;
   static bool   _is_windows_server;
+  static bool   _has_exit_bug;
 
   static void print_windows_version(outputStream* st);
 
@@ -63,6 +65,11 @@ class win32 {
   // load dll from Windows system directory or Windows directory
   static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
 
+ 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);
+
  public:
   // Generic interface:
 
@@ -79,6 +86,9 @@ class win32 {
   // 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; }
 
diff --git a/hotspot/src/os/windows/vm/os_windows.inline.hpp b/hotspot/src/os/windows/vm/os_windows.inline.hpp
index 5dac11c90..83c51935d 100644
--- a/hotspot/src/os/windows/vm/os_windows.inline.hpp
+++ b/hotspot/src/os/windows/vm/os_windows.inline.hpp
@@ -96,4 +96,8 @@ inline int os::close(int fd) {
   return ::close(fd);
 }
 
+inline void os::exit(int num) {
+  win32::exit_process_or_thread(win32::EPT_PROCESS, num);
+}
+
 #endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP
diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp
index 5b82a7a36..c72a5a766 100644
--- a/hotspot/src/share/vm/runtime/java.cpp
+++ b/hotspot/src/share/vm/runtime/java.cpp
@@ -625,7 +625,7 @@ void notify_vm_shutdown() {
 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() {
diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp
index e696321ab..6ca220021 100644
--- a/hotspot/src/share/vm/runtime/os.hpp
+++ b/hotspot/src/share/vm/runtime/os.hpp
@@ -545,8 +545,8 @@ class os: AllStatic {
   // run cmd in a separate process and return its exit code; or -1 on failures
   static int fork_and_exec(char *cmd, bool use_vfork_if_available = false);
 
-  // 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();
-- 
2.19.0

