diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 7abf5c89945..19025e46265 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -156,7 +156,7 @@ void Jfr::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, } void Jfr::on_vm_error_report(outputStream* st) { - if (JfrRecorder::is_recording()) { + if (JfrRecorder::is_recording() || JfrRecorder::is_recording_stopped_with_error()) { JfrRepository::on_vm_error_report(st); } } diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index f5214ff7942..aafb9b556ab 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -483,6 +483,10 @@ bool JfrRecorder::is_recording() { return JfrRecorderService::is_recording(); } +bool JfrRecorder::is_recording_stopped_with_error() { + return JfrRecorderService::is_recording_stopped_with_error(); +} + void JfrRecorder::stop_recording() { _post_box->post(MSG_STOP); } diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 34cc8fda949..0a080a00fa2 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -70,6 +70,7 @@ class JfrRecorder : public JfrCHeapObj { static void destroy(); static void start_recording(); static bool is_recording(); + static bool is_recording_stopped_with_error(); static void stop_recording(); }; diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index 309ae961808..22ba909a1f6 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -50,6 +50,8 @@ static fio_fd emergency_fd = invalid_fd; static const int64_t chunk_file_header_size = 68; static const size_t chunk_file_extension_length = sizeof chunk_file_jfr_ext - 1; static char _dump_path[JVM_MAXPATHLEN] = { 0 }; +static bool _dump_finished = false; +static char _dumped_file[JVM_MAXPATHLEN] = { 0 }; /* * The emergency dump logic is restrictive when it comes to @@ -99,7 +101,12 @@ static bool open_emergency_dump_fd(const char* path) { } assert(emergency_fd == invalid_fd, "invariant"); emergency_fd = open_exclusivly(path); - return emergency_fd != invalid_fd; + if (emergency_fd != invalid_fd) { + strncpy(_dumped_file, path, JVM_MAXPATHLEN - 1); + return true; + } else { + return false; + } } static void close_emergency_dump_file() { @@ -150,7 +157,7 @@ static void report(outputStream* st, bool emergency_file_opened, const char* rep assert(st != nullptr, "invariant"); if (emergency_file_opened) { st->print_raw("# JFR recording file will be written. Location: "); - st->print_raw_cr(_path_buffer); + st->print_raw_cr(_dump_finished ? _dumped_file : _path_buffer); st->print_raw_cr("#"); } else if (repository_path != nullptr) { st->print_raw("# The JFR repository may contain useful JFR files. Location: "); @@ -181,7 +188,9 @@ const char* JfrEmergencyDump::get_dump_path() { void JfrEmergencyDump::on_vm_error_report(outputStream* st, const char* repository_path) { assert(st != nullptr, "invariant"); Thread* thread = Thread::current_or_null_safe(); - if (thread != nullptr) { + if (_dump_finished) { + report(st, true, repository_path); + } else if (thread != nullptr) { report(st, open_emergency_dump_file(), repository_path); } else if (repository_path != nullptr) { // a non-attached thread will not be able to write anything later @@ -615,4 +624,5 @@ void JfrEmergencyDump::on_vm_shutdown(bool emit_old_object_samples, bool emit_ev const int messages = MSGBIT(MSG_VM_ERROR); JfrRecorderService service; service.rotate(messages); + _dump_finished = true; } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 3f0b132f1a4..734fc143dc5 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -397,6 +397,7 @@ JfrRecorderService::JfrRecorderService() : enum RecorderState { STOPPED, + STOPPED_WITH_ERROR, RUNNING }; @@ -425,6 +426,10 @@ bool JfrRecorderService::is_recording() { return recorder_state == RUNNING; } +bool JfrRecorderService::is_recording_stopped_with_error() { + return recorder_state == STOPPED_WITH_ERROR; +} + void JfrRecorderService::start() { JfrRotationLock lock; assert(!is_recording(), "invariant"); @@ -509,6 +514,7 @@ void JfrRecorderService::rotate(int msgs) { if (msgs & MSGBIT(MSG_VM_ERROR)) { stop(); vm_error_rotation(); + set_recorder_state(STOPPED, STOPPED_WITH_ERROR); return; } if (_storage.control().to_disk()) { diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp index e5b4500afc0..20a63921b3e 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. 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 @@ -74,6 +74,7 @@ class JfrRecorderService : public StackObj { void evaluate_chunk_size_for_rotation(); void emit_leakprofiler_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs); static bool is_recording(); + static bool is_recording_stopped_with_error(); }; #endif // SHARE_JFR_RECORDER_SERVICE_JFRRECORDERSERVICE_HPP diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index a290602e0be..183450e4736 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1745,6 +1745,10 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt os::check_core_dump_prerequisites(buffer, sizeof(buffer)); + // Jfr::on_vm_shutdown should be called before installing crash handler for error reporting + // because LeakProfiler::emit_events() would kick both VM Operation and long-running execution. + JFR_ONLY(Jfr::on_vm_shutdown(static_cast(_id) == OOM_JAVA_HEAP_FATAL, true);) + // reset signal handlers or exception filter; make sure recursive crashes // are handled properly. install_secondary_signal_handler(); @@ -1898,8 +1902,6 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt log.set_fd(-1); } - JFR_ONLY(Jfr::on_vm_shutdown(static_cast(_id) == OOM_JAVA_HEAP_FATAL, true);) - if (PrintNMTStatistics) { fdStream fds(fd_out); MemTracker::final_report(&fds);