408 lines
16 KiB
Diff
408 lines
16 KiB
Diff
From b61cd484f501a1fe7d49c336878a4b8398e727d9 Mon Sep 17 00:00:00 2001
|
|
From: eapen <zhangyipeng7@huawei.com>
|
|
Date: Thu, 15 Dec 2022 14:28:05 +0800
|
|
Subject: [PATCH 20/33] I68TO2: 8219584: Try to dump error file by thread which causes
|
|
safepoint timeout
|
|
---
|
|
hotspot/src/os/posix/vm/os_posix.cpp | 31 ++++++-
|
|
hotspot/src/os/windows/vm/os_windows.cpp | 9 ++
|
|
hotspot/src/share/vm/runtime/globals.hpp | 2 +-
|
|
hotspot/src/share/vm/runtime/os.hpp | 4 +
|
|
hotspot/src/share/vm/runtime/safepoint.cpp | 21 +++--
|
|
hotspot/src/share/vm/runtime/vmThread.cpp | 36 +++++---
|
|
hotspot/src/share/vm/runtime/vmThread.hpp | 10 ++-
|
|
hotspot/src/share/vm/utilities/vmError.cpp | 3 +
|
|
.../Safepoint/TestAbortVMOnSafepointTimeout.java | 97 ++++++++++++++++++++++
|
|
9 files changed, 195 insertions(+), 18 deletions(-)
|
|
create mode 100644 hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java
|
|
|
|
diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp
|
|
index e7f1fdd..d2663bd 100644
|
|
--- a/hotspot/src/os/posix/vm/os_posix.cpp
|
|
+++ b/hotspot/src/os/posix/vm/os_posix.cpp
|
|
@@ -26,6 +26,7 @@
|
|
#include "prims/jvm.h"
|
|
#include "runtime/frame.inline.hpp"
|
|
#include "runtime/os.hpp"
|
|
+#include "utilities/events.hpp"
|
|
#include "utilities/vmError.hpp"
|
|
|
|
#include <signal.h>
|
|
@@ -814,6 +815,15 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t
|
|
return true;
|
|
}
|
|
|
|
+bool os::signal_sent_by_kill(const void* siginfo) {
|
|
+ const siginfo_t* const si = (const siginfo_t*)siginfo;
|
|
+ return si->si_code == SI_USER || si->si_code == SI_QUEUE
|
|
+#ifdef SI_TKILL
|
|
+ || si->si_code == SI_TKILL
|
|
+#endif
|
|
+ ;
|
|
+}
|
|
+
|
|
// A POSIX conform, platform-independend siginfo print routine.
|
|
// Short print out on one line.
|
|
void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) {
|
|
@@ -844,7 +854,7 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) {
|
|
const int me = (int) ::getpid();
|
|
const int pid = (int) si->si_pid;
|
|
|
|
- if (si->si_code == SI_USER || si->si_code == SI_QUEUE) {
|
|
+ if (signal_sent_by_kill(si)) {
|
|
if (IS_VALID_PID(pid) && pid != me) {
|
|
os->print(", sent from pid: %d (uid: %d)", pid, (int) si->si_uid);
|
|
}
|
|
@@ -860,6 +870,25 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) {
|
|
}
|
|
}
|
|
|
|
+bool os::signal_thread(Thread* thread, int sig, const char* reason) {
|
|
+ OSThread* osthread = thread->osthread();
|
|
+ if (osthread) {
|
|
+#if defined (SOLARIS)
|
|
+ // Note: we cannot use pthread_kill on Solaris - not because
|
|
+ // its missing, but because we do not have the pthread_t id.
|
|
+ int status = thr_kill(osthread->thread_id(), sig);
|
|
+#else
|
|
+ int status = pthread_kill(osthread->pthread_id(), sig);
|
|
+#endif
|
|
+ if (status == 0) {
|
|
+ Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.",
|
|
+ sig, p2i(thread), reason);
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
bool os::Posix::is_root(uid_t uid){
|
|
return ROOT_UID == uid;
|
|
}
|
|
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
|
|
index cc31126..cf1036c 100644
|
|
--- a/hotspot/src/os/windows/vm/os_windows.cpp
|
|
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
|
|
@@ -1877,6 +1877,11 @@ void os::print_memory_info(outputStream* st) {
|
|
st->cr();
|
|
}
|
|
|
|
+bool os::signal_sent_by_kill(const void* siginfo) {
|
|
+ // TODO: Is this possible?
|
|
+ return false;
|
|
+}
|
|
+
|
|
void os::print_siginfo(outputStream *st, void *siginfo) {
|
|
EXCEPTION_RECORD* er = (EXCEPTION_RECORD*)siginfo;
|
|
st->print("siginfo:");
|
|
@@ -1911,6 +1916,10 @@ void os::print_siginfo(outputStream *st, void *siginfo) {
|
|
st->cr();
|
|
}
|
|
|
|
+bool os::signal_thread(Thread* thread, int sig, const char* reason) {
|
|
+ // TODO: Can we kill thread?
|
|
+ return false;
|
|
+}
|
|
|
|
int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) {
|
|
#if _MSC_VER >= 1900
|
|
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
|
|
index 10e4e7f..64d40e0 100644
|
|
--- a/hotspot/src/share/vm/runtime/globals.hpp
|
|
+++ b/hotspot/src/share/vm/runtime/globals.hpp
|
|
@@ -650,7 +650,7 @@ class CommandLineFlags {
|
|
"Print out every time compilation is longer than " \
|
|
"a given threshold") \
|
|
\
|
|
- develop(bool, SafepointALot, false, \
|
|
+ diagnostic(bool, SafepointALot, false, \
|
|
"Generate a lot of safepoints. This works with " \
|
|
"GuaranteedSafepointInterval") \
|
|
\
|
|
diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp
|
|
index 5f41e96..092459c 100644
|
|
--- a/hotspot/src/share/vm/runtime/os.hpp
|
|
+++ b/hotspot/src/share/vm/runtime/os.hpp
|
|
@@ -492,6 +492,9 @@ class os: AllStatic {
|
|
static void pd_start_thread(Thread* thread);
|
|
static void start_thread(Thread* thread);
|
|
|
|
+ // Returns true if successful.
|
|
+ static bool signal_thread(Thread* thread, int sig, const char* reason);
|
|
+
|
|
static void initialize_thread(Thread* thr);
|
|
static void free_thread(OSThread* osthread);
|
|
|
|
@@ -653,6 +656,7 @@ class os: AllStatic {
|
|
static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len);
|
|
static void print_context(outputStream* st, void* context);
|
|
static void print_register_info(outputStream* st, void* context);
|
|
+ static bool signal_sent_by_kill(const void* siginfo);
|
|
static void print_siginfo(outputStream* st, void* siginfo);
|
|
static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
|
|
static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
|
|
diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp
|
|
index 440617c..8408bed 100644
|
|
--- a/hotspot/src/share/vm/runtime/safepoint.cpp
|
|
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp
|
|
@@ -476,8 +476,7 @@ void SafepointSynchronize::begin() {
|
|
GC_locker::set_jni_lock_count(_current_jni_active_count);
|
|
|
|
if (TraceSafepoint) {
|
|
- VM_Operation *op = VMThread::vm_operation();
|
|
- tty->print_cr("Entering safepoint region: %s", (op != NULL) ? op->name() : "no vm operation");
|
|
+ tty->print_cr("Entering safepoint region: %s", VMThread::vm_safepoint_description());
|
|
}
|
|
|
|
RuntimeService::record_safepoint_synchronized();
|
|
@@ -929,11 +928,23 @@ void SafepointSynchronize::print_safepoint_timeout(SafepointTimeoutReason reason
|
|
// To debug the long safepoint, specify both AbortVMOnSafepointTimeout &
|
|
// ShowMessageBoxOnError.
|
|
if (AbortVMOnSafepointTimeout) {
|
|
+ // Send the blocking thread a signal to terminate and write an error file.
|
|
+ for (JavaThread *cur_thread = Threads::first(); cur_thread;
|
|
+ cur_thread = cur_thread->next()) {
|
|
+ ThreadSafepointState *cur_state = cur_thread->safepoint_state();
|
|
+ if (cur_thread->thread_state() != _thread_blocked &&
|
|
+ ((reason == _spinning_timeout && cur_state->is_running()) ||
|
|
+ (reason == _blocking_timeout && !cur_state->has_called_back()))) {
|
|
+ if (!os::signal_thread(cur_thread, SIGILL, "blocking a safepoint")) {
|
|
+ break; // Could not send signal. Report fatal error.
|
|
+ }
|
|
+ // Give cur_thread a chance to report the error and terminate the VM.
|
|
+ os::sleep(Thread::current(), 3000, false);
|
|
+ }
|
|
+ }
|
|
char msg[1024];
|
|
- VM_Operation *op = VMThread::vm_operation();
|
|
sprintf(msg, "Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.",
|
|
- SafepointTimeoutDelay,
|
|
- op != NULL ? op->name() : "no vm operation");
|
|
+ SafepointTimeoutDelay, VMThread::vm_safepoint_description());
|
|
fatal(msg);
|
|
}
|
|
}
|
|
diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp
|
|
index b27c287..4f1695e 100644
|
|
--- a/hotspot/src/share/vm/runtime/vmThread.cpp
|
|
+++ b/hotspot/src/share/vm/runtime/vmThread.cpp
|
|
@@ -217,6 +217,7 @@ VMThread* VMThread::_vm_thread = NULL;
|
|
VM_Operation* VMThread::_cur_vm_operation = NULL;
|
|
VMOperationQueue* VMThread::_vm_queue = NULL;
|
|
PerfCounter* VMThread::_perf_accumulated_vm_operation_time = NULL;
|
|
+const char* VMThread::_no_op_reason = NULL;
|
|
|
|
|
|
void VMThread::create() {
|
|
@@ -290,6 +291,7 @@ void VMThread::run() {
|
|
}
|
|
|
|
// 4526887 let VM thread exit at Safepoint
|
|
+ _no_op_reason = "Halt";
|
|
SafepointSynchronize::begin();
|
|
|
|
if (VerifyBeforeExit) {
|
|
@@ -422,6 +424,25 @@ void VMThread::evaluate_operation(VM_Operation* op) {
|
|
}
|
|
}
|
|
|
|
+bool VMThread::no_op_safepoint_needed(bool check_time) {
|
|
+ if (SafepointALot) {
|
|
+ _no_op_reason = "SafepointALot";
|
|
+ return true;
|
|
+ }
|
|
+ if (!SafepointSynchronize::is_cleanup_needed()) {
|
|
+ return false;
|
|
+ }
|
|
+ if (check_time) {
|
|
+ long interval = SafepointSynchronize::last_non_safepoint_interval();
|
|
+ bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
|
|
+ (interval > GuaranteedSafepointInterval);
|
|
+ if (!max_time_exceeded) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ _no_op_reason = "Cleanup";
|
|
+ return true;
|
|
+}
|
|
|
|
void VMThread::loop() {
|
|
assert(_cur_vm_operation == NULL, "no current one should be executing");
|
|
@@ -460,8 +481,7 @@ void VMThread::loop() {
|
|
exit(-1);
|
|
}
|
|
|
|
- if (timedout && (SafepointALot ||
|
|
- SafepointSynchronize::is_cleanup_needed())) {
|
|
+ if (timedout && VMThread::no_op_safepoint_needed(false)) {
|
|
MutexUnlockerEx mul(VMOperationQueue_lock,
|
|
Mutex::_no_safepoint_check_flag);
|
|
// Force a safepoint since we have not had one for at least
|
|
@@ -585,14 +605,10 @@ void VMThread::loop() {
|
|
//
|
|
// We want to make sure that we get to a safepoint regularly.
|
|
//
|
|
- if (SafepointALot || SafepointSynchronize::is_cleanup_needed()) {
|
|
- long interval = SafepointSynchronize::last_non_safepoint_interval();
|
|
- bool max_time_exceeded = GuaranteedSafepointInterval != 0 && (interval > GuaranteedSafepointInterval);
|
|
- if (SafepointALot || max_time_exceeded) {
|
|
- HandleMark hm(VMThread::vm_thread());
|
|
- SafepointSynchronize::begin();
|
|
- SafepointSynchronize::end();
|
|
- }
|
|
+ if (VMThread::no_op_safepoint_needed(true)) {
|
|
+ HandleMark hm(VMThread::vm_thread());
|
|
+ SafepointSynchronize::begin();
|
|
+ SafepointSynchronize::end();
|
|
}
|
|
}
|
|
}
|
|
diff --git a/hotspot/src/share/vm/runtime/vmThread.hpp b/hotspot/src/share/vm/runtime/vmThread.hpp
|
|
index a6d1ad3..d8af0d9 100644
|
|
--- a/hotspot/src/share/vm/runtime/vmThread.hpp
|
|
+++ b/hotspot/src/share/vm/runtime/vmThread.hpp
|
|
@@ -100,7 +100,12 @@ class VMThread: public NamedThread {
|
|
static Monitor * _terminate_lock;
|
|
static PerfCounter* _perf_accumulated_vm_operation_time;
|
|
|
|
+ static const char* _no_op_reason;
|
|
+
|
|
+ static bool no_op_safepoint_needed(bool check_time);
|
|
+
|
|
void evaluate_operation(VM_Operation* op);
|
|
+
|
|
public:
|
|
// Constructor
|
|
VMThread();
|
|
@@ -123,7 +128,10 @@ class VMThread: public NamedThread {
|
|
static void execute(VM_Operation* op);
|
|
|
|
// Returns the current vm operation if any.
|
|
- static VM_Operation* vm_operation() { return _cur_vm_operation; }
|
|
+ static VM_Operation* vm_operation() { return _cur_vm_operation; }
|
|
+
|
|
+ // Returns the current vm operation name or set reason
|
|
+ static const char* vm_safepoint_description() { return _cur_vm_operation != NULL ? _cur_vm_operation->name() : _no_op_reason; };
|
|
|
|
// Returns the single instance of VMThread.
|
|
static VMThread* vm_thread() { return _vm_thread; }
|
|
diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp
|
|
index 9b40a34..261591d 100644
|
|
--- a/hotspot/src/share/vm/utilities/vmError.cpp
|
|
+++ b/hotspot/src/share/vm/utilities/vmError.cpp
|
|
@@ -460,6 +460,9 @@ void VMError::report(outputStream* st) {
|
|
st->print("%s", buf);
|
|
st->print(" (0x%x)", _id); // signal number
|
|
st->print(" at pc=" PTR_FORMAT, _pc);
|
|
+ if (_siginfo != NULL && os::signal_sent_by_kill(_siginfo)) {
|
|
+ st->print(" (sent by kill)");
|
|
+ }
|
|
} else {
|
|
if (should_report_bug(_id)) {
|
|
st->print("Internal Error");
|
|
diff --git a/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java b/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java
|
|
new file mode 100644
|
|
index 0000000..a097bdc
|
|
--- /dev/null
|
|
+++ b/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java
|
|
@@ -0,0 +1,97 @@
|
|
+/*
|
|
+ * Copyright (c) 2019, SAP SE. All rights reserved.
|
|
+ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved.
|
|
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
+ *
|
|
+ * This code is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 only, as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
+ * version 2 for more details (a copy is included in the LICENSE file that
|
|
+ * accompanied this code).
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License version
|
|
+ * 2 along with this work; if not, write to the Free Software Foundation,
|
|
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ *
|
|
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
+ * or visit www.oracle.com if you need additional information or have any
|
|
+ * questions.
|
|
+ */
|
|
+
|
|
+import com.oracle.java.testlibrary.*;
|
|
+
|
|
+/*
|
|
+ * @test TestAbortVMOnSafepointTimeout
|
|
+ * @summary Check if VM can kill thread which doesn't reach safepoint.
|
|
+ * @bug 8219584 8227528
|
|
+ * @library /testlibrary
|
|
+ *
|
|
+ */
|
|
+
|
|
+public class TestAbortVMOnSafepointTimeout {
|
|
+
|
|
+ public static void main(String[] args) throws Exception {
|
|
+ if (args.length > 0) {
|
|
+ int result = test_loop(3);
|
|
+ System.out.println("This message would occur after some time with result " + result);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ testWith(500, 500);
|
|
+ }
|
|
+
|
|
+ static int test_loop(int x) {
|
|
+ int sum = 0;
|
|
+ if (x != 0) {
|
|
+ // Long running loop without safepoint.
|
|
+ for (int y = 1; y < Integer.MAX_VALUE; ++y) {
|
|
+ if (y % x == 0) ++sum;
|
|
+ }
|
|
+ }
|
|
+ return sum;
|
|
+ }
|
|
+
|
|
+ public static void testWith(int sfpt_interval, int timeout_delay) throws Exception {
|
|
+ // -XX:-UseCountedLoopSafepoints - is used to prevent the loop
|
|
+ // in test_loop() to poll for safepoints.
|
|
+ // -XX:LoopStripMiningIter=0 and -XX:LoopUnrollLimit=0 - are
|
|
+ // used to prevent optimizations over the loop in test_loop()
|
|
+ // since we actually want it to provoke a safepoint timeout.
|
|
+ // -XX:-UseBiasedLocking - is used to prevent biased locking
|
|
+ // handshakes from changing the timing of this test.
|
|
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
|
+ "-XX:+UnlockDiagnosticVMOptions",
|
|
+ "-XX:-UseBiasedLocking",
|
|
+ "-XX:+SafepointTimeout",
|
|
+ "-XX:+SafepointALot",
|
|
+ "-XX:+AbortVMOnSafepointTimeout",
|
|
+ "-XX:SafepointTimeoutDelay=" + timeout_delay,
|
|
+ "-XX:GuaranteedSafepointInterval=" + sfpt_interval,
|
|
+ "-XX:-TieredCompilation",
|
|
+ "-XX:-UseCountedLoopSafepoints",
|
|
+ "-XX:LoopUnrollLimit=0",
|
|
+ "-XX:CompileCommand=compileonly,TestAbortVMOnSafepointTimeout::test_loop",
|
|
+ "-Xcomp",
|
|
+ "-XX:-CreateMinidumpOnCrash",
|
|
+ "-Xms64m",
|
|
+ "TestAbortVMOnSafepointTimeout",
|
|
+ "runTestLoop"
|
|
+ );
|
|
+
|
|
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
|
+ if (Platform.isWindows()) {
|
|
+ output.shouldMatch("Safepoint sync time longer than");
|
|
+ } else {
|
|
+ output.shouldMatch("SIGILL");
|
|
+ if (Platform.isLinux()) {
|
|
+ output.shouldMatch("(sent by kill)");
|
|
+ }
|
|
+ output.shouldMatch("TestAbortVMOnSafepointTimeout.test_loop");
|
|
+ }
|
|
+ output.shouldNotHaveExitValue(0);
|
|
+ }
|
|
+}
|
|
--
|
|
1.8.3.1
|