/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 "classfile/systemDictionary.hpp"
#include "memory/allocation.hpp"
#include "memory/heapInspection.hpp"
#include "memory/oopFactory.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/thread.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/threadService.hpp"
// TODO: we need to define a naming convention for perf counters
// to distinguish counters for:
// - standard JSR174 use
// - Hotspot extension (public and committed)
// Default is disabled.
// These counters are for java.lang.management API support.
// They are created even if -XX:-UsePerfData is set and in
// that case, they will be allocated on C heap.
if (os::is_thread_cpu_time_supported()) {
_thread_cpu_time_enabled = true;
}
_thread_allocated_memory_enabled = true; // Always on, so enable it
}
// Acquire the lock to update the peak thread count
// to synchronize with thread addition and removal.
}
// Do not count VM internal or JVMTI agent threads
if (thread->is_hidden_from_external_view() ||
thread->is_jvmti_agent_thread()) {
return;
}
}
if (daemon) {
}
}
if (thread->is_hidden_from_external_view() ||
thread->is_jvmti_agent_thread()) {
return;
}
if (daemon) {
}
}
}
}
// FIXME: JVMTI should call this function
// thread is doing an Object.wait() call
} else {
// thread is trying to enter() or raw_enter() an ObjectMonitor.
}
// If obj == NULL, then ObjectMonitor is raw which doesn't count.
}
return h;
}
return prev;
}
return prev;
}
return prev;
}
// GC support
}
}
if (_threaddump_list == NULL) {
} else {
}
}
bool found = false;
if (d == dump) {
} else {
}
found = true;
break;
}
}
}
// Dump stack trace of threads specified in the given threads array.
// Returns StackTraceElement[][] each element is the stack trace of a thread in
// the corresponding entry in the given threads array
int num_threads,
TRAPS) {
-1, /* entire stack */
false, /* with locked monitors */
false /* with locked synchronizers */);
// Allocate the resulting StackTraceElement[][] object
klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_StackTraceElement_array(), true, CHECK_NH);
int i = 0;
if (stacktrace == NULL) {
// No stack trace
} else {
// Construct an array of java/lang/StackTraceElement object
}
}
return result_obj;
}
stat->reset_count_stat();
}
}
stat->reset_time_stat();
}
}
// Find deadlocks involving object monitors and concurrent locks if concurrent_locks is true
// This code was modified from the original Threads::find_deadlocks code.
bool blocked_on_monitor = false;
int num_deadlocks = 0;
// Initialize the depth-first-number
p->set_depth_first_number(-1);
}
if (jt->depth_first_number() >= 0) {
// this thread was already visited
continue;
}
previousThread = jt;
currentThread = jt;
// When there is a deadlock, all the monitors involved in the dependency
// cycle must be contended and heavyweight. So we only care about the
// heavyweight monitor a thread is waiting to lock.
if (concurrent_locks) {
}
if (waitingToLockMonitor != NULL) {
false /* no locking needed */);
} else {
if (concurrent_locks) {
oop threadObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(waitingToLockBlocker);
} else {
}
}
}
if (currentThread == NULL) {
// No dependency on another thread
break;
}
if (currentThread->depth_first_number() < 0) {
// First visit to this thread
// Thread already visited, and not on a (new) cycle
break;
} else if (currentThread == previousThread) {
// Self-loop, ignore
break;
} else {
// We have a (new) cycle
cycle->set_deadlock(true);
// add this cycle to the deadlocks list
} else {
}
cycle = new DeadlockCycle();
break;
}
if (concurrent_locks) {
}
}
}
delete cycle;
return deadlocks;
}
ThreadDumpResult::ThreadDumpResult() : _num_threads(0), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL) {
// Create a new ThreadDumpResult object and append to the list.
// If GC happens before this function returns, methodOop
// in the stack trace will be visited.
ThreadService::add_thread_dump(this);
}
ThreadDumpResult::ThreadDumpResult(int num_threads) : _num_threads(num_threads), _num_snapshots(0), _snapshots(NULL), _next(NULL), _last(NULL) {
// Create a new ThreadDumpResult object and append to the list.
// If GC happens before this function returns, oops
// will be visited.
ThreadService::add_thread_dump(this);
}
ThreadService::remove_thread_dump(this);
// free all the ThreadSnapshot objects created during
// the VM_ThreadDump operation
ThreadSnapshot* p = ts;
delete p;
}
}
"_num_snapshots must be less than _num_threads");
if (_snapshots == NULL) {
_snapshots = ts;
} else {
}
}
}
}
if (with_lock_info) {
if (length > 0) {
for (int i = 0; i < length; i++) {
}
}
}
}
if (_locked_monitors != NULL) {
for (int i = 0; i < length; i++) {
}
}
}
for (int i = 0; i < len; i++) {
}
}
// Iterate through monitor cache to find JNI locked monitors
private:
public:
_thread = t;
_stack_trace = st;
}
}
}
}
};
_thread = t;
_frames = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<StackFrameInfo*>(INITIAL_ARRAY_SIZE, true);
_depth = 0;
if (_with_locked_monitors) {
_jni_locked_monitors = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(INITIAL_ARRAY_SIZE, true);
} else {
}
}
}
delete _frames;
if (_jni_locked_monitors != NULL) {
delete _jni_locked_monitors;
}
}
if (_thread->has_last_Java_frame()) {
int count = 0;
if (f->is_java_frame()) {
count++;
} else {
// Ignore non-Java frames
}
// Skip frames if more than maxDepth
break;
}
}
}
if (_with_locked_monitors) {
// Iterate inflated monitors and find monitors locked by this thread
// not found in the stack
}
}
bool found = false;
for (int j = 0; j < len; j++) {
found = true;
break;
}
}
}
return found;
}
// Allocate an array of java/lang/StackTraceElement object
for (int j = 0; j < _depth; j++) {
}
return backtrace;
}
_depth++;
}
for (int i = 0; i < length; i++) {
}
for (int j = 0; j < length; j++) {
}
}
if (_retain_map_on_free) {
return;
}
t = t->next();
delete tcl;
}
}
// dump all locked concurrent locks
if (JDK_Version::is_gte_jdk16x_version()) {
// Find all instances of AbstractOwnableSynchronizer
HeapInspection::find_instances_at_safepoint(SystemDictionary::abstract_ownable_synchronizer_klass(),
// Build a map of thread to its owned AQS locks
}
}
// build a map of JavaThread to all its owned AbstractOwnableSynchronizer
for (int i = 0; i < length; i++) {
oop owner_thread_obj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(o);
if (owner_thread_obj != NULL) {
}
}
}
return;
}
// First owned lock found for this thread
} else {
}
}
return tcl;
}
}
return NULL;
}
return;
}
}
}
_owned_locks = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<instanceOop>(INITIAL_ARRAY_SIZE, true);
}
delete _owned_locks;
}
_owned_locks->append(o);
}
for (int i = 0; i < length; i++) {
}
}
_monitor_wait_count = 0;
_sleep_count = 0;
_count_pending_reset = false;
_timer_pending_reset = false;
}
_stack_trace = NULL;
// monitor no longer exists; thread is not blocked
} else {
_blocker_object = obj();
// ownership information of the monitor is not available
// (may no longer be owned or releasing to some other thread)
// make this thread in RUNNABLE state.
// And when the owner thread is in attaching state, the java thread
// is not completely initialized. For example thread name and id
// and may not be set, so hide the attaching thread.
}
}
}
// Support for JSR-166 locks
if (_blocker_object != NULL && _blocker_object->is_a(SystemDictionary::abstract_ownable_synchronizer_klass())) {
_blocker_object_owner = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(_blocker_object);
}
}
}
ThreadSnapshot::~ThreadSnapshot() {
delete _stack_trace;
delete _concurrent_locks;
}
}
f->do_oop(&_threadObj);
f->do_oop(&_blocker_object);
f->do_oop(&_blocker_object_owner);
if (_stack_trace != NULL) {
_stack_trace->oops_do(f);
}
if (_concurrent_locks != NULL) {
_concurrent_locks->oops_do(f);
}
}
_is_deadlock = false;
_threads = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JavaThread*>(INITIAL_ARRAY_SIZE, true);
}
DeadlockCycle::~DeadlockCycle() {
delete _threads;
}
for (int i = 0; i < len; i++) {
if (waitingToLockMonitor != NULL) {
owner_desc = "\n in JNI, which is held by";
}
} else {
// No Java object associated - a JVMTI raw monitor
owner_desc = " (JVMTI raw monitor),\n which is held by";
}
} else {
"Must be an AbstractOwnableSynchronizer");
oop ownerObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(waitingToLockBlocker);
}
}
// Print stack traces
JavaMonitorsInStackTrace = true;
for (int j = 0; j < len; j++) {
}
}
bool include_jni_attaching_threads) {
// skips JavaThreads in the process of exiting
// and also skips VM internal JavaThreads
// Threads in _thread_new or _thread_new_trans state are included.
// i.e. threads have been started but not yet running.
jt->is_exiting() ||
continue;
}
// skip agent threads
continue;
}
// skip jni threads in the process of attaching
continue;
}
_threads_array->append(h);
}
}