--- /dev/null 2017-11-09 09:38:01.297999907 +0100 +++ new/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp 2018-04-09 15:09:59.224877136 +0200 @@ -0,0 +1,164 @@ +/* + * 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/leakprofiler/leakProfiler.hpp" +#include "jfr/recorder/repository/jfrEmergencyDump.hpp" +#include "jfr/recorder/service/jfrPostBox.hpp" +#include "jfr/recorder/service/jfrRecorderService.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" +#include "trace/traceBackend.hpp" +#include "tracefiles/traceEventClasses.hpp" +#include "tracefiles/traceTypes.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); +}