/* * Copyright (c) 2003, 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. *
*/
GrowableArray<JvmtiRawMonitor*>* JvmtiPendingMonitors::_monitors = new (mtServiceability) GrowableArray<JvmtiRawMonitor*>(1, mtServiceability);
void JvmtiPendingMonitors::transition_raw_monitors() {
assert((Threads::number_of_threads()==1), "Java thread has not been created yet or more than one java thread " "is running. Raw monitor transition will not work");
JavaThread* current_java_thread = JavaThread::current();
{
ThreadToNativeFromVM ttnfvm(current_java_thread); for (int i = 0; i < count(); i++) {
JvmtiRawMonitor* rmonitor = monitors()->at(i);
rmonitor->raw_enter(current_java_thread);
}
} // pending monitors are converted to real monitor so delete them all.
dispose();
}
// This object might not be a JvmtiRawMonitor so we can't assume // the _magic field is properly aligned. Get the value in a safe // way and then check against JVMTI_RM_MAGIC.
switch (sizeof(_magic)) { case 2:
value = Bytes::get_native_u2((address)&_magic); break;
case 4:
value = Bytes::get_native_u4((address)&_magic); break;
case 8:
value = Bytes::get_native_u8((address)&_magic); break;
default:
guarantee(false, "_magic field is an unexpected size");
}
return value == JVMTI_RM_MAGIC;
}
// ------------------------------------------------------------------------- // The JVMTI raw monitor subsystem is entirely distinct from normal // java-synchronization or jni-synchronization. JVMTI raw monitors are not // associated with objects. They can be implemented in any manner // that makes sense. The original implementors decided to piggy-back // the raw-monitor implementation on the existing Java ObjectMonitor mechanism. // Now we just use a simplified form of that ObjectMonitor code. // // Note that we use the single RawMonitor_lock to protect queue operations for // _all_ raw monitors. This is a scalability impediment, but since raw monitor usage // is fairly rare, this is not of concern. The RawMonitor_lock can not // be held indefinitely. The critical sections must be short and bounded. // // -------------------------------------------------------------------------
void JvmtiRawMonitor::simple_enter(Thread* self) { for (;;) { if (Atomic::replace_if_null(&_owner, self)) { if (self->is_Java_thread()) {
Continuation::pin(JavaThread::cast(self));
} return;
}
RawMonitor_lock->lock_without_safepoint_check();
QNode* w = _entry_list; if (w != NULL) {
_entry_list = w->_next;
}
RawMonitor_lock->unlock(); if (w != NULL) {
guarantee(w ->_t_state == QNode::TS_ENTER, "invariant"); // Once we set _t_state to TS_RUN the waiting thread can complete // simple_enter and 'w' is pointing into random stack space. So we have // to ensure we extract the ParkEvent (which is in type-stable memory) // before we set the state, and then don't access 'w'.
ParkEvent* ev = w->_event;
OrderAccess::loadstore();
w->_t_state = QNode::TS_RUN;
OrderAccess::fence();
ev->unpark();
} return;
}
inlinevoid JvmtiRawMonitor::dequeue_waiter(QNode& node) { // If thread still resides on the waitset then unlink it. // Double-checked locking -- the usage is safe in this context // as _t_state is volatile and the lock-unlock operators are // serializing (barrier-equivalent).
// simple_wait is not quite so simple as we have to deal with the interaction // with the Thread interrupt state, which resides in the java.lang.Thread object. // That state must only be accessed while _thread_in_vm and requires proper thread-state // transitions. // Returns M_OK usually, but M_INTERRUPTED if the thread is a JavaThread and was // interrupted. // Note: // - simple_wait never reenters the monitor. // - A JavaThread must be in native. int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
guarantee(_owner == self , "invariant");
guarantee(_recursions == 0, "invariant");
int ret = M_OK; if (self->is_Java_thread()) {
JavaThread* jt = JavaThread::cast(self);
guarantee(jt->thread_state() == _thread_in_native, "invariant");
{ // This transition must be after we exited the monitor.
ThreadInVMfromNative tivmfn(jt); if (jt->is_interrupted(true)) {
ret = M_INTERRUPTED;
} else {
ThreadBlockInVM tbivm(jt); if (millis <= 0) {
self->_ParkEvent->park();
} else {
self->_ParkEvent->park(millis);
} // Return to VM before post-check of interrupt state
} if (jt->is_interrupted(true)) {
ret = M_INTERRUPTED;
}
}
} else { if (millis <= 0) {
self->_ParkEvent->park();
} else {
self->_ParkEvent->park(millis);
}
}
// We have two options: // A. Transfer the threads from the _wait_set to the _entry_list // B. Remove the thread from the _wait_set and unpark() it. // // We use (B), which is crude and results in lots of futile // context switching. In particular (B) induces lots of contention.
ParkEvent* ev = NULL; // consider using a small auto array ...
RawMonitor_lock->lock_without_safepoint_check(); for (;;) {
QNode* w = _wait_set; if (w == NULL) break;
_wait_set = w->_next; if (ev != NULL) {
ev->unpark();
ev = NULL;
}
ev = w->_event;
OrderAccess::loadstore();
w->_t_state = QNode::TS_RUN;
OrderAccess::storeload(); if (!all) { break;
}
}
RawMonitor_lock->unlock(); if (ev != NULL) {
ev->unpark();
} return;
}
void JvmtiRawMonitor::ExitOnSuspend::operator()(JavaThread* current) { // We must exit the monitor in case of a safepoint.
_rm->simple_exit(current);
_rm_exited = true;
}
// JavaThreads will enter here with state _thread_in_native. void JvmtiRawMonitor::raw_enter(Thread* self) { // TODO Atomic::load on _owner field if (_owner == self) {
_recursions++; return;
}
self->set_current_pending_raw_monitor(this);
if (!self->is_Java_thread()) {
simple_enter(self);
} else {
JavaThread* jt = JavaThread::cast(self);
guarantee(jt->thread_state() == _thread_in_native, "invariant");
ThreadInVMfromNative tivmfn(jt); for (;;) {
ExitOnSuspend eos(this);
{
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos, true/* allow_suspend */);
simple_enter(jt);
} if (!eos.monitor_exited()) { break;
}
}
}
int JvmtiRawMonitor::raw_exit(Thread* self) { if (self != _owner) { return M_ILLEGAL_MONITOR_STATE;
} if (_recursions > 0) {
_recursions--;
} else {
simple_exit(self);
}
return M_OK;
}
int JvmtiRawMonitor::raw_wait(jlong millis, Thread* self) { if (self != _owner) { return M_ILLEGAL_MONITOR_STATE;
}
int ret = M_OK;
// To avoid spurious wakeups we reset the parkevent. This is strictly optional. // The caller must be able to tolerate spurious returns from raw_wait().
self->_ParkEvent->reset();
OrderAccess::fence();
intptr_t save = _recursions;
_recursions = 0;
ret = simple_wait(self, millis);
// Now we need to re-enter the monitor. For JavaThreads // we need to manage suspend requests. if (self->is_Java_thread()) { // JavaThread re-enter
JavaThread* jt = JavaThread::cast(self);
ThreadInVMfromNative tivmfn(jt); for (;;) {
ExitOnSuspend eos(this);
{
ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos, true/* allow_suspend */);
simple_enter(jt);
} if (!eos.monitor_exited()) { break;
}
} if (jt->is_interrupted(true)) {
ret = M_INTERRUPTED;
}
} else { // Non-JavaThread re-enter
assert(ret != M_INTERRUPTED, "Only JavaThreads can be interrupted");
simple_enter(self);
}
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.