/* * Copyright (c) 2012, 2022, 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. *
*/
void JfrThreadLocal::on_start(Thread* t) {
assign_thread_id(t, t->jfr_thread_local()); if (JfrRecorder::is_recording()) {
JfrCheckpointManager::write_checkpoint(t); if (t->is_Java_thread()) {
send_java_thread_start_event(JavaThread::cast(t));
}
} if (t->jfr_thread_local()->has_cached_stack_trace()) {
t->jfr_thread_local()->clear_cached_stack_trace();
}
}
// The starter thread ensures that the startee has a valid _vm_thread_id and _contextual_id. // This is to avoid recursion in thread assignment since accessing the java threadObj can lead // to events being fired, a situation the starter thread can handle but not the startee. void JfrThreadLocal::on_java_thread_start(JavaThread* starter, JavaThread* startee) {
assert(starter != nullptr, "invariant");
assert(startee != nullptr, "invariant");
JfrThreadLocal* const tl = startee->jfr_thread_local();
assign_thread_id(startee, tl);
assert(vthread_id(startee) != 0, "invariant");
assert(jvm_thread_id(startee) == vthread_id(startee), "invariant"); if (JfrRecorder::is_recording() && EventThreadStart::is_enabled() && EventThreadStart::is_stacktrace_enabled()) { // skip level 2 to skip frames Thread.start() and Thread.start0()
startee->jfr_thread_local()->set_cached_stack_trace_id(JfrStackTraceRepository::record(starter, 2));
}
}
void JfrThreadLocal::on_exit(Thread* t) {
assert(t != NULL, "invariant");
JfrThreadLocal * const tl = t->jfr_thread_local();
assert(!tl->is_dead(), "invariant"); if (JfrRecorder::is_recording()) {
JfrCheckpointManager::write_checkpoint(t);
} if (t->is_Java_thread()) {
JavaThread* const jt = JavaThread::cast(t);
send_java_thread_end_event(jt, JfrThreadLocal::jvm_thread_id(jt));
JfrThreadCPULoadEvent::send_event_for_thread(jt);
}
release(tl, Thread::current()); // because it could be that Thread::current() != t
}
void JfrThreadLocal::set_vthread_epoch(const JavaThread* jt, traceid tid, u2 epoch) {
assert(jt != nullptr, "invariant");
assert(is_vthread(jt), "invariant"); // To support event recursion, we update the native side first, // this provides the terminating case.
Atomic::store(&jt->jfr_thread_local()->_vthread_epoch, epoch); /* * The java side, i.e. the vthread object, can now be updated. * Accessing the vthread object itself is a recursive case, * because it can trigger additional events, e.g. * loading the oop through load barriers. * Note there is a potential problem with this solution: * The recursive write hitting the terminating case will * use the thread id _before_ the checkpoint is committed. * Hence, the periodic thread can possibly flush that event * to a segment that does not include an associated checkpoint. * Considered rare and quite benign for now. The worst case is * that thread information for that event is not resolvable, i.e. null.
*/
oop vthread = jt->vthread();
assert(vthread != nullptr, "invariant");
AccessThreadTraceId::set_epoch(vthread, epoch);
JfrCheckpointManager::write_checkpoint(const_cast<JavaThread*>(jt), tid, vthread);
}
traceid JfrThreadLocal::thread_id(const Thread* t) {
assert(t != NULL, "invariant"); if (is_impersonating(t)) { return t->jfr_thread_local()->_thread_id_alias;
}
JfrThreadLocal* const tl = t->jfr_thread_local(); if (!t->is_Java_thread() || !Atomic::load_acquire(&tl->_vthread)) { return jvm_thread_id(t, tl);
} // virtual thread const JavaThread* jt = JavaThread::cast(t); const traceid tid = vthread_id(jt);
assert(tid != 0, "invariant"); if (!tl->is_vthread_excluded()) { const u2 current_epoch = AccessThreadTraceId::current_epoch(); if (vthread_epoch(jt) != current_epoch) {
set_vthread_epoch(jt, tid, current_epoch);
}
} return tid;
}
// When not recording, there is no checkpoint system // in place for writing vthread information.
traceid JfrThreadLocal::external_thread_id(const Thread* t) {
assert(t != NULL, "invariant"); return JfrRecorder::is_recording() ? thread_id(t) : jvm_thread_id(t);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.