blob: ed44ba033d9ce00759acbf3b5a9eab71eb5609d9 [file] [log] [blame]
/*
* Copyright (c) 2012, 2018, 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
* 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.
*
*/
#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
#include "jfr/utilities/jfrTypes.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.hpp"
#include "runtime/globals.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.hpp"
/*
* We are just about to exit the VM, so we will be very aggressive
* at this point in order to increase overall success of dumping jfr data:
*
* 1. if the thread state is not "_thread_in_vm", we will quick transition
* it to "_thread_in_vm".
* 2. the nesting state for both resource and handle areas are unknown,
* so we allocate new fresh arenas, discarding the old ones.
* 3. if the thread is the owner of some critical lock(s), unlock them.
*
* If we end up deadlocking in the attempt of dumping out jfr data,
* we rely on the WatcherThread task "is_error_reported()",
* to exit the VM after a hard-coded timeout.
* This "safety net" somewhat explains the aggressiveness in this attempt.
*
*/
static void prepare_for_emergency_dump(Thread* thread) {
if (thread->is_Java_thread()) {
((JavaThread*)thread)->set_thread_state(_thread_in_vm);
}
#ifdef ASSERT
Monitor* owned_lock = thread->owned_locks();
while (owned_lock != NULL) {
Monitor* next = owned_lock->next();
owned_lock->unlock();
owned_lock = next;
}
#endif // ASSERT
if (Threads_lock->owned_by_self()) {
Threads_lock->unlock();
}
if (Module_lock->owned_by_self()) {
Module_lock->unlock();
}
if (Heap_lock->owned_by_self()) {
Heap_lock->unlock();
}
if (Safepoint_lock->owned_by_self()) {
Safepoint_lock->unlock();
}
if (VMOperationQueue_lock->owned_by_self()) {
VMOperationQueue_lock->unlock();
}
if (VMOperationRequest_lock->owned_by_self()) {
VMOperationRequest_lock->unlock();
}
if (Service_lock->owned_by_self()) {
Service_lock->unlock();
}
if (CodeCache_lock->owned_by_self()) {
CodeCache_lock->unlock();
}
if (PeriodicTask_lock->owned_by_self()) {
PeriodicTask_lock->unlock();
}
if (JfrMsg_lock->owned_by_self()) {
JfrMsg_lock->unlock();
}
if (JfrBuffer_lock->owned_by_self()) {
JfrBuffer_lock->unlock();
}
if (JfrStream_lock->owned_by_self()) {
JfrStream_lock->unlock();
}
if (JfrStacktrace_lock->owned_by_self()) {
JfrStacktrace_lock->unlock();
}
}
static volatile int jfr_shutdown_lock = 0;
static bool guard_reentrancy() {
return Atomic::cmpxchg(1, &jfr_shutdown_lock, 0) == 0;
}
void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
if (!guard_reentrancy()) {
return;
}
// function made non-reentrant
Thread* thread = Thread::current();
if (exception_handler) {
// we are crashing
if (thread->is_Watcher_thread()) {
// The Watcher thread runs the periodic thread sampling task.
// If it has crashed, it is likely that another thread is
// left in a suspended state. This would mean the system
// will not be able to ever move to a safepoint. We try
// to avoid issuing safepoint operations when attempting
// an emergency dump, but a safepoint might be already pending.
return;
}
prepare_for_emergency_dump(thread);
}
EventDumpReason event;
if (event.should_commit()) {
event.set_reason(exception_handler ? "Crash" : "Out of Memory");
event.set_recordingId(-1);
event.commit();
}
if (!exception_handler) {
// OOM
LeakProfiler::emit_events(max_jlong, false);
}
const int messages = MSGBIT(MSG_VM_ERROR);
ResourceMark rm(thread);
HandleMark hm(thread);
JfrRecorderService service;
service.rotate(messages);
}