void initialize() {
_value = &_value_buffer[1];
_value_state = &_value_state_buffer[1];
_max_size = _default_size;
_size = 0;
_start_at_zero = false;
}
template<typename T>
inline int push_oop_impl(T handle, int size) {
JNITypes::put_obj((oop)handle, _value, size); // Updates size.
return size; // Return the updated size.
}
public:
JavaCallArguments() { initialize(); }
JavaCallArguments(Handle receiver) {
initialize();
push_oop(receiver);
}
JavaCallArguments(int max_size) {
if (max_size > _default_size) {
_value = NEW_RESOURCE_ARRAY(intptr_t, max_size + 1);
_value_state = NEW_RESOURCE_ARRAY(u_char, max_size + 1);
_value++;
_value_state++;
_max_size = max_size;
_size = 0;
_start_at_zero = false;
} else {
initialize();
}
}
enum {
value_state_primitive,
value_state_oop,
value_state_handle,
value_state_jobject,
value_state_limit
};
inline void push_oop(Handle h) {
_value_state[_size] = value_state_handle;
_size = push_oop_impl(h.raw_value(), _size);
}
inline void push_jobject(jobject h) {
_value_state[_size] = value_state_jobject;
_size = push_oop_impl(h, _size);
}
inline void push_int(int i) {
_value_state[_size] = value_state_primitive;
JNITypes::put_int(i, _value, _size);
}
inline void push_double(double d) {
_value_state[_size] = value_state_primitive;
_value_state[_size + 1] = value_state_primitive;
JNITypes::put_double(d, _value, _size);
}
inline void push_long(jlong l) {
_value_state[_size] = value_state_primitive;
_value_state[_size + 1] = value_state_primitive;
JNITypes::put_long(l, _value, _size);
}
inline void push_float(float f) {
_value_state[_size] = value_state_primitive;
JNITypes::put_float(f, _value, _size);
}
Handle receiver() {
assert(_size > 0, "must at least be one argument");
assert(_value_state[0] == value_state_handle,
"first argument must be an oop");
assert(_value[0] != 0, "receiver must be not-null");
return Handle((oop*)_value[0], false);
}
void set_receiver(Handle h) {
assert(_start_at_zero == false, "can only be called once");
_start_at_zero = true;
_value_state--;
_value--;
_size++;
_value_state[0] = value_state_handle;
push_oop_impl(h.raw_value(), 0);
}
intptr_t* parameters() ;
int size_of_parameters() const { return _size; }
void verify(methodHandle method, BasicType return_type);
};
class JavaCalls: AllStatic {
static void call_helper(JavaValue* result, methodHandle* method, JavaCallArguments* args, TRAPS);
public:
static void call_default_constructor(JavaThread* thread, methodHandle method, Handle receiver, TRAPS);
static void call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS); // No args
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_special(JavaValue* result, Handle receiver, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
static void call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, TRAPS); // No args
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_virtual(JavaValue* result, Handle receiver, KlassHandle spec_klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, TRAPS);
static void call_static(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, Handle arg1, Handle arg2, TRAPS);
static void call(JavaValue* result, methodHandle method, JavaCallArguments* args, TRAPS);
};
#endif // SHARE_VM_RUNTIME_JAVACALLS_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/javaFrameAnchor.hpp
#ifndef SHARE_VM_RUNTIME_JAVAFRAMEANCHOR_HPP
#define SHARE_VM_RUNTIME_JAVAFRAMEANCHOR_HPP
#include "utilities/globalDefinitions.hpp"
#include "runtime/orderAccess.inline.hpp"
class JavaThread;
class JavaFrameAnchor VALUE_OBJ_CLASS_SPEC {
friend class CallNativeDirectNode;
friend class OptoRuntime;
friend class Runtime1;
friend class StubAssembler;
friend class CallRuntimeDirectNode;
friend class MacroAssembler;
friend class InterpreterGenerator;
friend class LIR_Assembler;
friend class GraphKit;
friend class StubGenerator;
friend class JavaThread;
friend class frame;
friend class VMStructs;
friend class BytecodeInterpreter;
friend class JavaCallWrapper;
private:
intptr_t* volatile _last_Java_sp;
volatile address _last_Java_pc;
bool has_last_Java_frame() const { return _last_Java_sp != NULL; }
void zap(void) { _last_Java_sp = NULL; }
#ifdef TARGET_ARCH_x86
# include "javaFrameAnchor_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "javaFrameAnchor_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "javaFrameAnchor_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "javaFrameAnchor_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "javaFrameAnchor_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "javaFrameAnchor_ppc.hpp"
#endif
public:
JavaFrameAnchor() { clear(); }
JavaFrameAnchor(JavaFrameAnchor *src) { copy(src); }
void set_last_Java_pc(address pc) { _last_Java_pc = pc; }
static ByteSize last_Java_sp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_sp); }
static ByteSize last_Java_pc_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_pc); }
};
#endif // SHARE_VM_RUNTIME_JAVAFRAMEANCHOR_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/jfieldIDWorkaround.hpp
#ifndef SHARE_VM_RUNTIME_JFIELDIDWORKAROUND_HPP
#define SHARE_VM_RUNTIME_JFIELDIDWORKAROUND_HPP
class jfieldIDWorkaround: AllStatic {
private:
enum {
checked_bits = 1,
instance_bits = 1,
address_bits = BitsPerWord - checked_bits - instance_bits,
large_offset_bits = address_bits, // unioned with address
small_offset_bits = 7,
klass_bits = address_bits - small_offset_bits,
checked_shift = 0,
instance_shift = checked_shift + checked_bits,
address_shift = instance_shift + instance_bits,
offset_shift = address_shift, // unioned with address
klass_shift = offset_shift + small_offset_bits,
checked_mask_in_place = right_n_bits(checked_bits) << checked_shift,
instance_mask_in_place = right_n_bits(instance_bits) << instance_shift,
#ifndef _WIN64
large_offset_mask = right_n_bits(large_offset_bits),
small_offset_mask = right_n_bits(small_offset_bits),
klass_mask = right_n_bits(klass_bits)
#endif
};
#ifdef _WIN64
const static uintptr_t large_offset_mask = right_n_bits(large_offset_bits);
const static uintptr_t small_offset_mask = right_n_bits(small_offset_bits);
const static uintptr_t klass_mask = right_n_bits(klass_bits);
#endif
static bool is_checked_jfieldID(jfieldID id) {
uintptr_t as_uint = (uintptr_t) id;
return ((as_uint & checked_mask_in_place) != 0);
}
static intptr_t raw_instance_offset(jfieldID id) {
uintptr_t result = (uintptr_t) id >> address_shift;
if (VerifyJNIFields && is_checked_jfieldID(id)) {
result &= small_offset_mask; // cut off the hash bits
}
return (intptr_t)result;
}
static intptr_t encode_klass_hash(Klass* k, intptr_t offset);
static bool klass_hash_ok(Klass* k, jfieldID id);
static void verify_instance_jfieldID(Klass* k, jfieldID id);
public:
static bool is_valid_jfieldID(Klass* k, jfieldID id);
static bool is_instance_jfieldID(Klass* k, jfieldID id) {
uintptr_t as_uint = (uintptr_t) id;
return ((as_uint & instance_mask_in_place) != 0);
}
static bool is_static_jfieldID(jfieldID id) {
uintptr_t as_uint = (uintptr_t) id;
return ((as_uint & instance_mask_in_place) == 0);
}
static jfieldID to_instance_jfieldID(Klass* k, int offset) {
intptr_t as_uint = ((offset & large_offset_mask) << offset_shift) | instance_mask_in_place;
if (VerifyJNIFields) {
as_uint |= encode_klass_hash(k, offset);
}
jfieldID result = (jfieldID) as_uint;
#ifndef ASSERT
if (VerifyJNIFields)
#endif // ASSERT
{
verify_instance_jfieldID(k, result);
}
assert(raw_instance_offset(result) == (offset & large_offset_mask), "extract right offset");
return result;
}
static intptr_t from_instance_jfieldID(Klass* k, jfieldID id) {
#ifndef ASSERT
if (VerifyJNIFields)
#endif // ASSERT
{
verify_instance_jfieldID(k, id);
}
return raw_instance_offset(id);
}
static jfieldID to_static_jfieldID(JNIid* id) {
assert(id->is_static_field_id(), "from_JNIid, but not static field id");
jfieldID result = (jfieldID) id;
assert(from_static_jfieldID(result) == id, "must produce the same static id");
return result;
}
static JNIid* from_static_jfieldID(jfieldID id) {
assert(jfieldIDWorkaround::is_static_jfieldID(id),
"to_JNIid, but not static jfieldID");
JNIid* result = (JNIid*) id;
assert(result->is_static_field_id(), "to_JNIid, but not static field id");
return result;
}
static jfieldID to_jfieldID(instanceKlassHandle k, int offset, bool is_static) {
if (is_static) {
JNIid *id = k->jni_id_for(offset);
debug_only(id->set_is_static_field_id());
return jfieldIDWorkaround::to_static_jfieldID(id);
} else {
return jfieldIDWorkaround::to_instance_jfieldID(k(), offset);
}
}
};
#endif // SHARE_VM_RUNTIME_JFIELDIDWORKAROUND_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/jniHandles.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/iterator.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#endif
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
JNIHandleBlock* JNIHandles::_global_handles = NULL;
JNIHandleBlock* JNIHandles::_weak_global_handles = NULL;
oop JNIHandles::_deleted_handle = NULL;
jobject JNIHandles::make_local(oop obj) {
if (obj == NULL) {
return NULL; // ignore null handles
} else {
Thread* thread = Thread::current();
assert(Universe::heap()->is_in_reserved(obj), "sanity check");
return thread->active_handles()->allocate_handle(obj);
}
}
jobject JNIHandles::make_local(Thread* thread, oop obj) {
if (obj == NULL) {
return NULL; // ignore null handles
} else {
assert(Universe::heap()->is_in_reserved(obj), "sanity check");
return thread->active_handles()->allocate_handle(obj);
}
}
jobject JNIHandles::make_local(JNIEnv* env, oop obj) {
if (obj == NULL) {
return NULL; // ignore null handles
} else {
JavaThread* thread = JavaThread::thread_from_jni_environment(env);
assert(Universe::heap()->is_in_reserved(obj), "sanity check");
return thread->active_handles()->allocate_handle(obj);
}
}
jobject JNIHandles::make_global(Handle obj) {
assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
jobject res = NULL;
if (!obj.is_null()) {
MutexLocker ml(JNIGlobalHandle_lock);
assert(Universe::heap()->is_in_reserved(obj()), "sanity check");
res = _global_handles->allocate_handle(obj());
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
return res;
}
jobject JNIHandles::make_weak_global(Handle obj) {
assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC");
jobject res = NULL;
if (!obj.is_null()) {
{
MutexLocker ml(JNIGlobalHandle_lock);
assert(Universe::heap()->is_in_reserved(obj()), "sanity check");
res = _weak_global_handles->allocate_handle(obj());
}
assert(is_ptr_aligned(res, weak_tag_alignment), "invariant");
char* tptr = reinterpret_cast<char*>(res) + weak_tag_value;
res = reinterpret_cast<jobject>(tptr);
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
return res;
}
template<bool external_guard>
oop JNIHandles::resolve_jweak(jweak handle) {
assert(is_jweak(handle), "precondition");
oop result = jweak_ref(handle);
result = guard_value<external_guard>(result);
#if INCLUDE_ALL_GCS
if (result != NULL && UseG1GC) {
G1SATBCardTableModRefBS::enqueue(result);
}
#endif // INCLUDE_ALL_GCS
return result;
}
template oop JNIHandles::resolve_jweak<true>(jweak);
template oop JNIHandles::resolve_jweak<false>(jweak);
void JNIHandles::destroy_global(jobject handle) {
if (handle != NULL) {
assert(is_global_handle(handle), "Invalid delete of global JNI handle");
jobject_ref(handle) = deleted_handle();
}
}
void JNIHandles::destroy_weak_global(jobject handle) {
if (handle != NULL) {
jweak_ref(handle) = deleted_handle();
}
}
void JNIHandles::oops_do(OopClosure* f) {
f->do_oop(&_deleted_handle);
_global_handles->oops_do(f);
}
void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
_weak_global_handles->weak_oops_do(is_alive, f);
}
void JNIHandles::weak_oops_do(OopClosure* f) {
AlwaysTrueClosure always_true;
weak_oops_do(&always_true, f);
}
void JNIHandles::initialize() {
_global_handles = JNIHandleBlock::allocate_block();
_weak_global_handles = JNIHandleBlock::allocate_block();
EXCEPTION_MARK;
Klass* k = SystemDictionary::Object_klass();
_deleted_handle = InstanceKlass::cast(k)->allocate_instance(CATCH);
}
bool JNIHandles::is_local_handle(Thread* thread, jobject handle) {
JNIHandleBlock* block = thread->active_handles();
while (block != NULL) {
if (block->chain_contains(handle)) {
return true;
}
block = block->pop_frame_link();
}
return false;
}
bool JNIHandles::is_frame_handle(JavaThread* thr, jobject obj) {
return (thr->has_last_Java_frame() &&
(void*)obj < (void*)thr->stack_base() &&
(void*)obj >= (void*)thr->last_Java_sp());
}
bool JNIHandles::is_global_handle(jobject handle) {
return _global_handles->chain_contains(handle);
}
bool JNIHandles::is_weak_global_handle(jobject handle) {
return _weak_global_handles->chain_contains(handle);
}
long JNIHandles::global_handle_memory_usage() {
return _global_handles->memory_usage();
}
long JNIHandles::weak_global_handle_memory_usage() {
return _weak_global_handles->memory_usage();
}
class CountHandleClosure: public OopClosure {
private:
int _count;
public:
CountHandleClosure(): _count(0) {}
virtual void do_oop(oop* ooph) {
if (*ooph != JNIHandles::deleted_handle()) {
_count++;
}
}
virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); }
int count() { return _count; }
};
void JNIHandles::print_on(outputStream* st) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
assert(_global_handles != NULL && _weak_global_handles != NULL,
"JNIHandles not initialized");
CountHandleClosure global_handle_count;
oops_do(&global_handle_count);
weak_oops_do(&global_handle_count);
st->print_cr("JNI global references: %d", global_handle_count.count());
st->cr();
st->flush();
}
class VerifyHandleClosure: public OopClosure {
public:
virtual void do_oop(oop* root) {
(*root)->verify();
}
virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); }
};
void JNIHandles::verify() {
VerifyHandleClosure verify_handle;
oops_do(&verify_handle);
weak_oops_do(&verify_handle);
}
void jni_handles_init() {
JNIHandles::initialize();
}
int JNIHandleBlock::_blocks_allocated = 0;
JNIHandleBlock* JNIHandleBlock::_block_free_list = NULL;
#ifndef PRODUCT
JNIHandleBlock* JNIHandleBlock::_block_list = NULL;
#endif
void JNIHandleBlock::zap() {
_top = 0;
for (int index = 0; index < block_size_in_oops; index++) {
_handles[index] = badJNIHandle;
}
}
JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread) {
assert(thread == NULL || thread == Thread::current(), "sanity check");
JNIHandleBlock* block;
if (thread != NULL && thread->free_handle_block() != NULL) {
block = thread->free_handle_block();
thread->set_free_handle_block(block->_next);
}
else {
MutexLockerEx ml(JNIHandleBlockFreeList_lock,
Mutex::_no_safepoint_check_flag);
if (_block_free_list == NULL) {
block = new JNIHandleBlock();
_blocks_allocated++;
if (TraceJNIHandleAllocation) {
tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)",
block, _blocks_allocated);
}
if (ZapJNIHandleArea) block->zap();
#ifndef PRODUCT
block->_block_list_link = _block_list;
_block_list = block;
#endif
} else {
block = _block_free_list;
_block_free_list = _block_free_list->_next;
}
}
block->_top = 0;
block->_next = NULL;
block->_pop_frame_link = NULL;
block->_planned_capacity = block_size_in_oops;
debug_only(block->_last = NULL);
debug_only(block->_free_list = NULL);
debug_only(block->_allocate_before_rebuild = -1);
return block;
}
void JNIHandleBlock::release_block(JNIHandleBlock* block, Thread* thread) {
assert(thread == NULL || thread == Thread::current(), "sanity check");
JNIHandleBlock* pop_frame_link = block->pop_frame_link();
if (thread != NULL ) {
if (ZapJNIHandleArea) block->zap();
JNIHandleBlock* freelist = thread->free_handle_block();
block->_pop_frame_link = NULL;
thread->set_free_handle_block(block);
if ( freelist != NULL ) {
while ( block->_next != NULL ) block = block->_next;
block->_next = freelist;
}
block = NULL;
}
if (block != NULL) {
MutexLockerEx ml(JNIHandleBlockFreeList_lock,
Mutex::_no_safepoint_check_flag);
while (block != NULL) {
if (ZapJNIHandleArea) block->zap();
JNIHandleBlock* next = block->_next;
block->_next = _block_free_list;
_block_free_list = block;
block = next;
}
}
if (pop_frame_link != NULL) {
release_block(pop_frame_link, thread);
}
}
void JNIHandleBlock::oops_do(OopClosure* f) {
JNIHandleBlock* current_chain = this;
while (current_chain != NULL) {
for (JNIHandleBlock* current = current_chain; current != NULL;
current = current->_next) {
assert(current == current_chain || current->pop_frame_link() == NULL,
"only blocks first in chain should have pop frame link set");
for (int index = 0; index < current->_top; index++) {
oop* root = &(current->_handles)[index];
oop value = *root;
if (value != NULL && Universe::heap()->is_in_reserved(value)) {
f->do_oop(root);
}
}
if (current->_top < block_size_in_oops) {
break;
}
}
current_chain = current_chain->pop_frame_link();
}
}
void JNIHandleBlock::weak_oops_do(BoolObjectClosure* is_alive,
OopClosure* f) {
for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {
assert(current->pop_frame_link() == NULL,
"blocks holding weak global JNI handles should not have pop frame link set");
for (int index = 0; index < current->_top; index++) {
oop* root = &(current->_handles)[index];
oop value = *root;
if (value != NULL && Universe::heap()->is_in_reserved(value)) {
if (is_alive->do_object_b(value)) {
f->do_oop(root);
} else {
if (TraceReferenceGC) {
tty->print_cr("Clearing JNI weak reference (" INTPTR_FORMAT ")", root);
}
}
}
}
if (current->_top < block_size_in_oops) {
break;
}
}
JvmtiExport::weak_oops_do(is_alive, f);
}
jobject JNIHandleBlock::allocate_handle(oop obj) {
assert(Universe::heap()->is_in_reserved(obj), "sanity check");
if (_top == 0) {
for (JNIHandleBlock* current = _next; current != NULL;
current = current->_next) {
assert(current->_last == NULL, "only first block should have _last set");
assert(current->_free_list == NULL,
"only first block should have _free_list set");
current->_top = 0;
if (ZapJNIHandleArea) current->zap();
}
_free_list = NULL;
_allocate_before_rebuild = 0;
_last = this;
if (ZapJNIHandleArea) zap();
}
if (_last->_top < block_size_in_oops) {
oop* handle = &(_last->_handles)[_last->_top++];
return (jobject) handle;
}
if (_free_list != NULL) {
oop* handle = _free_list;
_free_list = (oop*) *_free_list;
return (jobject) handle;
}
if (_last->_next != NULL) {
_last = _last->_next;
return allocate_handle(obj);
}
if (_allocate_before_rebuild == 0) {
rebuild_free_list(); // updates _allocate_before_rebuild counter
} else {
Thread* thread = Thread::current();
Handle obj_handle(thread, obj);
_last->_next = JNIHandleBlock::allocate_block(thread);
_last = _last->_next;
_allocate_before_rebuild--;
obj = obj_handle();
}
return allocate_handle(obj); // retry
}
void JNIHandleBlock::rebuild_free_list() {
assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking");
int free = 0;
int blocks = 0;
for (JNIHandleBlock* current = this; current != NULL; current = current->_next) {
for (int index = 0; index < current->_top; index++) {
oop* handle = &(current->_handles)[index];
if (*handle == JNIHandles::deleted_handle()) {
_free_list = handle;
free++;
}
}
assert(current->_top == block_size_in_oops, "just checking");
blocks++;
}
int total = blocks * block_size_in_oops;
int extra = total - 2*free;
if (extra > 0) {
_allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops;
}
if (TraceJNIHandleAllocation) {
tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d",
this, blocks, total-free, free, _allocate_before_rebuild);
}
}
bool JNIHandleBlock::contains(jobject handle) const {
return ((jobject)&_handles[0] <= handle && handle<(jobject)&_handles[_top]);
}
bool JNIHandleBlock::chain_contains(jobject handle) const {
for (JNIHandleBlock* current = (JNIHandleBlock*) this; current != NULL; current = current->_next) {
if (current->contains(handle)) {
return true;
}
}
return false;
}
int JNIHandleBlock::length() const {
int result = 1;
for (JNIHandleBlock* current = _next; current != NULL; current = current->_next) {
result++;
}
return result;
}
const size_t JNIHandleBlock::get_number_of_live_handles() {
CountHandleClosure counter;
oops_do(&counter);
return counter.count();
}
long JNIHandleBlock::memory_usage() const {
return length() * sizeof(JNIHandleBlock);
}
#ifndef PRODUCT
bool JNIHandleBlock::any_contains(jobject handle) {
for (JNIHandleBlock* current = _block_list; current != NULL; current = current->_block_list_link) {
if (current->contains(handle)) {
return true;
}
}
return false;
}
void JNIHandleBlock::print_statistics() {
int used_blocks = 0;
int free_blocks = 0;
int used_handles = 0;
int free_handles = 0;
JNIHandleBlock* block = _block_list;
while (block != NULL) {
if (block->_top > 0) {
used_blocks++;
} else {
free_blocks++;
}
used_handles += block->_top;
free_handles += (block_size_in_oops - block->_top);
block = block->_block_list_link;
}
tty->print_cr("JNIHandleBlocks statistics");
tty->print_cr("- blocks allocated: %d", used_blocks + free_blocks);
tty->print_cr("- blocks in use: %d", used_blocks);
tty->print_cr("- blocks free: %d", free_blocks);
tty->print_cr("- handles in use: %d", used_handles);
tty->print_cr("- handles free: %d", free_handles);
}
#endif
C:\hotspot-69087d08d473\src\share\vm/runtime/jniHandles.hpp
#ifndef SHARE_VM_RUNTIME_JNIHANDLES_HPP
#define SHARE_VM_RUNTIME_JNIHANDLES_HPP
#include "runtime/handles.hpp"
#include "utilities/top.hpp"
class JNIHandleBlock;
class JNIHandles : AllStatic {
friend class VMStructs;
private:
static JNIHandleBlock* _global_handles; // First global handle block
static JNIHandleBlock* _weak_global_handles; // First weak global handle block
static oop _deleted_handle; // Sentinel marking deleted handles
inline static bool is_jweak(jobject handle);
inline static oop& jobject_ref(jobject handle); // NOT jweak!
inline static oop& jweak_ref(jobject handle);
template<bool external_guard> inline static oop guard_value(oop value);
template<bool external_guard> inline static oop resolve_impl(jobject handle);
template<bool external_guard> static oop resolve_jweak(jweak handle);
public:
static const uintptr_t weak_tag_size = 1;
static const uintptr_t weak_tag_alignment = (1u << weak_tag_size);
static const uintptr_t weak_tag_mask = weak_tag_alignment - 1;
static const int weak_tag_value = 1;
inline static oop resolve(jobject handle);
inline static oop resolve_external_guard(jobject handle);
inline static oop resolve_non_null(jobject handle);
static jobject make_local(oop obj);
static jobject make_local(JNIEnv* env, oop obj); // Fast version when env is known
static jobject make_local(Thread* thread, oop obj); // Even faster version when current thread is known
inline static void destroy_local(jobject handle);
static jobject make_global(Handle obj);
static void destroy_global(jobject handle);
static jobject make_weak_global(Handle obj);
static void destroy_weak_global(jobject handle);
static oop deleted_handle() { return _deleted_handle; }
static void initialize();
static void print_on(outputStream* st);
static void print() { print_on(tty); }
static void verify();
static bool is_local_handle(Thread* thread, jobject handle);
static bool is_frame_handle(JavaThread* thr, jobject obj);
static bool is_global_handle(jobject handle);
static bool is_weak_global_handle(jobject handle);
static long global_handle_memory_usage();
static long weak_global_handle_memory_usage();
static void oops_do(OopClosure* f);
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
static void weak_oops_do(OopClosure* f);
};
class JNIHandleBlock : public CHeapObj<mtInternal> {
friend class VMStructs;
friend class CppInterpreter;
private:
enum SomeConstants {
block_size_in_oops = 32 // Number of handles per handle block
};
oop _handles[block_size_in_oops]; // The handles
int _top; // Index of next unused handle
JNIHandleBlock* _next; // Link to next block
JNIHandleBlock* _last; // Last block in use
JNIHandleBlock* _pop_frame_link; // Block to restore on PopLocalFrame call
oop* _free_list; // Handle free list
int _allocate_before_rebuild; // Number of blocks to allocate before rebuilding free list
size_t _planned_capacity;
#ifndef PRODUCT
JNIHandleBlock* _block_list_link; // Link for list below
static JNIHandleBlock* _block_list; // List of all allocated blocks (for debugging only)
#endif
static JNIHandleBlock* _block_free_list; // Free list of currently unused blocks
static int _blocks_allocated; // For debugging/printing
void zap();
protected:
void clear() { _top = 0; }
private:
void rebuild_free_list();
public:
jobject allocate_handle(oop obj);
static JNIHandleBlock* allocate_block(Thread* thread = NULL);
static void release_block(JNIHandleBlock* block, Thread* thread = NULL);
JNIHandleBlock* pop_frame_link() const { return _pop_frame_link; }
void set_pop_frame_link(JNIHandleBlock* block) { _pop_frame_link = block; }
static int top_offset_in_bytes() { return offset_of(JNIHandleBlock, _top); }
void oops_do(OopClosure* f);
void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
void set_planned_capacity(size_t planned_capacity) { _planned_capacity = planned_capacity; }
const size_t get_planned_capacity() { return _planned_capacity; }
const size_t get_number_of_live_handles();
bool chain_contains(jobject handle) const; // Does this block or following blocks contain handle
bool contains(jobject handle) const; // Does this block contain handle
int length() const; // Length of chain starting with this block
long memory_usage() const;
#ifndef PRODUCT
static bool any_contains(jobject handle); // Does any block currently in use contain handle
static void print_statistics();
#endif
};
inline bool JNIHandles::is_jweak(jobject handle) {
STATIC_ASSERT(weak_tag_size == 1);
STATIC_ASSERT(weak_tag_value == 1);
return (reinterpret_cast<uintptr_t>(handle) & weak_tag_mask) != 0;
}
inline oop& JNIHandles::jobject_ref(jobject handle) {
assert(!is_jweak(handle), "precondition");
return *reinterpret_cast<oop*>(handle);
}
inline oop& JNIHandles::jweak_ref(jobject handle) {
assert(is_jweak(handle), "precondition");
char* ptr = reinterpret_cast<char*>(handle) - weak_tag_value;
return *reinterpret_cast<oop*>(ptr);
}
template<bool external_guard>
inline oop JNIHandles::guard_value(oop value) {
if (!external_guard) {
assert(value != badJNIHandle, "Pointing to zapped jni handle area");
assert(value != deleted_handle(), "Used a deleted global handle");
} else if ((value == badJNIHandle) || (value == deleted_handle())) {
value = NULL;
}
return value;
}
template<bool external_guard>
inline oop JNIHandles::resolve_impl(jobject handle) {
assert(handle != NULL, "precondition");
oop result;
if (is_jweak(handle)) { // Unlikely
result = resolve_jweak<external_guard>(handle);
} else {
result = jobject_ref(handle);
assert(external_guard || result != NULL,
"Invalid value read from jni handle");
result = guard_value<external_guard>(result);
}
return result;
}
inline oop JNIHandles::resolve(jobject handle) {
oop result = NULL;
if (handle != NULL) {
result = resolve_impl<false /* external_guard */ >(handle);
}
return result;
}
inline oop JNIHandles::resolve_external_guard(jobject handle) {
oop result = NULL;
if (handle != NULL) {
result = resolve_impl<true /* external_guard */ >(handle);
}
return result;
}
inline oop JNIHandles::resolve_non_null(jobject handle) {
assert(handle != NULL, "JNI handle should not be null");
oop result = resolve_impl<false /* external_guard */ >(handle);
assert(result != NULL, "NULL read from jni handle");
return result;
}
inline void JNIHandles::destroy_local(jobject handle) {
if (handle != NULL) {
jobject_ref(handle) = deleted_handle();
}
}
#endif // SHARE_VM_RUNTIME_JNIHANDLES_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/jniPeriodicChecker.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/jniPeriodicChecker.hpp"
#include "runtime/task.hpp"
class JniPeriodicCheckerTask : public PeriodicTask {
public:
JniPeriodicCheckerTask(int interval_time) : PeriodicTask(interval_time) {}
void task() { os::run_periodic_checks(); }
static void engage();
static void disengage();
};
JniPeriodicCheckerTask* JniPeriodicChecker::_task = NULL;
void JniPeriodicChecker::engage() {
if (CheckJNICalls && !is_active()) {
_task = new JniPeriodicCheckerTask(10);
_task->enroll();
}
}
void JniPeriodicChecker::disengage() {
if (CheckJNICalls && is_active()) {
_task->disenroll();
delete _task;
_task = NULL;
}
}
void jniPeriodicChecker_exit() {
if (!CheckJNICalls) return;
}
C:\hotspot-69087d08d473\src\share\vm/runtime/jniPeriodicChecker.hpp
#ifndef SHARE_VM_RUNTIME_JNIPERIODICCHECKER_HPP
#define SHARE_VM_RUNTIME_JNIPERIODICCHECKER_HPP
class JniPeriodicCheckerTask;
class JniPeriodicChecker : AllStatic {
friend class JniPeriodicCheckerTask;
private:
static JniPeriodicCheckerTask* _task;
public:
static void engage();
static void disengage();
static bool is_active() { return _task != NULL; }
static void initialize();
static void destroy();
};
void jniPeriodicChecker_exit();
#endif // SHARE_VM_RUNTIME_JNIPERIODICCHECKER_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/memprofiler.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/oopMapCache.hpp"
#include "memory/generation.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/memprofiler.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/task.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vmThread.hpp"
#ifndef PRODUCT
class MemProfilerTask : public PeriodicTask {
public:
MemProfilerTask(int interval_time) : PeriodicTask(interval_time) {}
void task();
};
void MemProfilerTask::task() {
MutexLocker mu(Threads_lock);
MemProfiler::do_trace();
}
MemProfilerTask* MemProfiler::_task = NULL;
FILE* MemProfiler::_log_fp = NULL;
bool MemProfiler::is_active() {
return _task != NULL;
}
void MemProfiler::engage() {
const char *log_name = "mprofile.log";
if (!is_active()) {
_log_fp = fopen(log_name , "w+");
if (_log_fp == NULL) {
fatal(err_msg("MemProfiler: Cannot create log file: %s", log_name));
}
fprintf(_log_fp, "MemProfiler: sizes are in Kb, time is in seconds since startup\n\n");
fprintf(_log_fp, " time, #thr, #cls, heap, heap, perm, perm, code, hndls, rescs, oopmp\n");
fprintf(_log_fp, " used, total, used, total, total, total, total, total\n");
fprintf(_log_fp, "--------------------------------------------------------------------------\n");
_task = new MemProfilerTask(MemProfilingInterval);
_task->enroll();
}
}
void MemProfiler::disengage() {
if (!is_active()) return;
do_trace();
fprintf(_log_fp, "MemProfiler detached\n");
fclose(_log_fp);
assert(_task != NULL, "sanity check");
_task->disenroll();
delete _task;
_task = NULL;
}
void MemProfiler::do_trace() {
size_t handles_memory_usage = VMThread::vm_thread()->handle_area()->size_in_bytes();
size_t resource_memory_usage = VMThread::vm_thread()->resource_area()->size_in_bytes();
JavaThread *cur = Threads::first();
while (cur != NULL) {
handles_memory_usage += cur->handle_area()->size_in_bytes();
resource_memory_usage += cur->resource_area()->size_in_bytes();
cur = cur->next();
}
fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
os::elapsedTime(),
Threads::number_of_threads(),
SystemDictionary::number_of_classes(),
Universe::heap()->used() / K,
Universe::heap()->capacity() / K);
fprintf(_log_fp, UINTX_FORMAT_W(6) ",", CodeCache::capacity() / K);
fprintf(_log_fp, UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) "\n",
handles_memory_usage / K,
resource_memory_usage / K,
OopMapCache::memory_usage() / K);
fflush(_log_fp);
}
#endif
C:\hotspot-69087d08d473\src\share\vm/runtime/memprofiler.hpp
#ifndef SHARE_VM_RUNTIME_MEMPROFILER_HPP
#define SHARE_VM_RUNTIME_MEMPROFILER_HPP
class MemProfilerTask;
class MemProfiler : AllStatic {
friend class MemProfilerTask;
private:
static MemProfilerTask* _task;
static FILE* _log_fp;
static void do_trace() PRODUCT_RETURN;
public:
static void engage() PRODUCT_RETURN;
static void disengage() PRODUCT_RETURN;
static bool is_active() PRODUCT_RETURN0;
};
#endif // SHARE_VM_RUNTIME_MEMPROFILER_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/monitorChunk.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/monitorChunk.hpp"
MonitorChunk::MonitorChunk(int number_on_monitors) {
_number_of_monitors = number_on_monitors;
_monitors = NEW_C_HEAP_ARRAY(BasicObjectLock, number_on_monitors, mtInternal);
_next = NULL;
}
MonitorChunk::~MonitorChunk() {
FreeHeap(monitors());
}
void MonitorChunk::oops_do(OopClosure* f) {
for (int index = 0; index < number_of_monitors(); index++) {
at(index)->oops_do(f);
}
}
C:\hotspot-69087d08d473\src\share\vm/runtime/monitorChunk.hpp
#ifndef SHARE_VM_RUNTIME_MONITORCHUNK_HPP
#define SHARE_VM_RUNTIME_MONITORCHUNK_HPP
#include "runtime/synchronizer.hpp"
class MonitorChunk: public CHeapObj<mtInternal> {
private:
int _number_of_monitors;
BasicObjectLock* _monitors;
BasicObjectLock* monitors() const { return _monitors; }
MonitorChunk* _next;
public:
MonitorChunk(int number_on_monitors);
~MonitorChunk();
MonitorChunk* next() const { return _next; }
void set_next(MonitorChunk* next) { _next = next; }
bool is_linked() const { return next() != NULL; }
int number_of_monitors() const { return _number_of_monitors; }
BasicObjectLock* at(int index) { assert(index >= 0 && index < number_of_monitors(), "out of bounds check"); return &monitors()[index]; }
void oops_do(OopClosure* f);
bool contains(void* addr) const { return (addr >= (void*) monitors()) && (addr < (void*) (monitors() + number_of_monitors())); }
};
#endif // SHARE_VM_RUNTIME_MONITORCHUNK_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/mutex.cpp
#include "precompiled.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/events.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "mutex_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "mutex_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "mutex_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "mutex_bsd.inline.hpp"
#endif
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
#define CASPTR(a,c,s) intptr_t(Atomic::cmpxchg_ptr ((void *)(s),(void *)(a),(void *)(c)))
#define UNS(x) (uintptr_t(x))
#define TRACE(m) { static volatile int ctr = 0 ; int x = ++ctr ; if ((x & (x-1))==0) { ::printf ("%d:%s\n", x, #m); ::fflush(stdout); }}
static inline jint MarsagliaXORV (jint x) {
if (x == 0) x = 1|os::random() ;
x ^= x << 6;
x ^= ((unsigned)x) >> 21;
x ^= x << 7 ;
return x & 0x7FFFFFFF ;
}
static int Stall (int its) {
static volatile jint rv = 1 ;
volatile int OnFrame = 0 ;
jint v = rv ^ UNS(OnFrame) ;
while (--its >= 0) {
v = MarsagliaXORV (v) ;
}
if (v == 0x12345) rv = v ;
return v ;
}
int Monitor::TryLock () {
intptr_t v = _LockWord.FullWord ;
for (;;) {
if ((v & _LBIT) != 0) return 0 ;
const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
if (v == u) return 1 ;
v = u ;
}
}
int Monitor::TryFast () {
intptr_t v = CASPTR (&_LockWord, 0, _LBIT) ; // agro ...
if (v == 0) return 1 ;
for (;;) {
if ((v & _LBIT) != 0) return 0 ;
const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
if (v == u) return 1 ;
v = u ;
}
}
int Monitor::ILocked () {
const intptr_t w = _LockWord.FullWord & 0xFF ;
assert (w == 0 || w == _LBIT, "invariant") ;
return w == _LBIT ;
}
int Monitor::TrySpin (Thread * const Self) {
if (TryLock()) return 1 ;
if (!os::is_MP()) return 0 ;
int Probes = 0 ;
int Delay = 0 ;
int Steps = 0 ;
int SpinMax = NativeMonitorSpinLimit ;
int flgs = NativeMonitorFlags ;
for (;;) {
intptr_t v = _LockWord.FullWord;
if ((v & _LBIT) == 0) {
if (CASPTR (&_LockWord, v, v|_LBIT) == v) {
return 1 ;
}
continue ;
}
if ((flgs & 8) == 0) {
SpinPause () ;
}
++ Probes;
if (Probes > SpinMax) return 0 ;
if ((Probes & 0x7) == 0) {
Delay = ((Delay << 1)|1) & 0x7FF ;
}
if (flgs & 2) continue ;
Steps += Delay ;
if (Self != NULL) {
jint rv = Self->rng[0] ;
for (int k = Delay ; --k >= 0; ) {
rv = MarsagliaXORV (rv) ;
if ((flgs & 4) == 0 && SafepointSynchronize::do_call_back()) return 0 ;
}
Self->rng[0] = rv ;
} else {
Stall (Delay) ;
}
}
}
static int ParkCommon (ParkEvent * ev, jlong timo) {
intx nmt = NativeMonitorTimeout ;
if (nmt > 0 && (nmt < timo || timo <= 0)) {
timo = nmt ;
}
int err = OS_OK ;
if (0 == timo) {
ev->park() ;
} else {
err = ev->park(timo) ;
}
return err ;
}
inline int Monitor::AcquireOrPush (ParkEvent * ESelf) {
intptr_t v = _LockWord.FullWord ;
for (;;) {
if ((v & _LBIT) == 0) {
const intptr_t u = CASPTR (&_LockWord, v, v|_LBIT) ;
if (u == v) return 1 ; // indicate acquired
v = u ;
} else {
ESelf->ListNext = (ParkEvent *) (v & ~_LBIT) ;
const intptr_t u = CASPTR (&_LockWord, v, intptr_t(ESelf)|_LBIT) ;
if (u == v) return 0 ; // indicate pushed onto cxq
v = u ;
}
}
}
void Monitor::ILock (Thread * Self) {
assert (_OnDeck != Self->_MutexEvent, "invariant") ;
if (TryFast()) {
Exeunt:
assert (ILocked(), "invariant") ;
return ;
}
ParkEvent * const ESelf = Self->_MutexEvent ;
assert (_OnDeck != ESelf, "invariant") ;
if (TrySpin (Self)) goto Exeunt ;
ESelf->reset() ;
OrderAccess::fence() ;
if ((NativeMonitorFlags & 32) && CASPTR (&_OnDeck, NULL, UNS(Self)) == 0) {
goto OnDeck_LOOP ;
}
if (AcquireOrPush (ESelf)) goto Exeunt ;
while (_OnDeck != ESelf) {
ParkCommon (ESelf, 0) ;
}
OnDeck_LOOP:
for (;;) {
assert (_OnDeck == ESelf, "invariant") ;
if (TrySpin (Self)) break ;
ParkCommon (ESelf, 0) ;
}
assert (_OnDeck == ESelf, "invariant") ;
_OnDeck = NULL ;
goto Exeunt ;
}
void Monitor::IUnlock (bool RelaxAssert) {
assert (ILocked(), "invariant") ;
OrderAccess::release_store(&_LockWord.Bytes[_LSBINDEX], 0); // drop outer lock
OrderAccess::storeload ();
ParkEvent * const w = _OnDeck ;
assert (RelaxAssert || w != Thread::current()->_MutexEvent, "invariant") ;
if (w != NULL) {
if ((UNS(w) & _LBIT) == 0) w->unpark() ;
return ;
}
intptr_t cxq = _LockWord.FullWord ;
if (((cxq & ~_LBIT)|UNS(_EntryList)) == 0) {
return ; // normal fast-path exit - cxq and EntryList both empty
}
if (cxq & _LBIT) {
return ;
}
Succession:
if (CASPTR (&_OnDeck, NULL, _LBIT) != UNS(NULL)) {
return ;
}
ParkEvent * List = _EntryList ;
if (List != NULL) {
WakeOne:
assert (List == _EntryList, "invariant") ;
ParkEvent * const w = List ;
assert (RelaxAssert || w != Thread::current()->_MutexEvent, "invariant") ;
_EntryList = w->ListNext ;
assert (UNS(_OnDeck) == _LBIT, "invariant") ;
_OnDeck = w ; // pass OnDeck to w.
OrderAccess::storeload() ;
cxq = _LockWord.FullWord ;
if (cxq & _LBIT) return ;
w->unpark() ;
return ;
}
cxq = _LockWord.FullWord ;
if ((cxq & ~_LBIT) != 0) {
for (;;) {
if (cxq & _LBIT) goto Punt ;
const intptr_t vfy = CASPTR (&_LockWord, cxq, cxq & _LBIT) ;
if (vfy == cxq) break ;
cxq = vfy ;
}
assert (_EntryList == NULL, "invariant") ;
_EntryList = List = (ParkEvent *)(cxq & ~_LBIT) ;
assert (List != NULL, "invariant") ;
goto WakeOne ;
}
Punt:
assert (UNS(_OnDeck) == _LBIT, "invariant") ;
_OnDeck = NULL ; // Release inner lock.
OrderAccess::storeload(); // Dekker duality - pivot point
cxq = _LockWord.FullWord ;
if ((cxq & ~_LBIT) != 0 && (cxq & _LBIT) == 0) {
goto Succession ; // potential race -- re-run succession
}
return ;
}
bool Monitor::notify() {
assert (_owner == Thread::current(), "invariant") ;
assert (ILocked(), "invariant") ;
if (_WaitSet == NULL) return true ;
NotifyCount ++ ;
Thread::muxAcquire (_WaitLock, "notify:WaitLock") ;
ParkEvent * nfy = _WaitSet ;
if (nfy != NULL) { // DCL idiom
_WaitSet = nfy->ListNext ;
assert (nfy->Notified == 0, "invariant") ;
for (;;) {
const intptr_t v = _LockWord.FullWord ;
assert ((v & 0xFF) == _LBIT, "invariant") ;
nfy->ListNext = (ParkEvent *)(v & ~_LBIT);
if (CASPTR (&_LockWord, v, UNS(nfy)|_LBIT) == v) break;
}
OrderAccess::fence() ;
nfy->Notified = 1;
}
Thread::muxRelease (_WaitLock) ;
if (nfy != NULL && (NativeMonitorFlags & 16)) {
nfy->unpark() ;
}
assert (ILocked(), "invariant") ;
return true ;
}
bool Monitor::notify_all() {
assert (_owner == Thread::current(), "invariant") ;
assert (ILocked(), "invariant") ;
while (_WaitSet != NULL) notify() ;
return true ;
}
int Monitor::IWait (Thread * Self, jlong timo) {
assert (ILocked(), "invariant") ;
ParkEvent * const ESelf = Self->_MutexEvent ;
ESelf->Notified = 0 ;
ESelf->reset() ;
OrderAccess::fence() ;
Thread::muxAcquire (_WaitLock, "wait:WaitLock:Add") ;
ESelf->ListNext = _WaitSet ;
_WaitSet = ESelf ;
Thread::muxRelease (_WaitLock) ;
IUnlock (true) ;
for (;;) {
if (ESelf->Notified) break ;
int err = ParkCommon (ESelf, timo) ;
if (err == OS_TIMEOUT || (NativeMonitorFlags & 1)) break ;
}
OrderAccess::fence() ;
int WasOnWaitSet = 0 ;
if (ESelf->Notified == 0) {
Thread::muxAcquire (_WaitLock, "wait:WaitLock:remove") ;
if (ESelf->Notified == 0) { // DCL idiom
assert (_OnDeck != ESelf, "invariant") ; // can't be both OnDeck and on WaitSet
ParkEvent * p = _WaitSet ;
ParkEvent * q = NULL ; // classic q chases p
while (p != NULL && p != ESelf) {
q = p ;
p = p->ListNext ;
}
assert (p == ESelf, "invariant") ;
if (p == _WaitSet) { // found at head
assert (q == NULL, "invariant") ;
_WaitSet = p->ListNext ;
} else { // found in interior
assert (q->ListNext == p, "invariant") ;
q->ListNext = p->ListNext ;
}
WasOnWaitSet = 1 ; // We were *not* notified but instead encountered timeout
}
Thread::muxRelease (_WaitLock) ;
}
if (WasOnWaitSet) {
assert (_OnDeck != ESelf, "invariant") ;
ILock (Self) ;
} else {
for (;;) {
if (_OnDeck == ESelf && TrySpin(Self)) break ;
ParkCommon (ESelf, 0) ;
}
assert (_OnDeck == ESelf, "invariant") ;
_OnDeck = NULL ;
}
assert (ILocked(), "invariant") ;
return WasOnWaitSet != 0 ; // return true IFF timeout
}
void Monitor::lock (Thread * Self) {
#ifdef CHECK_UNHANDLED_OOPS
if (Self->is_Java_thread()) {
Self->clear_unhandled_oops();
}
#endif // CHECK_UNHANDLED_OOPS
debug_only(check_prelock_state(Self));
assert (_owner != Self , "invariant") ;
assert (_OnDeck != Self->_MutexEvent, "invariant") ;
if (TryFast()) {
Exeunt:
assert (ILocked(), "invariant") ;
assert (owner() == NULL, "invariant");
set_owner (Self);
return ;
}
bool can_sneak = Self->is_VM_thread() && SafepointSynchronize::is_at_safepoint();
if (can_sneak && _owner == NULL) {
_snuck = true;
goto Exeunt ;
}
if (TrySpin (Self)) goto Exeunt ;
check_block_state(Self);
if (Self->is_Java_thread()) {
assert(rank() > Mutex::special, "Potential deadlock with special or lesser rank mutex");
ThreadBlockInVM tbivm ((JavaThread *) Self) ;
ILock (Self) ;
} else {
ILock (Self) ;
}
goto Exeunt ;
}
void Monitor::lock() {
this->lock(Thread::current());
}
void Monitor::lock_without_safepoint_check (Thread * Self) {
assert (_owner != Self, "invariant") ;
ILock (Self) ;
assert (_owner == NULL, "invariant");
set_owner (Self);
}
void Monitor::lock_without_safepoint_check () {
lock_without_safepoint_check (Thread::current()) ;
}
bool Monitor::try_lock() {
Thread * const Self = Thread::current();
debug_only(check_prelock_state(Self));
bool can_sneak = Self->is_VM_thread() && SafepointSynchronize::is_at_safepoint();
if (can_sneak && _owner == NULL) {
set_owner(Self); // Do not need to be atomic, since we are at a safepoint
_snuck = true;
return true;
}
if (TryLock()) {
assert (_owner == NULL, "invariant");
set_owner (Self);
return true;
}
return false;
}
void Monitor::unlock() {
assert (_owner == Thread::current(), "invariant") ;
assert (_OnDeck != Thread::current()->_MutexEvent , "invariant") ;
set_owner (NULL) ;
if (_snuck) {
assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sneak");
_snuck = false;
return ;
}
IUnlock (false) ;
}
void Monitor::jvm_raw_lock() {
assert(rank() == native, "invariant");
if (TryLock()) {
Exeunt:
assert (ILocked(), "invariant") ;
assert (_owner == NULL, "invariant");
_owner = ThreadLocalStorage::thread();
return ;
}
if (TrySpin(NULL)) goto Exeunt ;
ParkEvent * const ESelf = ParkEvent::Allocate(NULL) ;
ESelf->reset() ;
OrderAccess::storeload() ;
if (AcquireOrPush (ESelf)) {
ParkEvent::Release (ESelf) ; // surrender the ParkEvent
goto Exeunt ;
}
for (;;) {
if (_OnDeck == ESelf && TrySpin(NULL)) break ;
ParkCommon (ESelf, 0) ;
}
assert (_OnDeck == ESelf, "invariant") ;
_OnDeck = NULL ;
ParkEvent::Release (ESelf) ; // surrender the ParkEvent
goto Exeunt ;
}
void Monitor::jvm_raw_unlock() {
_owner = NULL ;
if (_snuck) { // ???
assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), "sneak");
_snuck = false;
return ;
}
IUnlock(false) ;
}
bool Monitor::wait(bool no_safepoint_check, long timeout, bool as_suspend_equivalent) {
Thread * const Self = Thread::current() ;
assert (_owner == Self, "invariant") ;
assert (ILocked(), "invariant") ;
guarantee (!as_suspend_equivalent || !no_safepoint_check, "invariant") ;
guarantee (no_safepoint_check || Self->is_Java_thread(), "invariant") ;
#ifdef ASSERT
Monitor * least = get_least_ranked_lock_besides_this(Self->owned_locks());
assert(least != this, "Specification of get_least_... call above");
if (least != NULL && least->rank() <= special) {
tty->print("Attempting to wait on monitor %s/%d while holding"
" lock %s/%d -- possible deadlock",
name(), rank(), least->name(), least->rank());
assert(false, "Shouldn't block(wait) while holding a lock of rank special");
}
#endif // ASSERT
int wait_status ;
set_owner(NULL);
if (no_safepoint_check) {
wait_status = IWait (Self, timeout) ;
} else {
assert (Self->is_Java_thread(), "invariant") ;
JavaThread *jt = (JavaThread *)Self;
ThreadBlockInVM tbivm(jt);
OSThreadWaitState osts(Self->osthread(), false /* not Object.wait() */);
if (as_suspend_equivalent) {
jt->set_suspend_equivalent();
}
wait_status = IWait (Self, timeout) ;
if (as_suspend_equivalent && jt->handle_special_suspend_equivalent_condition()) {
assert (ILocked(), "invariant") ;
IUnlock (true) ;
jt->java_suspend_self();
ILock (Self) ;
assert (ILocked(), "invariant") ;
}
}
assert (ILocked(), "invariant") ;
assert (_owner == NULL, "invariant") ;
set_owner (Self) ;
return wait_status != 0 ; // return true IFF timeout
}
Monitor::~Monitor() {
assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
}
void Monitor::ClearMonitor (Monitor * m, const char *name) {
m->_owner = NULL ;
m->_snuck = false ;
if (name == NULL) {
strcpy(m->_name, "UNKNOWN") ;
} else {
strncpy(m->_name, name, MONITOR_NAME_LEN - 1);
m->_name[MONITOR_NAME_LEN - 1] = '\0';
}
m->_LockWord.FullWord = 0 ;
m->_EntryList = NULL ;
m->_OnDeck = NULL ;
m->_WaitSet = NULL ;
m->_WaitLock[0] = 0 ;
}
Monitor::Monitor() { ClearMonitor(this); }
Monitor::Monitor (int Rank, const char * name, bool allow_vm_block) {
ClearMonitor (this, name) ;
#ifdef ASSERT
_allow_vm_block = allow_vm_block;
_rank = Rank ;
#endif
}
Mutex::~Mutex() {
assert ((UNS(_owner)|UNS(_LockWord.FullWord)|UNS(_EntryList)|UNS(_WaitSet)|UNS(_OnDeck)) == 0, "") ;
}
Mutex::Mutex (int Rank, const char * name, bool allow_vm_block) {
ClearMonitor ((Monitor *) this, name) ;
#ifdef ASSERT
_allow_vm_block = allow_vm_block;
_rank = Rank ;
#endif
}
bool Monitor::owned_by_self() const {
bool ret = _owner == Thread::current();
assert (!ret || _LockWord.Bytes[_LSBINDEX] != 0, "invariant") ;
return ret;
}
void Monitor::print_on_error(outputStream* st) const {
st->print("[" PTR_FORMAT, this);
st->print("] %s", _name);
st->print(" - owner thread: " PTR_FORMAT, _owner);
}
#ifndef PRODUCT
void Monitor::print_on(outputStream* st) const {
st->print_cr("Mutex: [0x%lx/0x%lx] %s - owner: 0x%lx", this, _LockWord.FullWord, _name, _owner);
}
#endif
#ifndef PRODUCT
#ifdef ASSERT
Monitor * Monitor::get_least_ranked_lock(Monitor * locks) {
Monitor *res, *tmp;
for (res = tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp->rank() < res->rank()) {
res = tmp;
}
}
if (!SafepointSynchronize::is_at_safepoint()) {
for (tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp->next() != NULL) {
assert(tmp->rank() == Mutex::native ||
tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?");
}
}
}
return res;
}
Monitor* Monitor::get_least_ranked_lock_besides_this(Monitor* locks) {
Monitor *res, *tmp;
for (res = NULL, tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp != this && (res == NULL || tmp->rank() < res->rank())) {
res = tmp;
}
}
if (!SafepointSynchronize::is_at_safepoint()) {
for (tmp = locks; tmp != NULL; tmp = tmp->next()) {
if (tmp->next() != NULL) {
assert(tmp->rank() == Mutex::native ||
tmp->rank() <= tmp->next()->rank(), "mutex rank anomaly?");
}
}
}
return res;
}
bool Monitor::contains(Monitor* locks, Monitor * lock) {
for (; locks != NULL; locks = locks->next()) {
if (locks == lock)
return true;
}
return false;
}
#endif
void Monitor::set_owner_implementation(Thread *new_owner) {
if (new_owner != NULL) {
assert(new_owner == Thread::current(), "Should I be doing this?");
assert(_owner == NULL, "setting the owner thread of an already owned mutex");
_owner = new_owner; // set the owner
#ifdef ASSERT // Thread::_owned_locks is under the same ifdef
Monitor* locks = get_least_ranked_lock(new_owner->owned_locks());
assert(this->rank() >= 0, "bad lock rank");
if (this->rank() != Mutex::native &&
this->rank() != Mutex::suspend_resume &&
locks != NULL && locks->rank() <= this->rank() &&
!SafepointSynchronize::is_at_safepoint() &&
this != Interrupt_lock && this != ProfileVM_lock &&
!(this == Safepoint_lock && contains(locks, Terminator_lock) &&
SafepointSynchronize::is_synchronizing())) {
new_owner->print_owned_locks();
fatal(err_msg("acquiring lock %s/%d out of order with lock %s/%d -- "
"possible deadlock", this->name(), this->rank(),
locks->name(), locks->rank()));
}
this->_next = new_owner->_owned_locks;
new_owner->_owned_locks = this;
#endif
} else {
Thread* old_owner = _owner;
debug_only(_last_owner = old_owner);
assert(old_owner != NULL, "removing the owner thread of an unowned mutex");
assert(old_owner == Thread::current(), "removing the owner thread of an unowned mutex");
_owner = NULL; // set the owner
#ifdef ASSERT
Monitor *locks = old_owner->owned_locks();
Monitor *prev = NULL;
bool found = false;
for (; locks != NULL; prev = locks, locks = locks->next()) {
if (locks == this) {
found = true;
break;
}
}
assert(found, "Removing a lock not owned");
if (prev == NULL) {
old_owner->_owned_locks = _next;
} else {
prev->_next = _next;
}
_next = NULL;
#endif
}
}
void Monitor::check_prelock_state(Thread *thread) {
assert((!thread->is_Java_thread() || ((JavaThread *)thread)->thread_state() == _thread_in_vm)
|| rank() == Mutex::special, "wrong thread state for using locks");
if (StrictSafepointChecks) {
if (thread->is_VM_thread() && !allow_vm_block()) {
fatal(err_msg("VM thread using lock %s (not allowed to block on)",
name()));
}
debug_only(if (rank() != Mutex::special) \
thread->check_for_valid_safepoint_state(false);)
}
assert(!os::ThreadCrashProtection::is_crash_protected(thread),
"locking not allowed when crash protection is set");
}
void Monitor::check_block_state(Thread *thread) {
if (!_allow_vm_block && thread->is_VM_thread()) {
warning("VM thread blocked on lock");
print();
BREAKPOINT;
}
assert(_owner != thread, "deadlock: blocking on monitor owned by current thread");
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/runtime/mutex.hpp
#ifndef SHARE_VM_RUNTIME_MUTEX_HPP
#define SHARE_VM_RUNTIME_MUTEX_HPP
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
#include "utilities/histogram.hpp"
union SplitWord { // full-word with separately addressable LSB
volatile intptr_t FullWord ;
volatile void * Address ;
volatile jbyte Bytes [sizeof(intptr_t)] ;
} ;
#ifdef VM_LITTLE_ENDIAN
#define _LSBINDEX 0
#else
#define _LSBINDEX (sizeof(intptr_t)-1)
#endif
class ParkEvent ;
static const int MONITOR_NAME_LEN = 64;
class Monitor : public CHeapObj<mtInternal> {
public:
enum lock_types {
event,
special,
suspend_resume,
leaf = suspend_resume + 2,
safepoint = leaf + 10,
barrier = safepoint + 1,
nonleaf = barrier + 1,
max_nonleaf = nonleaf + 900,
native = max_nonleaf + 1
};
protected: // Monitor-Mutex metadata
SplitWord _LockWord ; // Contention queue (cxq) colocated with Lock-byte
enum LockWordBits { _LBIT=1 } ;
Thread * volatile _owner; // The owner of the lock
ParkEvent * volatile _EntryList ; // List of threads waiting for entry
ParkEvent * volatile _OnDeck ; // heir-presumptive
volatile intptr_t _WaitLock [1] ; // Protects _WaitSet
ParkEvent * volatile _WaitSet ; // LL of ParkEvents
volatile bool _snuck; // Used for sneaky locking (evil).
int NotifyCount ; // diagnostic assist
char _name[MONITOR_NAME_LEN]; // Name of mutex
#ifndef PRODUCT
bool _allow_vm_block;
debug_only(int _rank;) // rank (to avoid/detect potential deadlocks)
debug_only(Monitor * _next;) // Used by a Thread to link up owned locks
debug_only(Thread* _last_owner;) // the last thread to own the lock
debug_only(static bool contains(Monitor * locks, Monitor * lock);)
debug_only(static Monitor * get_least_ranked_lock(Monitor * locks);)
debug_only(Monitor * get_least_ranked_lock_besides_this(Monitor * locks);)
#endif
void set_owner_implementation(Thread* owner) PRODUCT_RETURN;
void check_prelock_state (Thread* thread) PRODUCT_RETURN;
void check_block_state (Thread* thread) PRODUCT_RETURN;
public:
enum {
_no_safepoint_check_flag = true,
_allow_vm_block_flag = true,
_as_suspend_equivalent_flag = true
};
enum WaitResults {
CONDVAR_EVENT, // Wait returned because of condition variable notification
INTERRUPT_EVENT, // Wait returned because waiting thread was interrupted
NUMBER_WAIT_RESULTS
};
private:
int TrySpin (Thread * Self) ;
int TryLock () ;
int TryFast () ;
int AcquireOrPush (ParkEvent * ev) ;
void IUnlock (bool RelaxAssert) ;
void ILock (Thread * Self) ;
int IWait (Thread * Self, jlong timo);
int ILocked () ;
protected:
static void ClearMonitor (Monitor * m, const char* name = NULL) ;
Monitor() ;
public:
Monitor(int rank, const char *name, bool allow_vm_block=false);
~Monitor();
bool wait(bool no_safepoint_check = !_no_safepoint_check_flag,
long timeout = 0,
bool as_suspend_equivalent = !_as_suspend_equivalent_flag);
bool notify();
bool notify_all();
void lock(); // prints out warning if VM thread blocks
void lock(Thread *thread); // overloaded with current thread
void unlock();
bool is_locked() const { return _owner != NULL; }
bool try_lock(); // Like lock(), but unblocking. It returns false instead
void lock_without_safepoint_check();
void lock_without_safepoint_check (Thread * Self) ;
Thread* owner() const { return _owner; }
bool owned_by_self() const;
void jvm_raw_lock();
void jvm_raw_unlock();
const char *name() const { return _name; }
void print_on_error(outputStream* st) const;
#ifndef PRODUCT
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
debug_only(int rank() const { return _rank; })
bool allow_vm_block() { return _allow_vm_block; }
debug_only(Monitor *next() const { return _next; })
debug_only(void set_next(Monitor *next) { _next = next; })
#endif
void set_owner(Thread* owner) {
#ifndef PRODUCT
set_owner_implementation(owner);
debug_only(void verify_Monitor(Thread* thr));
#else
_owner = owner;
#endif
}
};
class Mutex : public Monitor { // degenerate Monitor
public:
Mutex (int rank, const char *name, bool allow_vm_block=false);
~Mutex () ;
private:
bool notify () { ShouldNotReachHere(); return false; }
bool notify_all() { ShouldNotReachHere(); return false; }
bool wait (bool no_safepoint_check, long timeout, bool as_suspend_equivalent) {
ShouldNotReachHere() ;
return false ;
}
};
#endif // SHARE_VM_RUNTIME_MUTEX_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/mutexLocker.cpp
#include "precompiled.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
#include "runtime/vmThread.hpp"
Mutex* Patching_lock = NULL;
Monitor* SystemDictionary_lock = NULL;
Mutex* PackageTable_lock = NULL;
Mutex* CompiledIC_lock = NULL;
Mutex* InlineCacheBuffer_lock = NULL;
Mutex* VMStatistic_lock = NULL;
Mutex* JNIGlobalHandle_lock = NULL;
Mutex* JNIHandleBlockFreeList_lock = NULL;
Mutex* MemberNameTable_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_lock = NULL;
Monitor* JNICritical_lock = NULL;
Mutex* JvmtiThreadState_lock = NULL;
Monitor* JvmtiPendingEvent_lock = NULL;
Monitor* Heap_lock = NULL;
Mutex* ExpandHeap_lock = NULL;
Mutex* AdapterHandlerLibrary_lock = NULL;
Mutex* SignatureHandlerLibrary_lock = NULL;
Mutex* VtableStubs_lock = NULL;
Mutex* SymbolTable_lock = NULL;
Mutex* StringTable_lock = NULL;
Monitor* StringDedupQueue_lock = NULL;
Mutex* StringDedupTable_lock = NULL;
Mutex* CodeCache_lock = NULL;
Mutex* MethodData_lock = NULL;
Mutex* RetData_lock = NULL;
Monitor* VMOperationQueue_lock = NULL;
Monitor* VMOperationRequest_lock = NULL;
Monitor* Safepoint_lock = NULL;
Monitor* SerializePage_lock = NULL;
Monitor* Threads_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
Monitor* SLT_lock = NULL;
Monitor* iCMS_lock = NULL;
Monitor* FullGCCount_lock = NULL;
Monitor* CMark_lock = NULL;
Mutex* CMRegionStack_lock = NULL;
Mutex* SATB_Q_FL_lock = NULL;
Monitor* SATB_Q_CBL_mon = NULL;
Mutex* Shared_SATB_Q_lock = NULL;
Mutex* DirtyCardQ_FL_lock = NULL;
Monitor* DirtyCardQ_CBL_mon = NULL;
Mutex* Shared_DirtyCardQ_lock = NULL;
Mutex* ParGCRareEvent_lock = NULL;
Mutex* EvacFailureStack_lock = NULL;
Mutex* DerivedPointerTableGC_lock = NULL;
Mutex* Compile_lock = NULL;
Monitor* MethodCompileQueue_lock = NULL;
Monitor* CompileThread_lock = NULL;
Mutex* CompileTaskAlloc_lock = NULL;
Mutex* CompileStatistics_lock = NULL;
Mutex* MultiArray_lock = NULL;
Monitor* Terminator_lock = NULL;
Monitor* BeforeExit_lock = NULL;
Monitor* Notify_lock = NULL;
Monitor* Interrupt_lock = NULL;
Monitor* ProfileVM_lock = NULL;
Mutex* ProfilePrint_lock = NULL;
Mutex* ExceptionCache_lock = NULL;
Monitor* ObjAllocPost_lock = NULL;
Mutex* OsrList_lock = NULL;
#ifndef PRODUCT
Mutex* FullGCALot_lock = NULL;
#endif
Mutex* Debug1_lock = NULL;
Mutex* Debug2_lock = NULL;
Mutex* Debug3_lock = NULL;
Mutex* tty_lock = NULL;
Mutex* RawMonitor_lock = NULL;
Mutex* PerfDataMemAlloc_lock = NULL;
Mutex* PerfDataManager_lock = NULL;
Mutex* OopMapCacheAlloc_lock = NULL;
Mutex* FreeList_lock = NULL;
Monitor* SecondaryFreeList_lock = NULL;
Mutex* OldSets_lock = NULL;
Monitor* RootRegionScan_lock = NULL;
Mutex* MMUTracker_lock = NULL;
Monitor* GCTaskManager_lock = NULL;
Mutex* Management_lock = NULL;
Monitor* Service_lock = NULL;
Monitor* PeriodicTask_lock = NULL;
Monitor* RedefineClasses_lock = NULL;
#ifdef INCLUDE_JFR
Mutex* JfrStacktrace_lock = NULL;
Monitor* JfrMsg_lock = NULL;
Mutex* JfrBuffer_lock = NULL;
Mutex* JfrStream_lock = NULL;
Mutex* JfrThreadGroups_lock = NULL;
#ifndef SUPPORTS_NATIVE_CX8
Mutex* JfrCounters_lock = NULL;
#endif
#endif
#ifndef SUPPORTS_NATIVE_CX8
Mutex* UnsafeJlong_lock = NULL;
#endif
#define MAX_NUM_MUTEX 128
static Monitor * _mutex_array[MAX_NUM_MUTEX];
static int _num_mutex;
#ifdef ASSERT
void assert_locked_or_safepoint(const Monitor * lock) {
if (IgnoreLockingAssertions) return;
assert(lock != NULL, "Need non-NULL lock");
if (lock->owned_by_self()) return;
if (SafepointSynchronize::is_at_safepoint()) return;
if (!Universe::is_fully_initialized()) return;
VM_Operation* op = VMThread::vm_operation();
if (op != NULL && op->calling_thread() == lock->owner()) return;
fatal(err_msg("must own lock %s", lock->name()));
}
void assert_lock_strong(const Monitor * lock) {
if (IgnoreLockingAssertions) return;
assert(lock != NULL, "Need non-NULL lock");
if (lock->owned_by_self()) return;
fatal(err_msg("must own lock %s", lock->name()));
}
#endif
#define def(var, type, pri, vm_block) { \
var = new type(Mutex::pri, #var, vm_block); \
assert(_num_mutex < MAX_NUM_MUTEX, \
"increase MAX_NUM_MUTEX"); \
_mutex_array[_num_mutex++] = var; \
}
void mutex_init() {
def(tty_lock , Mutex , event, true ); // allow to lock in VM
def(CGC_lock , Monitor, special, true ); // coordinate between fore- and background GC
def(STS_lock , Monitor, leaf, true );
if (UseConcMarkSweepGC) {
def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification
}
if (UseConcMarkSweepGC || UseG1GC) {
def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent
}
if (UseG1GC) {
def(CMark_lock , Monitor, nonleaf, true ); // coordinate concurrent mark thread
def(CMRegionStack_lock , Mutex, leaf, true );
def(SATB_Q_FL_lock , Mutex , special, true );
def(SATB_Q_CBL_mon , Monitor, nonleaf, true );
def(Shared_SATB_Q_lock , Mutex, nonleaf, true );
def(DirtyCardQ_FL_lock , Mutex , special, true );
def(DirtyCardQ_CBL_mon , Monitor, nonleaf, true );
def(Shared_DirtyCardQ_lock , Mutex, nonleaf, true );
def(FreeList_lock , Mutex, leaf , true );
def(SecondaryFreeList_lock , Monitor, leaf , true );
def(OldSets_lock , Mutex , leaf , true );
def(RootRegionScan_lock , Monitor, leaf , true );
def(MMUTracker_lock , Mutex , leaf , true );
def(EvacFailureStack_lock , Mutex , nonleaf , true );
def(StringDedupQueue_lock , Monitor, leaf, true );
def(StringDedupTable_lock , Mutex , leaf, true );
}
def(ParGCRareEvent_lock , Mutex , leaf , true );
def(DerivedPointerTableGC_lock , Mutex, leaf, true );
def(CodeCache_lock , Mutex , special, true );
def(Interrupt_lock , Monitor, special, true ); // used for interrupt processing
def(RawMonitor_lock , Mutex, special, true );
def(OopMapCacheAlloc_lock , Mutex, leaf, true ); // used for oop_map_cache allocation.
def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching.
def(ObjAllocPost_lock , Monitor, special, false);
def(Service_lock , Monitor, special, true ); // used for service thread operations
def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs.
def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread
def(PackageTable_lock , Mutex , leaf, false);
def(InlineCacheBuffer_lock , Mutex , leaf, true );
def(VMStatistic_lock , Mutex , leaf, false);
def(ExpandHeap_lock , Mutex , leaf, true ); // Used during compilation by VM thread
def(JNIHandleBlockFreeList_lock , Mutex , leaf, true ); // handles are used by VM thread
def(SignatureHandlerLibrary_lock , Mutex , leaf, false);
def(SymbolTable_lock , Mutex , leaf+2, true );
def(StringTable_lock , Mutex , leaf, true );
def(ProfilePrint_lock , Mutex , leaf, false); // serial profile printing
def(ExceptionCache_lock , Mutex , leaf, false); // serial profile printing
def(OsrList_lock , Mutex , leaf, true );
def(Debug1_lock , Mutex , leaf, true );
#ifndef PRODUCT
def(FullGCALot_lock , Mutex , leaf, false); // a lock to make FullGCALot MT safe
#endif
def(BeforeExit_lock , Monitor, leaf, true );
def(PerfDataMemAlloc_lock , Mutex , leaf, true ); // used for allocating PerfData memory for performance data
def(PerfDataManager_lock , Mutex , leaf, true ); // used for synchronized access to PerfDataManager resources
def(Safepoint_lock , Monitor, safepoint, true ); // locks SnippetCache_lock/Threads_lock
def(Threads_lock , Monitor, barrier, true );
def(VMOperationQueue_lock , Monitor, nonleaf, true ); // VM_thread allowed to block on these
def(VMOperationRequest_lock , Monitor, nonleaf, true );
def(RetData_lock , Mutex , nonleaf, false);
def(Terminator_lock , Monitor, nonleaf, true );
def(VtableStubs_lock , Mutex , nonleaf, true );
def(Notify_lock , Monitor, nonleaf, true );
def(JNIGlobalHandle_lock , Mutex , nonleaf, true ); // locks JNIHandleBlockFreeList_lock
def(JNICritical_lock , Monitor, nonleaf, true ); // used for JNI critical regions
def(AdapterHandlerLibrary_lock , Mutex , nonleaf, true);
if (UseConcMarkSweepGC) {
def(SLT_lock , Monitor, nonleaf, false );
}
def(Heap_lock , Monitor, nonleaf+1, false);
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock
def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true );
def(CompileStatistics_lock , Mutex , nonleaf+2, false);
def(MultiArray_lock , Mutex , nonleaf+2, false); // locks SymbolTable_lock
def(JvmtiThreadState_lock , Mutex , nonleaf+2, false); // Used by JvmtiThreadState/JvmtiEventController
def(JvmtiPendingEvent_lock , Monitor, nonleaf, false); // Used by JvmtiCodeBlobEvents
def(Management_lock , Mutex , nonleaf+2, false); // used for JVM management
def(Compile_lock , Mutex , nonleaf+3, true );
def(MethodData_lock , Mutex , nonleaf+3, false);
def(MethodCompileQueue_lock , Monitor, nonleaf+4, true );
def(Debug2_lock , Mutex , nonleaf+4, true );
def(Debug3_lock , Mutex , nonleaf+4, true );
def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
def(CompileThread_lock , Monitor, nonleaf+5, false );
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
def(RedefineClasses_lock , Monitor, nonleaf+5, true);
#if INCLUDE_JFR
def(JfrMsg_lock , Monitor, leaf, true);
def(JfrBuffer_lock , Mutex, leaf, true);
def(JfrThreadGroups_lock , Mutex, leaf, true);
def(JfrStream_lock , Mutex, nonleaf, true);
def(JfrStacktrace_lock , Mutex, special, true);
#ifndef SUPPORTS_NATIVE_CX8
def(JfrCounters_lock , Mutex, special, false);
#endif
#endif
#ifndef SUPPORTS_NATIVE_CX8
def(UnsafeJlong_lock , Mutex, special, false);
#endif
}
GCMutexLocker::GCMutexLocker(Monitor * mutex) {
if (SafepointSynchronize::is_at_safepoint()) {
_locked = false;
} else {
_mutex = mutex;
_locked = true;
_mutex->lock();
}
}
void print_owned_locks_on_error(outputStream* st) {
st->print("VM Mutex/Monitor currently owned by a thread: ");
bool none = true;
for (int i = 0; i < _num_mutex; i++) {
if (_mutex_array[i]->owner() != NULL) {
if (none) {
st->print_cr(" ([mutex/lock_event])");
none = false;
}
_mutex_array[i]->print_on_error(st);
st->cr();
}
}
if (none) st->print_cr("None");
}
C:\hotspot-69087d08d473\src\share\vm/runtime/mutexLocker.hpp
#ifndef SHARE_VM_RUNTIME_MUTEXLOCKER_HPP
#define SHARE_VM_RUNTIME_MUTEXLOCKER_HPP
#include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_aix
# include "os_aix.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code
extern Monitor* SystemDictionary_lock; // a lock on the system dictonary
extern Mutex* PackageTable_lock; // a lock on the class loader package table
extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access
extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in
extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data
extern Monitor* JvmtiPendingEvent_lock; // a lock on the JVMTI pending events list
extern Monitor* Heap_lock; // a lock on the heap
extern Mutex* ExpandHeap_lock; // a lock on expanding the heap
extern Mutex* AdapterHandlerLibrary_lock; // a lock on the AdapterHandlerLibrary
extern Mutex* SignatureHandlerLibrary_lock; // a lock on the SignatureHandlerLibrary
extern Mutex* VtableStubs_lock; // a lock on the VtableStubs
extern Mutex* SymbolTable_lock; // a lock on the symbol table
extern Mutex* StringTable_lock; // a lock on the interned string table
extern Monitor* StringDedupQueue_lock; // a lock on the string deduplication queue
extern Mutex* StringDedupTable_lock; // a lock on the string deduplication table
extern Mutex* CodeCache_lock; // a lock on the CodeCache, rank is special, use MutexLockerEx
extern Mutex* MethodData_lock; // a lock on installation of method data
extern Mutex* RetData_lock; // a lock on installation of RetData inside method data
extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derived pointer table
extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute
extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate
extern Monitor* Safepoint_lock; // a lock used by the safepoint abstraction
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
extern Monitor* CGC_lock; // used for coordination between
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL
extern Monitor* iCMS_lock; // CMS incremental mode start/stop notification
extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc
extern Monitor* CMark_lock; // used for concurrent mark thread coordination
extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack
extern Mutex* SATB_Q_FL_lock; // Protects SATB Q
extern Monitor* SATB_Q_CBL_mon; // Protects SATB Q
extern Mutex* Shared_SATB_Q_lock; // Lock protecting SATB
extern Mutex* DirtyCardQ_FL_lock; // Protects dirty card Q
extern Monitor* DirtyCardQ_CBL_mon; // Protects dirty card Q
extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card
extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops.
extern Mutex* EvacFailureStack_lock; // guards the evac failure scan stack
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued
extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization
extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated
extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics
extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
extern Monitor* Terminator_lock; // a lock used to guard termination of the vm
extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks
extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm
extern Monitor* Interrupt_lock; // a lock used for condition variable mediated interrupt processing
extern Monitor* ProfileVM_lock; // a lock used for profiling the VMThread
extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles
extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates
extern Mutex* OsrList_lock; // a lock used to serialize access to OSR queues
#ifndef PRODUCT
extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe
#endif // PRODUCT
extern Mutex* Debug1_lock; // A bunch of pre-allocated locks that can be used for tracing
extern Mutex* Debug2_lock; // down synchronization related bugs!
extern Mutex* Debug3_lock;
extern Mutex* RawMonitor_lock;
extern Mutex* PerfDataMemAlloc_lock; // a lock on the allocator for PerfData memory for performance data
extern Mutex* PerfDataManager_lock; // a long on access to PerfDataManager resources
extern Mutex* ParkerFreeList_lock;
extern Mutex* OopMapCacheAlloc_lock; // protects allocation of oop_map caches
extern Mutex* FreeList_lock; // protects the free region list during safepoints
extern Monitor* SecondaryFreeList_lock; // protects the secondary free region list
extern Mutex* OldSets_lock; // protects the old region sets
extern Monitor* RootRegionScan_lock; // used to notify that the CM threads have finished scanning the IM snapshot regions
extern Mutex* MMUTracker_lock; // protects the MMU
extern Mutex* Management_lock; // a lock used to serialize JVM management
extern Monitor* Service_lock; // a lock used for service thread operation
extern Monitor* PeriodicTask_lock; // protects the periodic task structure
extern Monitor* RedefineClasses_lock; // locks classes from parallel redefinition
#if INCLUDE_JFR
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
extern Monitor* JfrMsg_lock; // protects JFR messaging
extern Mutex* JfrBuffer_lock; // protects JFR buffer operations
extern Mutex* JfrStream_lock; // protects JFR stream access
extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups
#ifndef SUPPORTS_NATIVE_CX8
extern Mutex* JfrCounters_lock; // provides atomic updates of JFR counters
#endif
#endif
#ifndef SUPPORTS_NATIVE_CX8
extern Mutex* UnsafeJlong_lock; // provides Unsafe atomic updates to jlongs on platforms that don't support cx8
#endif
void print_owned_locks_on_error(outputStream* st);
char *lock_name(Mutex *mutex);
class MutexLocker: StackObj {
private:
Monitor * _mutex;
public:
MutexLocker(Monitor * mutex) {
assert(mutex->rank() != Mutex::special,
"Special ranked mutex should only use MutexLockerEx");
_mutex = mutex;
_mutex->lock();
}
MutexLocker(Monitor * mutex, Thread *thread) {
assert(mutex->rank() != Mutex::special,
"Special ranked mutex should only use MutexLockerEx");
_mutex = mutex;
_mutex->lock(thread);
}
~MutexLocker() {
_mutex->unlock();
}
};
#ifdef ASSERT
void assert_locked_or_safepoint(const Monitor * lock);
void assert_lock_strong(const Monitor * lock);
#else
#define assert_locked_or_safepoint(lock)
#define assert_lock_strong(lock)
#endif
class MutexLockerEx: public StackObj {
private:
Monitor * _mutex;
public:
MutexLockerEx(Monitor * mutex, bool no_safepoint_check = !Mutex::_no_safepoint_check_flag) {
_mutex = mutex;
if (_mutex != NULL) {
assert(mutex->rank() > Mutex::special || no_safepoint_check,
"Mutexes with rank special or lower should not do safepoint checks");
if (no_safepoint_check)
_mutex->lock_without_safepoint_check();
else
_mutex->lock();
}
}
~MutexLockerEx() {
if (_mutex != NULL) {
_mutex->unlock();
}
}
};
class MonitorLockerEx: public MutexLockerEx {
private:
Monitor * _monitor;
public:
MonitorLockerEx(Monitor* monitor,
bool no_safepoint_check = !Mutex::_no_safepoint_check_flag):
MutexLockerEx(monitor, no_safepoint_check),
_monitor(monitor) {
}
~MonitorLockerEx() {
#ifdef ASSERT
if (_monitor != NULL) {
assert_lock_strong(_monitor);
}
#endif // ASSERT
}
bool wait(bool no_safepoint_check = !Mutex::_no_safepoint_check_flag,
long timeout = 0,
bool as_suspend_equivalent = !Mutex::_as_suspend_equivalent_flag) {
if (_monitor != NULL) {
return _monitor->wait(no_safepoint_check, timeout, as_suspend_equivalent);
}
return false;
}
bool notify_all() {
if (_monitor != NULL) {
return _monitor->notify_all();
}
return true;
}
bool notify() {
if (_monitor != NULL) {
return _monitor->notify();
}
return true;
}
};
class GCMutexLocker: public StackObj {
private:
Monitor * _mutex;
bool _locked;
public:
GCMutexLocker(Monitor * mutex);
~GCMutexLocker() { if (_locked) _mutex->unlock(); }
};
class MutexUnlocker: StackObj {
private:
Monitor * _mutex;
public:
MutexUnlocker(Monitor * mutex) {
_mutex = mutex;
_mutex->unlock();
}
~MutexUnlocker() {
_mutex->lock();
}
};
class MutexUnlockerEx: StackObj {
private:
Monitor * _mutex;
bool _no_safepoint_check;
public:
MutexUnlockerEx(Monitor * mutex, bool no_safepoint_check = !Mutex::_no_safepoint_check_flag) {
_mutex = mutex;
_no_safepoint_check = no_safepoint_check;
_mutex->unlock();
}
~MutexUnlockerEx() {
if (_no_safepoint_check == Mutex::_no_safepoint_check_flag) {
_mutex->lock_without_safepoint_check();
} else {
_mutex->lock();
}
}
};
#ifndef PRODUCT
class VerifyMutexLocker: StackObj {
private:
Monitor * _mutex;
bool _reentrant;
public:
VerifyMutexLocker(Monitor * mutex) {
_mutex = mutex;
_reentrant = mutex->owned_by_self();
if (!_reentrant) {
FlagSetting fs(StrictSafepointChecks, false);
_mutex->lock();
}
}
~VerifyMutexLocker() {
if (!_reentrant) {
_mutex->unlock();
}
}
};
#endif
#endif // SHARE_VM_RUNTIME_MUTEXLOCKER_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/objectMonitor.cpp
#include "precompiled.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "memory/resourceArea.hpp"
#include "oops/markOop.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/osThread.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "services/threadService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
#if INCLUDE_JFR
#include "jfr/support/jfrFlush.hpp"
#endif
#if defined(__GNUC__) && !defined(IA64) && !defined(PPC64)
#define ATTR __attribute__((noinline))
#else
#define ATTR
#endif
#ifdef DTRACE_ENABLED
#define DTRACE_MONITOR_PROBE_COMMON(obj, thread) \
char* bytes = NULL; \
int len = 0; \
jlong jtid = SharedRuntime::get_java_tid(thread); \
Symbol* klassname = ((oop)obj)->klass()->name(); \
if (klassname != NULL) { \
bytes = (char*)klassname->bytes(); \
len = klassname->utf8_length(); \
}
#ifndef USDT2
HS_DTRACE_PROBE_DECL4(hotspot, monitor__notify,
jlong, uintptr_t, char*, int);
HS_DTRACE_PROBE_DECL4(hotspot, monitor__notifyAll,
jlong, uintptr_t, char*, int);
HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__enter,
jlong, uintptr_t, char*, int);
HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__entered,
jlong, uintptr_t, char*, int);
HS_DTRACE_PROBE_DECL4(hotspot, monitor__contended__exit,
jlong, uintptr_t, char*, int);
#define DTRACE_MONITOR_WAIT_PROBE(monitor, obj, thread, millis) \
{ \
if (DTraceMonitorProbes) { \
DTRACE_MONITOR_PROBE_COMMON(obj, thread); \
HS_DTRACE_PROBE5(hotspot, monitor__wait, jtid, \
(monitor), bytes, len, (millis)); \
} \
}
#define DTRACE_MONITOR_PROBE(probe, monitor, obj, thread) \
{ \
if (DTraceMonitorProbes) { \
DTRACE_MONITOR_PROBE_COMMON(obj, thread); \
HS_DTRACE_PROBE4(hotspot, monitor__##probe, jtid, \
(uintptr_t)(monitor), bytes, len); \
} \
}
#else /* USDT2 */
#define DTRACE_MONITOR_WAIT_PROBE(monitor, obj, thread, millis) \
{ \
if (DTraceMonitorProbes) { \
DTRACE_MONITOR_PROBE_COMMON(obj, thread); \
HOTSPOT_MONITOR_WAIT(jtid, \
(monitor), bytes, len, (millis)); \
} \
}
#define HOTSPOT_MONITOR_contended__enter HOTSPOT_MONITOR_CONTENDED_ENTER
#define HOTSPOT_MONITOR_contended__entered HOTSPOT_MONITOR_CONTENDED_ENTERED
#define HOTSPOT_MONITOR_contended__exit HOTSPOT_MONITOR_CONTENDED_EXIT
#define HOTSPOT_MONITOR_notify HOTSPOT_MONITOR_NOTIFY
#define HOTSPOT_MONITOR_notifyAll HOTSPOT_MONITOR_NOTIFYALL
#define DTRACE_MONITOR_PROBE(probe, monitor, obj, thread) \
{ \
if (DTraceMonitorProbes) { \
DTRACE_MONITOR_PROBE_COMMON(obj, thread); \
HOTSPOT_MONITOR_##probe(jtid, \
(uintptr_t)(monitor), bytes, len); \
} \
}
#endif /* USDT2 */
#else // ndef DTRACE_ENABLED
#define DTRACE_MONITOR_WAIT_PROBE(obj, thread, millis, mon) {;}
#define DTRACE_MONITOR_PROBE(probe, obj, thread, mon) {;}
#endif // ndef DTRACE_ENABLED
int ObjectMonitor::Knob_Verbose = 0 ;
int ObjectMonitor::Knob_SpinLimit = 5000 ; // derived by an external tool -
static int Knob_LogSpins = 0 ; // enable jvmstat tally for spins
static int Knob_HandOff = 0 ;
static int Knob_ReportSettings = 0 ;
static int Knob_SpinBase = 0 ; // Floor AKA SpinMin
static int Knob_SpinBackOff = 0 ; // spin-loop backoff
static int Knob_CASPenalty = -1 ; // Penalty for failed CAS
static int Knob_OXPenalty = -1 ; // Penalty for observed _owner change
static int Knob_SpinSetSucc = 1 ; // spinners set the _succ field
static int Knob_SpinEarly = 1 ;
static int Knob_SuccEnabled = 1 ; // futile wake throttling
static int Knob_SuccRestrict = 0 ; // Limit successors + spinners to at-most-one
static int Knob_MaxSpinners = -1 ; // Should be a function of # CPUs
static int Knob_Bonus = 100 ; // spin success bonus
static int Knob_BonusB = 100 ; // spin success bonus
static int Knob_Penalty = 200 ; // spin failure penalty
static int Knob_Poverty = 1000 ;
static int Knob_SpinAfterFutile = 1 ; // Spin after returning from park()
static int Knob_FixedSpin = 0 ;
static int Knob_OState = 3 ; // Spinner checks thread state of _owner
static int Knob_UsePause = 1 ;
static int Knob_ExitPolicy = 0 ;
static int Knob_PreSpin = 10 ; // 20-100 likely better
static int Knob_ResetEvent = 0 ;
static int BackOffMask = 0 ;
static int Knob_FastHSSEC = 0 ;
static int Knob_MoveNotifyee = 2 ; // notify() - disposition of notifyee
static int Knob_QMode = 0 ; // EntryList-cxq policy - queue discipline
static volatile int InitDone = 0 ;
#define TrySpin TrySpin_VaryDuration
bool ObjectMonitor::try_enter(Thread* THREAD) {
if (THREAD != _owner) {
if (THREAD->is_lock_owned ((address)_owner)) {
assert(_recursions == 0, "internal state error");
_owner = THREAD ;
_recursions = 1 ;
OwnerIsThread = 1 ;
return true;
}
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return false;
}
return true;
} else {
_recursions++;
return true;
}
}
void ATTR ObjectMonitor::enter(TRAPS) {
Thread * const Self = THREAD ;
void * cur ;
cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
if (cur == NULL) {
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self, "invariant") ;
return ;
}
if (cur == Self) {
_recursions ++ ;
return ;
}
if (Self->is_lock_owned ((address)cur)) {
assert (_recursions == 0, "internal state error");
_recursions = 1 ;
_owner = Self ;
OwnerIsThread = 1 ;
return ;
}
assert (Self->_Stalled == 0, "invariant") ;
Self->_Stalled = intptr_t(this) ;
if (Knob_SpinEarly && TrySpin (Self) > 0) {
assert (_owner == Self , "invariant") ;
assert (_recursions == 0 , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
Self->_Stalled = 0 ;
return ;
}
assert (_owner != Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (Self->is_Java_thread() , "invariant") ;
JavaThread * jt = (JavaThread *) Self ;
assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
assert (jt->thread_state() != _thread_blocked , "invariant") ;
assert (this->object() != NULL , "invariant") ;
assert (_count >= 0, "invariant") ;
Atomic::inc_ptr(&_count);
JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
EventJavaMonitorEnter event;
if (event.should_commit()) {
event.set_monitorClass(((oop)this->object())->klass());
event.set_address((uintptr_t)(this->object_addr()));
}
{ // Change java thread status to indicate blocked on monitor enter.
JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
Self->set_current_pending_monitor(this);
DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_enter()) {
JvmtiExport::post_monitor_contended_enter(jt, this);
}
OSThreadContendState osts(Self->osthread());
ThreadBlockInVM tbivm(jt);
for (;;) {
jt->set_suspend_equivalent();
EnterI (THREAD) ;
if (!ExitSuspendEquivalent(jt)) break ;
_recursions = 0 ;
_succ = NULL ;
exit (false, Self) ;
jt->java_suspend_self();
}
Self->set_current_pending_monitor(NULL);
}
Atomic::dec_ptr(&_count);
assert (_count >= 0, "invariant") ;
Self->_Stalled = 0 ;
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_entered()) {
JvmtiExport::post_monitor_contended_entered(jt, this);
}
if (event.should_commit()) {
event.set_previousOwner((uintptr_t)_previous_owner_tid);
event.commit();
}
if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
}
}
int ObjectMonitor::TryLock (Thread * Self) {
for (;;) {
void * own = _owner ;
if (own != NULL) return 0 ;
if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
assert (_recursions == 0, "invariant") ;
assert (_owner == Self, "invariant") ;
return 1 ;
}
if (true) return -1 ;
}
}
void ATTR ObjectMonitor::EnterI (TRAPS) {
Thread * Self = THREAD ;
assert (Self->is_Java_thread(), "invariant") ;
assert (((JavaThread *) Self)->thread_state() == _thread_blocked , "invariant") ;
if (TryLock (Self) > 0) {
assert (_succ != Self , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_Responsible != Self , "invariant") ;
return ;
}
DeferredInitialize () ;
if (TrySpin (Self) > 0) {
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (_Responsible != Self , "invariant") ;
return ;
}
assert (_succ != Self , "invariant") ;
assert (_owner != Self , "invariant") ;
assert (_Responsible != Self , "invariant") ;
ObjectWaiter node(Self) ;
Self->_ParkEvent->reset() ;
node._prev = (ObjectWaiter *) 0xBAD ;
node.TState = ObjectWaiter::TS_CXQ ;
ObjectWaiter * nxt ;
for (;;) {
node._next = nxt = _cxq ;
if (Atomic::cmpxchg_ptr (&node, &_cxq, nxt) == nxt) break ;
if (TryLock (Self) > 0) {
assert (_succ != Self , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_Responsible != Self , "invariant") ;
return ;
}
}
if ((SyncFlags & 16) == 0 && nxt == NULL && _EntryList == NULL) {
Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
}
TEVENT (Inflated enter - Contention) ;
int nWakeups = 0 ;
int RecheckInterval = 1 ;
for (;;) {
if (TryLock (Self) > 0) break ;
assert (_owner != Self, "invariant") ;
if ((SyncFlags & 2) && _Responsible == NULL) {
Atomic::cmpxchg_ptr (Self, &_Responsible, NULL) ;
}
if (_Responsible == Self || (SyncFlags & 1)) {
TEVENT (Inflated enter - park TIMED) ;
Self->_ParkEvent->park ((jlong) RecheckInterval) ;
RecheckInterval *= 8 ;
if (RecheckInterval > 1000) RecheckInterval = 1000 ;
} else {
TEVENT (Inflated enter - park UNTIMED) ;
Self->_ParkEvent->park() ;
}
if (TryLock(Self) > 0) break ;
TEVENT (Inflated enter - Futile wakeup) ;
if (ObjectMonitor::_sync_FutileWakeups != NULL) {
ObjectMonitor::_sync_FutileWakeups->inc() ;
}
++ nWakeups ;
if ((Knob_SpinAfterFutile & 1) && TrySpin (Self) > 0) break ;
if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
Self->_ParkEvent->reset() ;
OrderAccess::fence() ;
}
if (_succ == Self) _succ = NULL ;
OrderAccess::fence() ;
}
assert (_owner == Self , "invariant") ;
assert (object() != NULL , "invariant") ;
UnlinkAfterAcquire (Self, &node) ;
if (_succ == Self) _succ = NULL ;
assert (_succ != Self, "invariant") ;
if (_Responsible == Self) {
_Responsible = NULL ;
OrderAccess::fence(); // Dekker pivot-point
}
if (SyncFlags & 8) {
OrderAccess::fence() ;
}
return ;
}
void ATTR ObjectMonitor::ReenterI (Thread * Self, ObjectWaiter * SelfNode) {
assert (Self != NULL , "invariant") ;
assert (SelfNode != NULL , "invariant") ;
assert (SelfNode->_thread == Self , "invariant") ;
assert (_waiters > 0 , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this) , "invariant") ;
assert (((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
JavaThread * jt = (JavaThread *) Self ;
int nWakeups = 0 ;
for (;;) {
ObjectWaiter::TStates v = SelfNode->TState ;
guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
assert (_owner != Self, "invariant") ;
if (TryLock (Self) > 0) break ;
if (TrySpin (Self) > 0) break ;
TEVENT (Wait Reentry - parking) ;
{
OSThreadContendState osts(Self->osthread());
ThreadBlockInVM tbivm(jt);
jt->set_suspend_equivalent();
if (SyncFlags & 1) {
Self->_ParkEvent->park ((jlong)1000) ;
} else {
Self->_ParkEvent->park () ;
}
for (;;) {
if (!ExitSuspendEquivalent (jt)) break ;
if (_succ == Self) { _succ = NULL; OrderAccess::fence(); }
jt->java_suspend_self();
jt->set_suspend_equivalent();
}
}
if (TryLock(Self) > 0) break ;
TEVENT (Wait Reentry - futile wakeup) ;
++ nWakeups ;
if (_succ == Self) _succ = NULL ;
OrderAccess::fence() ;
if (ObjectMonitor::_sync_FutileWakeups != NULL) {
ObjectMonitor::_sync_FutileWakeups->inc() ;
}
}
assert (_owner == Self, "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
UnlinkAfterAcquire (Self, SelfNode) ;
if (_succ == Self) _succ = NULL ;
assert (_succ != Self, "invariant") ;
SelfNode->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ; // see comments at the end of EnterI()
}
void ObjectMonitor::UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode)
{
assert (_owner == Self, "invariant") ;
assert (SelfNode->_thread == Self, "invariant") ;
if (SelfNode->TState == ObjectWaiter::TS_ENTER) {
ObjectWaiter * nxt = SelfNode->_next ;
ObjectWaiter * prv = SelfNode->_prev ;
if (nxt != NULL) nxt->_prev = prv ;
if (prv != NULL) prv->_next = nxt ;
if (SelfNode == _EntryList ) _EntryList = nxt ;
assert (nxt == NULL || nxt->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (prv == NULL || prv->TState == ObjectWaiter::TS_ENTER, "invariant") ;
TEVENT (Unlink from EntryList) ;
} else {
guarantee (SelfNode->TState == ObjectWaiter::TS_CXQ, "invariant") ;
ObjectWaiter * v = _cxq ;
assert (v != NULL, "invariant") ;
if (v != SelfNode || Atomic::cmpxchg_ptr (SelfNode->_next, &_cxq, v) != v) {
if (v == SelfNode) {
assert (_cxq != v, "invariant") ;
v = _cxq ; // CAS above failed - start scan at head of list
}
ObjectWaiter * p ;
ObjectWaiter * q = NULL ;
for (p = v ; p != NULL && p != SelfNode; p = p->_next) {
q = p ;
assert (p->TState == ObjectWaiter::TS_CXQ, "invariant") ;
}
assert (v != SelfNode, "invariant") ;
assert (p == SelfNode, "Node not found on cxq") ;
assert (p != _cxq, "invariant") ;
assert (q != NULL, "invariant") ;
assert (q->_next == p, "invariant") ;
q->_next = p->_next ;
}
TEVENT (Unlink from cxq) ;
}
SelfNode->_prev = (ObjectWaiter *) 0xBAD ;
SelfNode->_next = (ObjectWaiter *) 0xBAD ;
SelfNode->TState = ObjectWaiter::TS_RUN ;
}
void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
Thread * Self = THREAD ;
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
assert (_recursions == 0, "invariant") ;
_owner = THREAD ;
_recursions = 0 ;
OwnerIsThread = 1 ;
} else {
TEVENT (Exit - Throw IMSX) ;
assert(false, "Non-balanced monitor enter/exit!");
if (false) {
THROW(vmSymbols::java_lang_IllegalMonitorStateException());
}
return;
}
}
if (_recursions != 0) {
_recursions--; // this is simple recursive enter
TEVENT (Inflated exit - recursive) ;
return ;
}
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
#if INCLUDE_JFR
if (not_suspended && EventJavaMonitorEnter::is_enabled()) {
_previous_owner_tid = JFR_THREAD_ID(Self);
}
#endif
for (;;) {
assert (THREAD == _owner, "invariant") ;
if (Knob_ExitPolicy == 0) {
OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
OrderAccess::storeload() ; // See if we need to wake a successor
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
TEVENT (Inflated exit - simple egress) ;
return ;
}
TEVENT (Inflated exit - complex egress) ;
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
return ;
}
TEVENT (Exit - Reacquired) ;
} else {
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
OrderAccess::release_store_ptr (&_owner, NULL) ; // drop the lock
OrderAccess::storeload() ;
if (_cxq == NULL || _succ != NULL) {
TEVENT (Inflated exit - simple egress) ;
return ;
}
if (Atomic::cmpxchg_ptr (THREAD, &_owner, NULL) != NULL) {
TEVENT (Inflated exit - reacquired succeeded) ;
return ;
}
TEVENT (Inflated exit - reacquired failed) ;
} else {
TEVENT (Inflated exit - complex egress) ;
}
}
guarantee (_owner == THREAD, "invariant") ;
ObjectWaiter * w = NULL ;
int QMode = Knob_QMode ;
if (QMode == 2 && _cxq != NULL) {
w = _cxq ;
assert (w != NULL, "invariant") ;
assert (w->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
ExitEpilog (Self, w) ;
return ;
}
if (QMode == 3 && _cxq != NULL) {
w = _cxq ;
for (;;) {
assert (w != NULL, "Invariant") ;
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
assert (w != NULL , "invariant") ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}
ObjectWaiter * Tail ;
for (Tail = _EntryList ; Tail != NULL && Tail->_next != NULL ; Tail = Tail->_next) ;
if (Tail == NULL) {
_EntryList = w ;
} else {
Tail->_next = w ;
w->_prev = Tail ;
}
}
if (QMode == 4 && _cxq != NULL) {
w = _cxq ;
for (;;) {
assert (w != NULL, "Invariant") ;
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
assert (w != NULL , "invariant") ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}
if (_EntryList != NULL) {
q->_next = _EntryList ;
_EntryList->_prev = q ;
}
_EntryList = w ;
}
w = _EntryList ;
if (w != NULL) {
assert (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
ExitEpilog (Self, w) ;
return ;
}
w = _cxq ;
if (w == NULL) continue ;
for (;;) {
assert (w != NULL, "Invariant") ;
ObjectWaiter * u = (ObjectWaiter *) Atomic::cmpxchg_ptr (NULL, &_cxq, w) ;
if (u == w) break ;
w = u ;
}
TEVENT (Inflated exit - drain cxq into EntryList) ;
assert (w != NULL , "invariant") ;
assert (_EntryList == NULL , "invariant") ;
if (QMode == 1) {
ObjectWaiter * s = NULL ;
ObjectWaiter * t = w ;
ObjectWaiter * u = NULL ;
while (t != NULL) {
guarantee (t->TState == ObjectWaiter::TS_CXQ, "invariant") ;
t->TState = ObjectWaiter::TS_ENTER ;
u = t->_next ;
t->_prev = u ;
t->_next = s ;
s = t;
t = u ;
}
_EntryList = s ;
assert (s != NULL, "invariant") ;
} else {
_EntryList = w ;
ObjectWaiter * q = NULL ;
ObjectWaiter * p ;
for (p = w ; p != NULL ; p = p->_next) {
guarantee (p->TState == ObjectWaiter::TS_CXQ, "Invariant") ;
p->TState = ObjectWaiter::TS_ENTER ;
p->_prev = q ;
q = p ;
}
}
if (_succ != NULL) continue;
w = _EntryList ;
if (w != NULL) {
guarantee (w->TState == ObjectWaiter::TS_ENTER, "invariant") ;
ExitEpilog (Self, w) ;
return ;
}
}
}
bool ObjectMonitor::ExitSuspendEquivalent (JavaThread * jSelf) {
int Mode = Knob_FastHSSEC ;
if (Mode && !jSelf->is_external_suspend()) {
assert (jSelf->is_suspend_equivalent(), "invariant") ;
jSelf->clear_suspend_equivalent() ;
if (2 == Mode) OrderAccess::storeload() ;
if (!jSelf->is_external_suspend()) return false ;
TEVENT (ExitSuspendEquivalent - raced) ;
jSelf->set_suspend_equivalent() ;
}
return jSelf->handle_special_suspend_equivalent_condition() ;
}
void ObjectMonitor::ExitEpilog (Thread * Self, ObjectWaiter * Wakee) {
assert (_owner == Self, "invariant") ;
_succ = Knob_SuccEnabled ? Wakee->_thread : NULL ;
ParkEvent * Trigger = Wakee->_event ;
Wakee = NULL ;
OrderAccess::release_store_ptr (&_owner, NULL) ;
OrderAccess::fence() ; // ST _owner vs LD in unpark()
if (SafepointSynchronize::do_call_back()) {
TEVENT (unpark before SAFEPOINT) ;
}
DTRACE_MONITOR_PROBE(contended__exit, this, object(), Self);
Trigger->unpark() ;
if (ObjectMonitor::_sync_Parks != NULL) {
ObjectMonitor::_sync_Parks->inc() ;
}
}
intptr_t ObjectMonitor::complete_exit(TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
DeferredInitialize();
if (THREAD != _owner) {
if (THREAD->is_lock_owned ((address)_owner)) {
assert(_recursions == 0, "internal state error");
_owner = THREAD ; /* Convert from basiclock addr to Thread addr */
_recursions = 0 ;
OwnerIsThread = 1 ;
}
}
guarantee(Self == _owner, "complete_exit not owner");
intptr_t save = _recursions; // record the old recursion count
_recursions = 0; // set the recursion level to be 0
exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant");
return save;
}
void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
guarantee(_owner != Self, "reenter already owner");
enter (THREAD); // enter the monitor
guarantee (_recursions == 0, "reenter recursion");
_recursions = recursions;
return;
}
#define CHECK_OWNER() \
do { \
if (THREAD != _owner) { \
if (THREAD->is_lock_owned((address) _owner)) { \
_owner = THREAD ; /* Convert from basiclock addr to Thread addr */ \
_recursions = 0; \
OwnerIsThread = 1 ; \
} else { \
TEVENT (Throw IMSX) ; \
THROW(vmSymbols::java_lang_IllegalMonitorStateException()); \
} \
} \
} while (false)
void ObjectMonitor::check_slow(TRAPS) {
TEVENT (check_slow - throw IMSX) ;
assert(THREAD != _owner && !THREAD->is_lock_owned((address) _owner), "must not be owner");
THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
}
static int Adjust (volatile int * adr, int dx) {
int v ;
for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
return v ;
}
static void post_monitor_wait_event(EventJavaMonitorWait* event,
ObjectMonitor* monitor,
jlong notifier_tid,
jlong timeout,
bool timedout) {
assert(monitor != NULL, "invariant");
event->set_monitorClass(((oop)monitor->object())->klass());
event->set_timeout(timeout);
event->set_address((uintptr_t)monitor->object_addr());
event->set_notifier((u8)notifier_tid);
event->set_timedOut(timedout);
event->commit();
}
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
Thread * const Self = THREAD ;
assert(Self->is_Java_thread(), "Must be Java thread!");
JavaThread *jt = (JavaThread *)THREAD;
DeferredInitialize () ;
CHECK_OWNER();
EventJavaMonitorWait event;
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(jt, this, false);
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, 0, millis, false);
}
TEVENT (Wait - Throw IEX) ;
THROW(vmSymbols::java_lang_InterruptedException());
return ;
}
TEVENT (Wait) ;
assert (Self->_Stalled == 0, "invariant") ;
Self->_Stalled = intptr_t(this) ;
jt->set_current_waiting_monitor(this);
ObjectWaiter node(Self);
node.TState = ObjectWaiter::TS_WAIT ;
Self->_ParkEvent->reset() ;
OrderAccess::fence(); // ST into Event; membar ; LD interrupted-flag
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - add") ;
AddWaiter (&node) ;
Thread::SpinRelease (&_WaitSetLock) ;
if ((SyncFlags & 4) == 0) {
_Responsible = NULL ;
}
intptr_t save = _recursions; // record the old recursion count
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant") ;
int ret = OS_OK ;
int WasNotified = 0 ;
{ // State transition wrappers
OSThread* osthread = Self->osthread();
OSThreadWaitState osts(osthread, true);
{
ThreadBlockInVM tbivm(jt);
jt->set_suspend_equivalent();
if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
} else
if (node._notified == 0) {
if (millis <= 0) {
Self->_ParkEvent->park () ;
} else {
ret = Self->_ParkEvent->park (millis) ;
}
}
if (ExitSuspendEquivalent (jt)) {
jt->java_suspend_self();
}
} // Exit thread safepoint: transition _thread_blocked -> _thread_in_vm
if (node.TState == ObjectWaiter::TS_WAIT) {
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
if (node.TState == ObjectWaiter::TS_WAIT) {
DequeueSpecificWaiter (&node) ; // unlink from WaitSet
assert(node._notified == 0, "invariant");
node.TState = ObjectWaiter::TS_RUN ;
}
Thread::SpinRelease (&_WaitSetLock) ;
}
guarantee (node.TState != ObjectWaiter::TS_WAIT, "invariant") ;
OrderAccess::loadload() ;
if (_succ == Self) _succ = NULL ;
WasNotified = node._notified ;
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
if (node._notified != 0 && _succ == Self) {
node._event->unpark();
}
}
if (event.should_commit()) {
post_monitor_wait_event(&event, this, node._notifier_tid, millis, ret == OS_TIMEOUT);
}
OrderAccess::fence() ;
assert (Self->_Stalled != 0, "invariant") ;
Self->_Stalled = 0 ;
assert (_owner != Self, "invariant") ;
ObjectWaiter::TStates v = node.TState ;
if (v == ObjectWaiter::TS_RUN) {
enter (Self) ;
} else {
guarantee (v == ObjectWaiter::TS_ENTER || v == ObjectWaiter::TS_CXQ, "invariant") ;
ReenterI (Self, &node) ;
node.wait_reenter_end(this);
}
guarantee (node.TState == ObjectWaiter::TS_RUN, "invariant") ;
assert (_owner == Self, "invariant") ;
assert (_succ != Self , "invariant") ;
} // OSThreadWaitState()
jt->set_current_waiting_monitor(NULL);
guarantee (_recursions == 0, "invariant") ;
_recursions = save; // restore the old recursion count
_waiters--; // decrement the number of waiters
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
if (SyncFlags & 32) {
OrderAccess::fence() ;
}
if (!WasNotified) {
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
TEVENT (Wait - throw IEX from epilog) ;
THROW(vmSymbols::java_lang_InterruptedException());
}
}
}
void ObjectMonitor::notify(TRAPS) {
CHECK_OWNER();
if (_WaitSet == NULL) {
TEVENT (Empty-Notify) ;
return ;
}
DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);
int Policy = Knob_MoveNotifyee ;
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
ObjectWaiter * iterator = DequeueWaiter() ;
if (iterator != NULL) {
TEVENT (Notify1 - Transfer) ;
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
if (Policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
iterator->_notified = 1 ;
Thread * Self = THREAD;
iterator->_notifier_tid = JFR_THREAD_ID(Self);
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
if (Policy == 0) { // prepend to EntryList
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
List->_prev = iterator ;
iterator->_next = List ;
iterator->_prev = NULL ;
_EntryList = iterator ;
}
} else
if (Policy == 1) { // append to EntryList
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
ObjectWaiter * Tail ;
for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
}
} else
if (Policy == 2) { // prepend to cxq
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
}
} else
if (Policy == 3) { // append to cxq
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Tail ;
Tail = _cxq ;
if (Tail == NULL) {
iterator->_next = NULL ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
break ;
}
} else {
while (Tail->_next != NULL) Tail = Tail->_next ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
break ;
}
}
} else {
ParkEvent * ev = iterator->_event ;
iterator->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ;
ev->unpark() ;
}
if (Policy < 4) {
iterator->wait_reenter_begin(this);
}
}
Thread::SpinRelease (&_WaitSetLock) ;
if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
ObjectMonitor::_sync_Notifications->inc() ;
}
}
void ObjectMonitor::notifyAll(TRAPS) {
CHECK_OWNER();
ObjectWaiter* iterator;
if (_WaitSet == NULL) {
TEVENT (Empty-NotifyAll) ;
return ;
}
DTRACE_MONITOR_PROBE(notifyAll, this, object(), THREAD);
int Policy = Knob_MoveNotifyee ;
int Tally = 0 ;
Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notifyall") ;
for (;;) {
iterator = DequeueWaiter () ;
if (iterator == NULL) break ;
TEVENT (NotifyAll - Transfer1) ;
++Tally ;
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
iterator->_notified = 1 ;
Thread * Self = THREAD;
iterator->_notifier_tid = JFR_THREAD_ID(Self);
if (Policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
assert (List->_prev == NULL, "invariant") ;
assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
assert (List != iterator, "invariant") ;
}
if (Policy == 0) { // prepend to EntryList
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
List->_prev = iterator ;
iterator->_next = List ;
iterator->_prev = NULL ;
_EntryList = iterator ;
}
} else
if (Policy == 1) { // append to EntryList
if (List == NULL) {
iterator->_next = iterator->_prev = NULL ;
_EntryList = iterator ;
} else {
ObjectWaiter * Tail ;
for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
}
} else
if (Policy == 2) { // prepend to cxq
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Front = _cxq ;
iterator->_next = Front ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
break ;
}
}
} else
if (Policy == 3) { // append to cxq
iterator->TState = ObjectWaiter::TS_CXQ ;
for (;;) {
ObjectWaiter * Tail ;
Tail = _cxq ;
if (Tail == NULL) {
iterator->_next = NULL ;
if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
break ;
}
} else {
while (Tail->_next != NULL) Tail = Tail->_next ;
Tail->_next = iterator ;
iterator->_prev = Tail ;
iterator->_next = NULL ;
break ;
}
}
} else {
ParkEvent * ev = iterator->_event ;
iterator->TState = ObjectWaiter::TS_RUN ;
OrderAccess::fence() ;
ev->unpark() ;
}
if (Policy < 4) {
iterator->wait_reenter_begin(this);
}
}
Thread::SpinRelease (&_WaitSetLock) ;
if (Tally != 0 && ObjectMonitor::_sync_Notifications != NULL) {
ObjectMonitor::_sync_Notifications->inc(Tally) ;
}
}
intptr_t ObjectMonitor::SpinCallbackArgument = 0 ;
int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL ;
int ObjectMonitor::TrySpin_VaryDuration (Thread * Self) {
int ctr = Knob_FixedSpin ;
if (ctr != 0) {
while (--ctr >= 0) {
if (TryLock (Self) > 0) return 1 ;
SpinPause () ;
}
return 0 ;
}
for (ctr = Knob_PreSpin + 1; --ctr >= 0 ; ) {
if (TryLock(Self) > 0) {
int x = _SpinDuration ;
if (x < Knob_SpinLimit) {
if (x < Knob_Poverty) x = Knob_Poverty ;
_SpinDuration = x + Knob_BonusB ;
}
return 1 ;
}
SpinPause () ;
}
ctr = _SpinDuration ;
if (ctr < Knob_SpinBase) ctr = Knob_SpinBase ;
if (ctr <= 0) return 0 ;
if (Knob_SuccRestrict && _succ != NULL) return 0 ;
if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
TEVENT (Spin abort - notrunnable [TOP]);
return 0 ;
}
int MaxSpin = Knob_MaxSpinners ;
if (MaxSpin >= 0) {
if (_Spinner > MaxSpin) {
TEVENT (Spin abort -- too many spinners) ;
return 0 ;
}
Adjust (&_Spinner, 1) ;
}
int hits = 0 ;
int msk = 0 ;
int caspty = Knob_CASPenalty ;
int oxpty = Knob_OXPenalty ;
int sss = Knob_SpinSetSucc ;
if (sss && _succ == NULL ) _succ = Self ;
Thread * prv = NULL ;
while (--ctr >= 0) {
if ((ctr & 0xFF) == 0) {
if (SafepointSynchronize::do_call_back()) {
TEVENT (Spin: safepoint) ;
goto Abort ; // abrupt spin egress
}
if (Knob_UsePause & 1) SpinPause () ;
int (*scb)(intptr_t,int) = SpinCallbackFunction ;
if (hits > 50 && scb != NULL) {
int abend = (*scb)(SpinCallbackArgument, 0) ;
}
}
if (Knob_UsePause & 2) SpinPause() ;
if (ctr & msk) continue ;
++hits ;
if ((hits & 0xF) == 0) {
msk = ((msk << 2)|3) & BackOffMask ;
}
Thread * ox = (Thread *) _owner ;
if (ox == NULL) {
ox = (Thread *) Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
if (ox == NULL) {
if (sss && _succ == Self) {
_succ = NULL ;
}
if (MaxSpin > 0) Adjust (&_Spinner, -1) ;
int x = _SpinDuration ;
if (x < Knob_SpinLimit) {
if (x < Knob_Poverty) x = Knob_Poverty ;
_SpinDuration = x + Knob_Bonus ;
}
return 1 ;
}
prv = ox ;
TEVENT (Spin: cas failed) ;
if (caspty == -2) break ;
if (caspty == -1) goto Abort ;
ctr -= caspty ;
continue ;
}
if (ox != prv && prv != NULL ) {
TEVENT (spin: Owner changed)
if (oxpty == -2) break ;
if (oxpty == -1) goto Abort ;
ctr -= oxpty ;
}
prv = ox ;
if (Knob_OState && NotRunnable (Self, ox)) {
TEVENT (Spin abort - notrunnable);
goto Abort ;
}
if (sss && _succ == NULL ) _succ = Self ;
}
TEVENT (Spin failure) ;
{
int x = _SpinDuration ;
if (x > 0) {
x -= Knob_Penalty ;
if (x < 0) x = 0 ;
_SpinDuration = x ;
}
}
Abort:
if (MaxSpin >= 0) Adjust (&_Spinner, -1) ;
if (sss && _succ == Self) {
_succ = NULL ;
OrderAccess::fence() ;
if (TryLock(Self) > 0) return 1 ;
}
return 0 ;
}
int ObjectMonitor::NotRunnable (Thread * Self, Thread * ox) {
if (!OwnerIsThread) return 0 ;
if (ox == NULL) return 0 ;
intptr_t BlockedOn = SafeFetchN ((intptr_t *) &ox->_Stalled, intptr_t(1)) ;
if (BlockedOn == 1) return 1 ;
if (BlockedOn != 0) {
return BlockedOn != intptr_t(this) && _owner == ox ;
}
assert (sizeof(((JavaThread *)ox)->_thread_state == sizeof(int)), "invariant") ;
int jst = SafeFetch32 ((int *) &((JavaThread *) ox)->_thread_state, -1) ; ;
return jst == _thread_blocked || jst == _thread_in_native ;
}
ObjectWaiter::ObjectWaiter(Thread* thread) {
_next = NULL;
_prev = NULL;
_notified = 0;
_notifier_tid = 0;
TState = TS_RUN ;
_thread = thread;
_event = thread->_ParkEvent ;
_active = false;
assert (_event != NULL, "invariant") ;
}
void ObjectWaiter::wait_reenter_begin(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
_active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
}
void ObjectWaiter::wait_reenter_end(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
}
inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node->_prev == NULL, "node already in list");
assert(node->_next == NULL, "node already in list");
if (_WaitSet == NULL) {
_WaitSet = node;
node->_prev = node;
node->_next = node;
} else {
ObjectWaiter* head = _WaitSet ;
ObjectWaiter* tail = head->_prev;
assert(tail->_next == head, "invariant check");
tail->_next = node;
head->_prev = node;
node->_next = head;
node->_prev = tail;
}
}
inline ObjectWaiter* ObjectMonitor::DequeueWaiter() {
ObjectWaiter* waiter = _WaitSet;
if (waiter) {
DequeueSpecificWaiter(waiter);
}
return waiter;
}
inline void ObjectMonitor::DequeueSpecificWaiter(ObjectWaiter* node) {
assert(node != NULL, "should not dequeue NULL node");
assert(node->_prev != NULL, "node already removed from list");
assert(node->_next != NULL, "node already removed from list");
ObjectWaiter* next = node->_next;
if (next == node) {
assert(node->_prev == node, "invariant check");
_WaitSet = NULL;
} else {
ObjectWaiter* prev = node->_prev;
assert(prev->_next == node, "invariant check");
assert(next->_prev == node, "invariant check");
next->_prev = prev;
prev->_next = next;
if (_WaitSet == node) {
_WaitSet = next;
}
}
node->_next = NULL;
node->_prev = NULL;
}
PerfCounter * ObjectMonitor::_sync_ContendedLockAttempts = NULL ;
PerfCounter * ObjectMonitor::_sync_FutileWakeups = NULL ;
PerfCounter * ObjectMonitor::_sync_Parks = NULL ;
PerfCounter * ObjectMonitor::_sync_EmptyNotifications = NULL ;
PerfCounter * ObjectMonitor::_sync_Notifications = NULL ;
PerfCounter * ObjectMonitor::_sync_PrivateA = NULL ;
PerfCounter * ObjectMonitor::_sync_PrivateB = NULL ;
PerfCounter * ObjectMonitor::_sync_SlowExit = NULL ;
PerfCounter * ObjectMonitor::_sync_SlowEnter = NULL ;
PerfCounter * ObjectMonitor::_sync_SlowNotify = NULL ;
PerfCounter * ObjectMonitor::_sync_SlowNotifyAll = NULL ;
PerfCounter * ObjectMonitor::_sync_FailedSpins = NULL ;
PerfCounter * ObjectMonitor::_sync_SuccessfulSpins = NULL ;
PerfCounter * ObjectMonitor::_sync_MonInCirculation = NULL ;
PerfCounter * ObjectMonitor::_sync_MonScavenged = NULL ;
PerfCounter * ObjectMonitor::_sync_Inflations = NULL ;
PerfCounter * ObjectMonitor::_sync_Deflations = NULL ;
PerfLongVariable * ObjectMonitor::_sync_MonExtant = NULL ;
void ObjectMonitor::Initialize () {
static int InitializationCompleted = 0 ;
assert (InitializationCompleted == 0, "invariant") ;
InitializationCompleted = 1 ;
if (UsePerfData) {
EXCEPTION_MARK ;
#define NEWPERFCOUNTER(n) {n = PerfDataManager::create_counter(SUN_RT, #n, PerfData::U_Events,CHECK); }
#define NEWPERFVARIABLE(n) {n = PerfDataManager::create_variable(SUN_RT, #n, PerfData::U_Events,CHECK); }
NEWPERFCOUNTER(_sync_Inflations) ;
NEWPERFCOUNTER(_sync_Deflations) ;
NEWPERFCOUNTER(_sync_ContendedLockAttempts) ;
NEWPERFCOUNTER(_sync_FutileWakeups) ;
NEWPERFCOUNTER(_sync_Parks) ;
NEWPERFCOUNTER(_sync_EmptyNotifications) ;
NEWPERFCOUNTER(_sync_Notifications) ;
NEWPERFCOUNTER(_sync_SlowEnter) ;
NEWPERFCOUNTER(_sync_SlowExit) ;
NEWPERFCOUNTER(_sync_SlowNotify) ;
NEWPERFCOUNTER(_sync_SlowNotifyAll) ;
NEWPERFCOUNTER(_sync_FailedSpins) ;
NEWPERFCOUNTER(_sync_SuccessfulSpins) ;
NEWPERFCOUNTER(_sync_PrivateA) ;
NEWPERFCOUNTER(_sync_PrivateB) ;
NEWPERFCOUNTER(_sync_MonInCirculation) ;
NEWPERFCOUNTER(_sync_MonScavenged) ;
NEWPERFVARIABLE(_sync_MonExtant) ;
#undef NEWPERFCOUNTER
}
}
#define CTASSERT(x) { int tag[1-(2*!(x))]; printf ("Tag @" INTPTR_FORMAT "\n", (intptr_t)tag); }
void ObjectMonitor::ctAsserts() {
CTASSERT(offset_of (ObjectMonitor, _header) == 0);
}
static char * kvGet (char * kvList, const char * Key) {
if (kvList == NULL) return NULL ;
size_t n = strlen (Key) ;
char * Search ;
for (Search = kvList ; *Search ; Search += strlen(Search) + 1) {
if (strncmp (Search, Key, n) == 0) {
if (Search[n] == '=') return Search + n + 1 ;
if (Search[n] == 0) return (char *) "1" ;
}
}
return NULL ;
}
static int kvGetInt (char * kvList, const char * Key, int Default) {
char * v = kvGet (kvList, Key) ;
int rslt = v ? ::strtol (v, NULL, 0) : Default ;
if (Knob_ReportSettings && v != NULL) {
::printf (" SyncKnob: %s %d(%d)\n", Key, rslt, Default) ;
::fflush (stdout) ;
}
return rslt ;
}
void ObjectMonitor::DeferredInitialize () {
if (InitDone > 0) return ;
if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
while (InitDone != 1) ;
return ;
}
if (SyncKnobs == NULL) SyncKnobs = "" ;
size_t sz = strlen (SyncKnobs) ;
char * knobs = (char *) malloc (sz + 2) ;
if (knobs == NULL) {
vm_exit_out_of_memory (sz + 2, OOM_MALLOC_ERROR, "Parse SyncKnobs") ;
guarantee (0, "invariant") ;
}
strcpy (knobs, SyncKnobs) ;
knobs[sz+1] = 0 ;
for (char * p = knobs ; *p ; p++) {
if (*p == ':') *p = 0 ;
}
#define SETKNOB(x) { Knob_##x = kvGetInt (knobs, #x, Knob_##x); }
SETKNOB(ReportSettings) ;
SETKNOB(Verbose) ;
SETKNOB(FixedSpin) ;
SETKNOB(SpinLimit) ;
SETKNOB(SpinBase) ;
SETKNOB(SpinBackOff);
SETKNOB(CASPenalty) ;
SETKNOB(OXPenalty) ;
SETKNOB(LogSpins) ;
SETKNOB(SpinSetSucc) ;
SETKNOB(SuccEnabled) ;
SETKNOB(SuccRestrict) ;
SETKNOB(Penalty) ;
SETKNOB(Bonus) ;
SETKNOB(BonusB) ;
SETKNOB(Poverty) ;
SETKNOB(SpinAfterFutile) ;
SETKNOB(UsePause) ;
SETKNOB(SpinEarly) ;
SETKNOB(OState) ;
SETKNOB(MaxSpinners) ;
SETKNOB(PreSpin) ;
SETKNOB(ExitPolicy) ;
SETKNOB(QMode);
SETKNOB(ResetEvent) ;
SETKNOB(MoveNotifyee) ;
SETKNOB(FastHSSEC) ;
#undef SETKNOB
if (Knob_Verbose) {
sanity_checks();
}
if (os::is_MP()) {
BackOffMask = (1 << Knob_SpinBackOff) - 1 ;
if (Knob_ReportSettings) ::printf ("BackOffMask=%X\n", BackOffMask) ;
} else {
Knob_SpinLimit = 0 ;
Knob_SpinBase = 0 ;
Knob_PreSpin = 0 ;
Knob_FixedSpin = -1 ;
}
if (Knob_LogSpins == 0) {
ObjectMonitor::_sync_FailedSpins = NULL ;
}
free (knobs) ;
OrderAccess::fence() ;
InitDone = 1 ;
}
void ObjectMonitor::sanity_checks() {
int error_cnt = 0;
int warning_cnt = 0;
bool verbose = Knob_Verbose != 0 NOT_PRODUCT(|| VerboseInternalVMTests);
if (verbose) {
tty->print_cr("INFO: sizeof(ObjectMonitor)=" SIZE_FORMAT,
sizeof(ObjectMonitor));
}
uint cache_line_size = VM_Version::L1_data_cache_line_size();
if (verbose) {
tty->print_cr("INFO: L1_data_cache_line_size=%u", cache_line_size);
}
ObjectMonitor dummy;
u_char *addr_begin = (u_char*)&dummy;
u_char *addr_header = (u_char*)&dummy._header;
u_char *addr_owner = (u_char*)&dummy._owner;
uint offset_header = (uint)(addr_header - addr_begin);
if (verbose) tty->print_cr("INFO: offset(_header)=%u", offset_header);
uint offset_owner = (uint)(addr_owner - addr_begin);
if (verbose) tty->print_cr("INFO: offset(_owner)=%u", offset_owner);
if ((uint)(addr_header - addr_begin) != 0) {
tty->print_cr("ERROR: offset(_header) must be zero (0).");
error_cnt++;
}
if (cache_line_size != 0) {
if ((offset_owner - offset_header) < cache_line_size) {
tty->print_cr("WARNING: the _header and _owner fields are closer "
"than a cache line which permits false sharing.");
warning_cnt++;
}
if ((sizeof(ObjectMonitor) % cache_line_size) != 0) {
tty->print_cr("WARNING: ObjectMonitor size is not a multiple of "
"a cache line which permits false sharing.");
warning_cnt++;
}
}
ObjectSynchronizer::sanity_checks(verbose, cache_line_size, &error_cnt,
&warning_cnt);
if (verbose || error_cnt != 0 || warning_cnt != 0) {
tty->print_cr("INFO: error_cnt=%d", error_cnt);
tty->print_cr("INFO: warning_cnt=%d", warning_cnt);
}
guarantee(error_cnt == 0,
"Fatal error(s) found in ObjectMonitor::sanity_checks()");
}
#ifndef PRODUCT
void ObjectMonitor::verify() {
}
void ObjectMonitor::print() {
}
#endif
C:\hotspot-69087d08d473\src\share\vm/runtime/objectMonitor.hpp
#ifndef SHARE_VM_RUNTIME_OBJECTMONITOR_HPP
#define SHARE_VM_RUNTIME_OBJECTMONITOR_HPP
#include "runtime/os.hpp"
#include "runtime/park.hpp"
#include "runtime/perfData.hpp"
class ObjectWaiter : public StackObj {
public:
enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
enum Sorted { PREPEND, APPEND, SORTED } ;
ObjectWaiter * volatile _next;
ObjectWaiter * volatile _prev;
Thread* _thread;
jlong _notifier_tid;
ParkEvent * _event;
volatile int _notified ;
volatile TStates TState ;
Sorted _Sorted ; // List placement disposition
bool _active ; // Contention monitoring is enabled
public:
ObjectWaiter(Thread* thread);
void wait_reenter_begin(ObjectMonitor *mon);
void wait_reenter_end(ObjectMonitor *mon);
};
class ObjectMonitor {
public:
enum {
OM_OK, // no error
OM_SYSTEM_ERROR, // operating system error
OM_ILLEGAL_MONITOR_STATE, // IllegalMonitorStateException
OM_INTERRUPTED, // Thread.interrupt()
OM_TIMED_OUT // Object.wait() timed out
};
public:
static int header_offset_in_bytes() { return offset_of(ObjectMonitor, _header); }
static int object_offset_in_bytes() { return offset_of(ObjectMonitor, _object); }
static int owner_offset_in_bytes() { return offset_of(ObjectMonitor, _owner); }
static int count_offset_in_bytes() { return offset_of(ObjectMonitor, _count); }
static int recursions_offset_in_bytes() { return offset_of(ObjectMonitor, _recursions); }
static int cxq_offset_in_bytes() { return offset_of(ObjectMonitor, _cxq) ; }
static int succ_offset_in_bytes() { return offset_of(ObjectMonitor, _succ) ; }
static int EntryList_offset_in_bytes() { return offset_of(ObjectMonitor, _EntryList); }
static int FreeNext_offset_in_bytes() { return offset_of(ObjectMonitor, FreeNext); }
static int WaitSet_offset_in_bytes() { return offset_of(ObjectMonitor, _WaitSet) ; }
static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible);}
static int Spinner_offset_in_bytes() { return offset_of(ObjectMonitor, _Spinner); }
public:
static int (*SpinCallbackFunction)(intptr_t, int) ;
static intptr_t SpinCallbackArgument ;
public:
markOop header() const;
void set_header(markOop hdr);
intptr_t is_busy() const {
return _count|_waiters|intptr_t(_owner)|intptr_t(_cxq)|intptr_t(_EntryList ) ;
}
intptr_t is_entered(Thread* current) const;
void* owner() const;
void set_owner(void* owner);
intptr_t waiters() const;
intptr_t count() const;
void set_count(intptr_t count);
intptr_t contentions() const ;
intptr_t recursions() const { return _recursions; }
ObjectWaiter* first_waiter() { return _WaitSet; }
ObjectWaiter* next_waiter(ObjectWaiter* o) { return o->_next; }
Thread* thread_of_waiter(ObjectWaiter* o) { return o->_thread; }
ObjectMonitor() {
_header = NULL;
_count = 0;
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL;
_WaitSet = NULL;
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ;
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
_previous_owner_tid = 0;
}
~ObjectMonitor() {
}
private:
void Recycle () {
_succ = NULL ;
_EntryList = NULL ;
_cxq = NULL ;
_WaitSet = NULL ;
_recursions = 0 ;
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}
public:
void* object() const;
void* object_addr();
void set_object(void* obj);
bool check(TRAPS); // true if the thread owns the monitor.
void check_slow(TRAPS);
void clear();
static void sanity_checks(); // public for -XX:+ExecuteInternalVMTests
#ifndef PRODUCT
void verify();
void print();
#endif
bool try_enter (TRAPS) ;
void enter(TRAPS);
void exit(bool not_suspended, TRAPS);
void wait(jlong millis, bool interruptable, TRAPS);
void notify(TRAPS);
void notifyAll(TRAPS);
intptr_t complete_exit(TRAPS);
void reenter(intptr_t recursions, TRAPS);
private:
void AddWaiter (ObjectWaiter * waiter) ;
static void DeferredInitialize();
ObjectWaiter * DequeueWaiter () ;
void DequeueSpecificWaiter (ObjectWaiter * waiter) ;
void EnterI (TRAPS) ;
void ReenterI (Thread * Self, ObjectWaiter * SelfNode) ;
void UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode) ;
int TryLock (Thread * Self) ;
int NotRunnable (Thread * Self, Thread * Owner) ;
int TrySpin_Fixed (Thread * Self) ;
int TrySpin_VaryFrequency (Thread * Self) ;
int TrySpin_VaryDuration (Thread * Self) ;
void ctAsserts () ;
void ExitEpilog (Thread * Self, ObjectWaiter * Wakee) ;
bool ExitSuspendEquivalent (JavaThread * Self) ;
private:
friend class ObjectSynchronizer;
friend class ObjectWaiter;
friend class VMStructs;
volatile markOop _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root
double SharingPad [1] ; // temp to reduce false sharing
protected: // protected for jvmtiRawMonitor
void * volatile _owner; // pointer to owning thread OR BasicLock
volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor
volatile intptr_t _recursions; // recursion count, 0 for first entry
private:
int OwnerIsThread ; // _owner is (Thread *) vs SP/BasicLock
ObjectWaiter * volatile _cxq ; // LL of recently-arrived threads blocked on entry.
protected:
ObjectWaiter * volatile _EntryList ; // Threads blocked on entry or reentry.
private:
Thread * volatile _succ ; // Heir presumptive thread - used for futile wakeup throttling
Thread * volatile _Responsible ;
int _PromptDrain ; // rqst to drain cxq into EntryList ASAP
volatile int _Spinner ; // for exit->spinner handoff optimization
volatile int _SpinFreq ; // Spin 1-out-of-N attempts: success rate
volatile int _SpinClock ;
volatile int _SpinDuration ;
volatile intptr_t _SpinState ; // MCS/CLH list of spinners
volatile intptr_t _count; // reference count to prevent reclaimation/deflation
protected:
volatile intptr_t _waiters; // number of waiting threads
private:
protected:
ObjectWaiter * volatile _WaitSet; // LL of threads wait()ing on the monitor
private:
volatile int _WaitSetLock; // protects Wait Queue - simple spinlock
public:
int _QMix ; // Mixed prepend queue discipline
ObjectMonitor * FreeNext ; // Free list linkage
intptr_t StatA, StatsB ;
public:
static void Initialize () ;
static PerfCounter * _sync_ContendedLockAttempts ;
static PerfCounter * _sync_FutileWakeups ;
static PerfCounter * _sync_Parks ;
static PerfCounter * _sync_EmptyNotifications ;
static PerfCounter * _sync_Notifications ;
static PerfCounter * _sync_SlowEnter ;
static PerfCounter * _sync_SlowExit ;
static PerfCounter * _sync_SlowNotify ;
static PerfCounter * _sync_SlowNotifyAll ;
static PerfCounter * _sync_FailedSpins ;
static PerfCounter * _sync_SuccessfulSpins ;
static PerfCounter * _sync_PrivateA ;
static PerfCounter * _sync_PrivateB ;
static PerfCounter * _sync_MonInCirculation ;
static PerfCounter * _sync_MonScavenged ;
static PerfCounter * _sync_Inflations ;
static PerfCounter * _sync_Deflations ;
static PerfLongVariable * _sync_MonExtant ;
public:
static int Knob_Verbose;
static int Knob_SpinLimit;
void* operator new (size_t size) throw() {
return AllocateHeap(size, mtInternal);
}
void* operator new[] (size_t size) throw() {
return operator new (size);
}
void operator delete(void* p) {
FreeHeap(p, mtInternal);
}
void operator delete[] (void *p) {
operator delete(p);
}
};
#undef TEVENT
#define TEVENT(nom) {if (SyncVerbose) FEVENT(nom); }
#define FEVENT(nom) { static volatile int ctr = 0 ; int v = ++ctr ; if ((v & (v-1)) == 0) { ::printf (#nom " : %d \n", v); ::fflush(stdout); }}
#undef TEVENT
#define TEVENT(nom) {;}
#endif // SHARE_VM_RUNTIME_OBJECTMONITOR_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/objectMonitor.inline.hpp
#ifndef SHARE_VM_RUNTIME_OBJECTMONITOR_INLINE_HPP
#define SHARE_VM_RUNTIME_OBJECTMONITOR_INLINE_HPP
inline intptr_t ObjectMonitor::is_entered(TRAPS) const {
if (THREAD == _owner || THREAD->is_lock_owned((address) _owner)) {
return 1;
}
return 0;
}
inline markOop ObjectMonitor::header() const {
return _header;
}
inline void ObjectMonitor::set_header(markOop hdr) {
_header = hdr;
}
inline intptr_t ObjectMonitor::count() const {
return _count;
}
inline void ObjectMonitor::set_count(intptr_t count) {
_count= count;
}
inline intptr_t ObjectMonitor::waiters() const {
return _waiters;
}
inline void* ObjectMonitor::owner() const {
return _owner;
}
inline void ObjectMonitor::clear() {
assert(_header, "Fatal logic error in ObjectMonitor header!");
assert(_count == 0, "Fatal logic error in ObjectMonitor count!");
assert(_waiters == 0, "Fatal logic error in ObjectMonitor waiters!");
assert(_recursions == 0, "Fatal logic error in ObjectMonitor recursions!");
assert(_object, "Fatal logic error in ObjectMonitor object!");
assert(_owner == 0, "Fatal logic error in ObjectMonitor owner!");
_header = NULL;
_object = NULL;
}
inline void* ObjectMonitor::object() const {
return _object;
}
inline void* ObjectMonitor::object_addr() {
return (void *)(&_object);
}
inline void ObjectMonitor::set_object(void* obj) {
_object = obj;
}
inline bool ObjectMonitor::check(TRAPS) {
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
_owner = THREAD; // regain ownership of inflated monitor
OwnerIsThread = 1 ;
assert (_recursions == 0, "invariant") ;
} else {
check_slow(THREAD);
return false;
}
}
return true;
}
inline intptr_t ObjectMonitor::contentions() const {
return _count;
}
inline void ObjectMonitor::set_owner(void* owner) {
_owner = owner;
_recursions = 0;
}
#endif // SHARE_VM_RUNTIME_OBJECTMONITOR_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/orderAccess.cpp
#include "precompiled.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.hpp"
void OrderAccess::StubRoutines_fence() {
void (*func)() = CAST_TO_FN_PTR(void (*)(), StubRoutines::fence_entry());
if (func != NULL) {
(*func)();
return;
}
assert(Threads::number_of_threads() == 0, "for bootstrap only");
}
C:\hotspot-69087d08d473\src\share\vm/runtime/orderAccess.hpp
#ifndef SHARE_VM_RUNTIME_ORDERACCESS_HPP
#define SHARE_VM_RUNTIME_ORDERACCESS_HPP
#include "memory/allocation.hpp"
class OrderAccess : AllStatic {
public:
static void loadload();
static void storestore();
static void loadstore();
static void storeload();
static void acquire();
static void release();
static void fence();
static jbyte load_acquire(volatile jbyte* p);
static jshort load_acquire(volatile jshort* p);
static jint load_acquire(volatile jint* p);
static jlong load_acquire(volatile jlong* p);
static jubyte load_acquire(volatile jubyte* p);
static jushort load_acquire(volatile jushort* p);
static juint load_acquire(volatile juint* p);
static julong load_acquire(volatile julong* p);
static jfloat load_acquire(volatile jfloat* p);
static jdouble load_acquire(volatile jdouble* p);
static intptr_t load_ptr_acquire(volatile intptr_t* p);
static void* load_ptr_acquire(volatile void* p);
static void* load_ptr_acquire(const volatile void* p);
static void release_store(volatile jbyte* p, jbyte v);
static void release_store(volatile jshort* p, jshort v);
static void release_store(volatile jint* p, jint v);
static void release_store(volatile jlong* p, jlong v);
static void release_store(volatile jubyte* p, jubyte v);
static void release_store(volatile jushort* p, jushort v);
static void release_store(volatile juint* p, juint v);
static void release_store(volatile julong* p, julong v);
static void release_store(volatile jfloat* p, jfloat v);
static void release_store(volatile jdouble* p, jdouble v);
static void release_store_ptr(volatile intptr_t* p, intptr_t v);
static void release_store_ptr(volatile void* p, void* v);
static void store_fence(jbyte* p, jbyte v);
static void store_fence(jshort* p, jshort v);
static void store_fence(jint* p, jint v);
static void store_fence(jlong* p, jlong v);
static void store_fence(jubyte* p, jubyte v);
static void store_fence(jushort* p, jushort v);
static void store_fence(juint* p, juint v);
static void store_fence(julong* p, julong v);
static void store_fence(jfloat* p, jfloat v);
static void store_fence(jdouble* p, jdouble v);
static void store_ptr_fence(intptr_t* p, intptr_t v);
static void store_ptr_fence(void** p, void* v);
static void release_store_fence(volatile jbyte* p, jbyte v);
static void release_store_fence(volatile jshort* p, jshort v);
static void release_store_fence(volatile jint* p, jint v);
static void release_store_fence(volatile jlong* p, jlong v);
static void release_store_fence(volatile jubyte* p, jubyte v);
static void release_store_fence(volatile jushort* p, jushort v);
static void release_store_fence(volatile juint* p, juint v);
static void release_store_fence(volatile julong* p, julong v);
static void release_store_fence(volatile jfloat* p, jfloat v);
static void release_store_fence(volatile jdouble* p, jdouble v);
static void release_store_ptr_fence(volatile intptr_t* p, intptr_t v);
static void release_store_ptr_fence(volatile void* p, void* v);
private:
static void StubRoutines_fence();
};
#endif // SHARE_VM_RUNTIME_ORDERACCESS_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/orderAccess.inline.hpp
#ifndef SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP
#define SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP
#include "runtime/orderAccess.hpp"
#ifdef TARGET_OS_ARCH_linux_x86
# include "orderAccess_linux_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_sparc
# include "orderAccess_linux_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_zero
# include "orderAccess_linux_zero.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_arm
# include "orderAccess_linux_arm.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_aarch64
# include "orderAccess_linux_aarch64.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_ppc
# include "orderAccess_linux_ppc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_x86
# include "orderAccess_solaris_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_sparc
# include "orderAccess_solaris_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_windows_x86
# include "orderAccess_windows_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_aix_ppc
# include "orderAccess_aix_ppc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_x86
# include "orderAccess_bsd_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_zero
# include "orderAccess_bsd_zero.inline.hpp"
#endif
#endif // SHARE_VM_RUNTIME_ORDERACCESS_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/runtime/os.cpp
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/allocation.inline.hpp"
#ifdef ASSERT
#include "memory/guardedMemory.hpp"
#endif
#include "oops/oop.inline.hpp"
#include "prims/jvm.h"
#include "prims/jvm_misc.hpp"
#include "prims/privilegedStack.hpp"
#include "runtime/arguments.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "services/attachListener.hpp"
#include "services/nmtCommon.hpp"
#include "services/mallocTracker.hpp"
#include "services/memTracker.hpp"
#include "services/threadService.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/events.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
# include <signal.h>
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
OSThread* os::_starting_thread = NULL;
address os::_polling_page = NULL;
volatile int32_t* os::_mem_serialize_page = NULL;
uintptr_t os::_serialize_page_mask = 0;
long os::_rand_seed = 1;
int os::_processor_count = 0;
int os::_initial_active_processor_count = 0;
size_t os::_page_sizes[os::page_sizes_max];
#ifndef PRODUCT
julong os::num_mallocs = 0; // # of calls to malloc/realloc
julong os::alloc_bytes = 0; // # of bytes allocated
julong os::num_frees = 0; // # of calls to free
julong os::free_bytes = 0; // # of bytes freed
#endif
static juint cur_malloc_words = 0; // current size for MallocMaxTestWords
void os_init_globals() {
os::init_globals();
}
int os::snprintf(char* buf, size_t len, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
int result = os::vsnprintf(buf, len, fmt, args);
va_end(args);
return result;
}
char* os::iso8601_time(char* buffer, size_t buffer_length) {
static const char* iso8601_format =
"%04d-%02d-%02dT%02d:%02d:%02d.%03d%c%02d%02d";
static const size_t needed_buffer = 29;
if (buffer == NULL) {
assert(false, "NULL buffer");
return NULL;
}
if (buffer_length < needed_buffer) {
assert(false, "buffer_length too small");
return NULL;
}
jlong milliseconds_since_19700101 = javaTimeMillis();
const int milliseconds_per_microsecond = 1000;
const time_t seconds_since_19700101 =
milliseconds_since_19700101 / milliseconds_per_microsecond;
const int milliseconds_after_second =
milliseconds_since_19700101 % milliseconds_per_microsecond;
struct tm time_struct;
if (localtime_pd(&seconds_since_19700101, &time_struct) == NULL) {
assert(false, "Failed localtime_pd");
return NULL;
}
const time_t seconds_per_minute = 60;
const time_t minutes_per_hour = 60;
const time_t seconds_per_hour = seconds_per_minute * minutes_per_hour;
time_t UTC_to_local = 0;
#if defined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE)
UTC_to_local = -(time_struct.tm_gmtoff);
#elif defined(_WINDOWS)
long zone;
_get_timezone(&zone);
UTC_to_local = static_cast<time_t>(zone);
#else
UTC_to_local = timezone;
#endif
#if !defined(_ALLBSD_SOURCE) && !defined(_GNU_SOURCE)
if (time_struct.tm_isdst > 0) {
UTC_to_local = UTC_to_local - seconds_per_hour;
}
#endif
const time_t local_to_UTC = -(UTC_to_local);
char sign_local_to_UTC = '+';
time_t abs_local_to_UTC = local_to_UTC;
if (local_to_UTC < 0) {
sign_local_to_UTC = '-';
abs_local_to_UTC = -(abs_local_to_UTC);
}
const time_t zone_hours = (abs_local_to_UTC / seconds_per_hour);
const time_t zone_min =
((abs_local_to_UTC % seconds_per_hour) / seconds_per_minute);
const int year = 1900 + time_struct.tm_year;
const int month = 1 + time_struct.tm_mon;
const int printed = jio_snprintf(buffer, buffer_length, iso8601_format,
year,
month,
time_struct.tm_mday,
time_struct.tm_hour,
time_struct.tm_min,
time_struct.tm_sec,
milliseconds_after_second,
sign_local_to_UTC,
zone_hours,
zone_min);
if (printed == 0) {
assert(false, "Failed jio_printf");
return NULL;
}
return buffer;
}
OSReturn os::set_priority(Thread* thread, ThreadPriority p) {
#ifdef ASSERT
if (!(!thread->is_Java_thread() ||
Thread::current() == thread ||
Threads_lock->owned_by_self()
|| thread->is_Compiler_thread()
)) {
assert(false, "possibility of dangling Thread pointer");
}
#endif
if (p >= MinPriority && p <= MaxPriority) {
int priority = java_to_os_priority[p];
return set_native_priority(thread, priority);
} else {
assert(false, "Should not happen");
return OS_ERR;
}
}
OSReturn os::get_priority(const Thread* const thread, ThreadPriority& priority) {
int p;
int os_prio;
OSReturn ret = get_native_priority(thread, &os_prio);
if (ret != OS_OK) return ret;
if (java_to_os_priority[MaxPriority] > java_to_os_priority[MinPriority]) {
for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] > os_prio; p--) ;
} else {
for (p = MaxPriority; p > MinPriority && java_to_os_priority[p] < os_prio; p--) ;
}
priority = (ThreadPriority)p;
return OS_OK;
}
#ifndef SIGBREAK
#define SIGBREAK SIGQUIT
#endif
static void signal_thread_entry(JavaThread* thread, TRAPS) {
os::set_priority(thread, NearMaxPriority);
while (true) {
int sig;
{
sig = os::signal_wait();
}
if (sig == os::sigexitnum_pd()) {
return;
}
switch (sig) {
case SIGBREAK: {
if (!DisableAttachMechanism && AttachListener::is_init_trigger()) {
continue;
}
VM_PrintThreads op;
VMThread::execute(&op);
VM_PrintJNI jni_op;
VMThread::execute(&jni_op);
VM_FindDeadlocks op1(tty);
VMThread::execute(&op1);
Universe::print_heap_at_SIGBREAK();
if (PrintClassHistogram) {
VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */);
VMThread::execute(&op1);
}
if (JvmtiExport::should_post_data_dump()) {
JvmtiExport::post_data_dump();
}
break;
}
default: {
HandleMark hm(THREAD);
Klass* k = SystemDictionary::resolve_or_null(vmSymbols::sun_misc_Signal(), THREAD);
KlassHandle klass (THREAD, k);
if (klass.not_null()) {
JavaValue result(T_VOID);
JavaCallArguments args;
args.push_int(sig);
JavaCalls::call_static(
&result,
klass,
vmSymbols::dispatch_name(),
vmSymbols::int_void_signature(),
&args,
THREAD
);
}
if (HAS_PENDING_EXCEPTION) {
if (tty != NULL) {
char klass_name[256];
char tmp_sig_name[16];
const char* sig_name = "UNKNOWN";
InstanceKlass::cast(PENDING_EXCEPTION->klass())->
name()->as_klass_external_name(klass_name, 256);
if (os::exception_name(sig, tmp_sig_name, 16) != NULL)
sig_name = tmp_sig_name;
warning("Exception %s occurred dispatching signal %s to handler"
"- the VM may need to be forcibly terminated",
klass_name, sig_name );
}
CLEAR_PENDING_EXCEPTION;
}
}
}
}
}
void os::init_before_ergo() {
initialize_initial_active_processor_count();
large_page_init();
VM_Version::init_before_ergo();
}
void os::signal_init() {
if (!ReduceSignalUsage) {
EXCEPTION_MARK;
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
const char thread_name[] = "Signal Dispatcher";
Handle string = java_lang_String::create_from_str(thread_name, CHECK);
Handle thread_group (THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
JavaCalls::call_special(&result, thread_oop,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
CHECK);
KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
JavaCalls::call_special(&result,
thread_group,
group,
vmSymbols::add_method_name(),
vmSymbols::thread_void_signature(),
thread_oop, // ARG 1
CHECK);
os::signal_init_pd();
{ MutexLocker mu(Threads_lock);
JavaThread* signal_thread = new JavaThread(&signal_thread_entry);
if (signal_thread == NULL || signal_thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
"unable to create new native thread");
}
java_lang_Thread::set_thread(thread_oop(), signal_thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
signal_thread->set_threadObj(thread_oop());
Threads::add(signal_thread);
Thread::start(signal_thread);
}
os::signal(SIGBREAK, os::user_handler());
}
}
void os::terminate_signal_thread() {
if (!ReduceSignalUsage)
signal_notify(sigexitnum_pd());
}
typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
extern struct JavaVM_ main_vm;
static void* _native_java_library = NULL;
void* os::native_java_library() {
if (_native_java_library == NULL) {
char buffer[JVM_MAXPATHLEN];
char ebuf[1024];
if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"verify")) {
dll_load(buffer, ebuf, sizeof(ebuf));
}
if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"java")) {
_native_java_library = dll_load(buffer, ebuf, sizeof(ebuf));
}
if (_native_java_library == NULL) {
vm_exit_during_initialization("Unable to load native library", ebuf);
}
#if defined(__OpenBSD__)
if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"net")) {
dll_load(buffer, ebuf, sizeof(ebuf));
}
#endif
}
static jboolean onLoaded = JNI_FALSE;
if (onLoaded) {
if (ThreadLocalStorage::is_initialized()) {
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(
JNI_OnLoad_t, dll_lookup(_native_java_library, onLoadSymbols[0]));
if (JNI_OnLoad != NULL) {
JavaThread* thread = JavaThread::current();
ThreadToNativeFromVM ttn(thread);
HandleMark hm(thread);
jint ver = (*JNI_OnLoad)(&main_vm, NULL);
onLoaded = JNI_TRUE;
if (!Threads::is_supported_jni_version_including_1_1(ver)) {
vm_exit_during_initialization("Unsupported JNI version");
}
}
}
}
return _native_java_library;
}
void* os::find_agent_function(AgentLibrary *agent_lib, bool check_lib,
const char *syms[], size_t syms_len) {
assert(agent_lib != NULL, "sanity check");
const char *lib_name;
void *handle = agent_lib->os_lib();
void *entryName = NULL;
char *agent_function_name;
size_t i;
lib_name = ((check_lib || agent_lib->is_static_lib()) ? agent_lib->name() : NULL);
for (i = 0; i < syms_len; i++) {
agent_function_name = build_agent_function_name(syms[i], lib_name, agent_lib->is_absolute_path());
if (agent_function_name == NULL) {
break;
}
entryName = dll_lookup(handle, agent_function_name);
FREE_C_HEAP_ARRAY(char, agent_function_name, mtThread);
if (entryName != NULL) {
break;
}
}
return entryName;
}
bool os::find_builtin_agent(AgentLibrary *agent_lib, const char *syms[],
size_t syms_len) {
void *ret;
void *proc_handle;
void *save_handle;
assert(agent_lib != NULL, "sanity check");
if (agent_lib->name() == NULL) {
return false;
}
proc_handle = get_default_process_handle();
save_handle = agent_lib->os_lib();
agent_lib->set_os_lib(proc_handle);
ret = find_agent_function(agent_lib, true, syms, syms_len);
if (ret != NULL) {
agent_lib->set_valid();
agent_lib->set_static_lib(true);
return true;
}
agent_lib->set_os_lib(save_handle);
return false;
}
char *os::strdup(const char *str, MEMFLAGS flags) {
size_t size = strlen(str);
char *dup_str = (char *)malloc(size + 1, flags);
if (dup_str == NULL) return NULL;
strcpy(dup_str, str);
return dup_str;
}
#define paranoid 0 /* only set to 1 if you suspect checking code has bug */
#ifdef ASSERT
static void verify_memory(void* ptr) {
GuardedMemory guarded(ptr);
if (!guarded.verify_guards()) {
tty->print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees);
tty->print_cr("## memory stomp:");
guarded.print_on(tty);
fatal("memory stomping error");
}
}
#endif
static u_char* testMalloc(size_t alloc_size) {
assert(MallocMaxTestWords > 0, "sanity check");
if ((cur_malloc_words + (alloc_size / BytesPerWord)) > MallocMaxTestWords) {
return NULL;
}
u_char* ptr = (u_char*)::malloc(alloc_size);
if (ptr != NULL) {
Atomic::add(((jint) (alloc_size / BytesPerWord)),
(volatile jint *) &cur_malloc_words);
}
return ptr;
}
void* os::malloc(size_t size, MEMFLAGS flags) {
return os::malloc(size, flags, CALLER_PC);
}
void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
assert(!os::ThreadCrashProtection::is_crash_protected(ThreadLocalStorage::thread()),
"malloc() not allowed when crash protection is set");
if (size == 0) {
size = 1;
}
NMT_TrackingLevel level = MemTracker::tracking_level();
size_t nmt_header_size = MemTracker::malloc_header_size(level);
#ifndef ASSERT
const size_t alloc_size = size + nmt_header_size;
#else
const size_t alloc_size = GuardedMemory::get_total_size(size + nmt_header_size);
if (size + nmt_header_size > alloc_size) { // Check for rollover.
return NULL;
}
#endif
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
u_char* ptr;
if (MallocMaxTestWords > 0) {
ptr = testMalloc(alloc_size);
} else {
ptr = (u_char*)::malloc(alloc_size);
}
#ifdef ASSERT
if (ptr == NULL) {
return NULL;
}
GuardedMemory guarded(ptr, size + nmt_header_size);
ptr = guarded.get_user_ptr();
#endif
if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
breakpoint();
}
debug_only(if (paranoid) verify_memory(ptr));
if (PrintMalloc && tty != NULL) {
tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
}
return MemTracker::record_malloc((address)ptr, size, memflags, stack, level);
}
void* os::realloc(void *memblock, size_t size, MEMFLAGS flags) {
return os::realloc(memblock, size, flags, CALLER_PC);
}
void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
#ifndef ASSERT
NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1));
NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size));
void* membase = MemTracker::record_free(memblock);
NMT_TrackingLevel level = MemTracker::tracking_level();
size_t nmt_header_size = MemTracker::malloc_header_size(level);
void* ptr = ::realloc(membase, size + nmt_header_size);
return MemTracker::record_malloc(ptr, size, memflags, stack, level);
#else
if (memblock == NULL) {
return os::malloc(size, memflags, stack);
}
if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
tty->print_cr("os::realloc caught " PTR_FORMAT, memblock);
breakpoint();
}
void* membase = MemTracker::malloc_base(memblock);
verify_memory(membase);
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
if (size == 0) {
return NULL;
}
void* ptr = os::malloc(size, memflags, stack);
if (PrintMalloc) {
tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
}
if ( ptr != NULL ) {
GuardedMemory guarded(MemTracker::malloc_base(memblock));
size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock);
memcpy(ptr, memblock, MIN2(size, memblock_size));
if (paranoid) verify_memory(MemTracker::malloc_base(ptr));
if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, ptr);
breakpoint();
}
os::free(memblock);
}
return ptr;
#endif
}
void os::free(void *memblock, MEMFLAGS memflags) {
NOT_PRODUCT(inc_stat_counter(&num_frees, 1));
#ifdef ASSERT
if (memblock == NULL) return;
if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, memblock);
breakpoint();
}
void* membase = MemTracker::record_free(memblock);
verify_memory(membase);
NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap());
GuardedMemory guarded(membase);
size_t size = guarded.get_user_size();
inc_stat_counter(&free_bytes, size);
membase = guarded.release_for_freeing();
if (PrintMalloc && tty != NULL) {
fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)membase);
}
::free(membase);
#else
void* membase = MemTracker::record_free(memblock);
::free(membase);
#endif
}
void os::init_random(long initval) {
_rand_seed = initval;
}
long os::random() {
const long a = 16807;
const unsigned long m = 2147483647;
const long q = m / a; assert(q == 127773, "weird math");
const long r = m % a; assert(r == 2836, "weird math");
unsigned long lo = a * (long)(_rand_seed & 0xFFFF);
unsigned long hi = a * (long)((unsigned long)_rand_seed >> 16);
lo += (hi & 0x7FFF) << 16;
if (lo > m) {
lo &= m;
++lo;
}
lo += hi >> 15;
if (lo > m) {
lo &= m;
++lo;
}
return (_rand_seed = lo);
}
void os::start_thread(Thread* thread) {
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
OSThread* osthread = thread->osthread();
osthread->set_state(RUNNABLE);
pd_start_thread(thread);
}
void os::print_hex_dump(outputStream* st, address start, address end, int unitsize) {
assert(unitsize == 1 || unitsize == 2 || unitsize == 4 || unitsize == 8, "just checking");
int cols = 0;
int cols_per_line = 0;
switch (unitsize) {
case 1: cols_per_line = 16; break;
case 2: cols_per_line = 8; break;
case 4: cols_per_line = 4; break;
case 8: cols_per_line = 2; break;
default: return;
}
address p = start;
st->print(PTR_FORMAT ": ", start);
while (p < end) {
switch (unitsize) {
case 1: st->print("%02x", *(u1*)p); break;
case 2: st->print("%04x", *(u2*)p); break;
case 4: st->print("%08x", *(u4*)p); break;
case 8: st->print("%016" FORMAT64_MODIFIER "x", *(u8*)p); break;
}
p += unitsize;
cols++;
if (cols >= cols_per_line && p < end) {
cols = 0;
st->cr();
st->print(PTR_FORMAT ": ", p);
} else {
st->print(" ");
}
}
st->cr();
}
void os::print_environment_variables(outputStream* st, const char** env_list,
char* buffer, int len) {
if (env_list) {
st->print_cr("Environment Variables:");
for (int i = 0; env_list[i] != NULL; i++) {
if (getenv(env_list[i], buffer, len)) {
st->print("%s", env_list[i]);
st->print("=");
st->print_cr("%s", buffer);
}
}
}
}
void os::print_cpu_info(outputStream* st) {
st->print("CPU:");
st->print("total %d", os::processor_count());
st->print(" (initial active %d)", _initial_active_processor_count);
st->print(" %s", VM_Version::cpu_features());
st->cr();
pd_print_cpu_info(st);
}
void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
const int secs_per_day = 86400;
const int secs_per_hour = 3600;
const int secs_per_min = 60;
time_t tloc;
(void)time(&tloc);
st->print("time: %s", ctime(&tloc)); // ctime adds newline.
struct tm tz;
if (localtime_pd(&tloc, &tz) != NULL) {
::strftime(buf, buflen, "%Z", &tz);
st->print_cr("timezone: %s", buf);
}
double t = os::elapsedTime();
int eltime = (int)t; // elapsed time in seconds
int eltimeFraction = (int) ((t - eltime) * 1000000);
int eldays = eltime / secs_per_day;
int day_secs = eldays * secs_per_day;
int elhours = (eltime - day_secs) / secs_per_hour;
int hour_secs = elhours * secs_per_hour;
int elmins = (eltime - day_secs - hour_secs) / secs_per_min;
int minute_secs = elmins * secs_per_min;
int elsecs = (eltime - day_secs - hour_secs - minute_secs);
st->print_cr("elapsed time: %d.%06d seconds (%dd %dh %dm %ds)", eltime, eltimeFraction, eldays, elhours, elmins, elsecs);
}
void os::print_location(outputStream* st, intptr_t x, bool verbose) {
address addr = (address)x;
CodeBlob* b = CodeCache::find_blob_unsafe(addr);
if (b != NULL) {
if (b->is_buffer_blob()) {
InterpreterCodelet* i = Interpreter::codelet_containing(addr);
if (i != NULL) {
st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an Interpreter codelet", addr, (int)(addr - i->code_begin()));
i->print_on(st);
return;
}
if (Interpreter::contains(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing into interpreter code"
" (not bytecode specific)", addr);
return;
}
if (AdapterHandlerLibrary::contains(b)) {
st->print_cr(INTPTR_FORMAT " is at code_begin+%d in an AdapterHandler", addr, (int)(addr - b->code_begin()));
AdapterHandlerLibrary::print_handler_on(st, b);
}
StubCodeDesc* d = StubCodeDesc::desc_for(addr);
if (d != NULL) {
st->print_cr(INTPTR_FORMAT " is at begin+%d in a stub", addr, (int)(addr - d->begin()));
d->print_on(st);
st->cr();
return;
}
if (StubRoutines::contains(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing to an (unnamed) "
"stub routine", addr);
return;
}
if (InlineCacheBuffer::contains(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing into InlineCacheBuffer", addr);
return;
}
VtableStub* v = VtableStubs::stub_containing(addr);
if (v != NULL) {
st->print_cr(INTPTR_FORMAT " is at entry_point+%d in a vtable stub", addr, (int)(addr - v->entry_point()));
v->print_on(st);
st->cr();
return;
}
}
nmethod* nm = b->as_nmethod_or_null();
if (nm != NULL) {
ResourceMark rm;
st->print(INTPTR_FORMAT " is at entry_point+%d in (nmethod*)" INTPTR_FORMAT,
addr, (int)(addr - nm->entry_point()), nm);
if (verbose) {
st->print(" for ");
nm->method()->print_value_on(st);
}
st->cr();
nm->print_nmethod(verbose);
return;
}
st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", addr, (int)(addr - b->code_begin()));
b->print_on(st);
return;
}
if (Universe::heap()->is_in(addr)) {
HeapWord* p = Universe::heap()->block_start(addr);
bool print = false;
if (p != NULL && Universe::heap()->block_is_obj(p)) {
print = true;
} else if (p == NULL && ((oopDesc*)addr)->is_oop()) {
p = (HeapWord*) addr;
print = true;
}
if (print) {
if (p == (HeapWord*) addr) {
st->print_cr(INTPTR_FORMAT " is an oop", addr);
} else {
st->print_cr(INTPTR_FORMAT " is pointing into object: " INTPTR_FORMAT, addr, p);
}
oop(p)->print_on(st);
return;
}
} else {
if (Universe::heap()->is_in_reserved(addr)) {
st->print_cr(INTPTR_FORMAT " is an unallocated location "
"in the heap", addr);
return;
}
}
if (JNIHandles::is_global_handle((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a global jni handle", addr);
return;
}
if (JNIHandles::is_weak_global_handle((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a weak global jni handle", addr);
return;
}
#ifndef PRODUCT
if (JNIHandleBlock::any_contains((jobject) addr)) {
st->print_cr(INTPTR_FORMAT " is a local jni handle", addr);
return;
}
#endif
for(JavaThread *thread = Threads::first(); thread; thread = thread->next()) {
if (thread->privileged_stack_top() != NULL &&
thread->privileged_stack_top()->contains(addr)) {
st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack "
"for thread: " INTPTR_FORMAT, addr, thread);
if (verbose) thread->print_on(st);
return;
}
if (addr == (address)thread) {
if (verbose) {
thread->print_on(st);
} else {
st->print_cr(INTPTR_FORMAT " is a thread", addr);
}
return;
}
if (thread->stack_base() >= addr &&
addr > (thread->stack_base() - thread->stack_size())) {
st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: "
INTPTR_FORMAT, addr, thread);
if (verbose) thread->print_on(st);
return;
}
}
if (Metaspace::contains(addr)) {
if (Method::has_method_vptr((const void*)addr)) {
((Method*)addr)->print_value_on(st);
st->cr();
} else {
st->print_cr(INTPTR_FORMAT " is pointing into metadata", addr);
}
return;
}
if (os::find(addr, st)) {
return;
}
st->print_cr(INTPTR_FORMAT " is an unknown value", addr);
}
bool os::is_first_C_frame(frame* fr) {
#if (defined(IA64) && !defined(AIX)) && !defined(_WIN32)
Thread *thread = Thread::current();
if ((address)fr->fp() <=
thread->register_stack_base() HPUX_ONLY(+ 0x0) LINUX_ONLY(+ 0x50)) {
return true;
} else {
return false;
}
#elif defined(IA64) && defined(_WIN32)
return true;
#else
uintptr_t fp_align_mask = (uintptr_t)(sizeof(address)-1);
uintptr_t sp_align_mask = (uintptr_t)(sizeof(int)-1);
uintptr_t usp = (uintptr_t)fr->sp();
if ((usp & sp_align_mask) != 0) return true;
uintptr_t ufp = (uintptr_t)fr->fp();
if ((ufp & fp_align_mask) != 0) return true;
uintptr_t old_sp = (uintptr_t)fr->sender_sp();
if ((old_sp & sp_align_mask) != 0) return true;
if (old_sp == 0 || old_sp == (uintptr_t)-1) return true;
uintptr_t old_fp = (uintptr_t)fr->link();
if ((old_fp & fp_align_mask) != 0) return true;
if (old_fp == 0 || old_fp == (uintptr_t)-1 || old_fp == ufp) return true;
if (old_fp < ufp) return true;
if (old_fp - ufp > 64 * K) return true;
return false;
#endif
}
#ifdef ASSERT
extern "C" void test_random() {
const double m = 2147483647;
double mean = 0.0, variance = 0.0, t;
long reps = 10000;
unsigned long seed = 1;
tty->print_cr("seed %ld for %ld repeats...", seed, reps);
os::init_random(seed);
long num;
for (int k = 0; k < reps; k++) {
num = os::random();
double u = (double)num / m;
assert(u >= 0.0 && u <= 1.0, "bad random number!");
mean += u;
variance += (u*u);
}
mean /= reps;
variance /= (reps - 1);
assert(num == 1043618065, "bad seed");
tty->print_cr("mean of the 1st 10000 numbers: %f", mean);
tty->print_cr("variance of the 1st 10000 numbers: %f", variance);
const double eps = 0.0001;
t = fabsd(mean - 0.5018);
assert(t < eps, "bad mean");
t = (variance - 0.3355) < 0.0 ? -(variance - 0.3355) : variance - 0.3355;
assert(t < eps, "bad variance");
}
#endif
char* os::format_boot_path(const char* format_string,
const char* home,
int home_len,
char fileSep,
char pathSep) {
assert((fileSep == '/' && pathSep == ':') ||
(fileSep == '\\' && pathSep == ';'), "unexpected seperator chars");
int formatted_path_len = 0;
const char* p;
for (p = format_string; *p != 0; ++p) {
if (*p == '%') formatted_path_len += home_len - 1;
++formatted_path_len;
}
char* formatted_path = NEW_C_HEAP_ARRAY(char, formatted_path_len + 1, mtInternal);
if (formatted_path == NULL) {
return NULL;
}
char* q = formatted_path;
for (p = format_string; *p != 0; ++p) {
switch (*p) {
case '%':
strcpy(q, home);
q += home_len;
break;
case '/':
break;
case ':':
break;
default:
}
}
assert((q - formatted_path) == formatted_path_len, "formatted_path size botched");
return formatted_path;
}
bool os::set_boot_path(char fileSep, char pathSep) {
const char* home = Arguments::get_java_home();
int home_len = (int)strlen(home);
static const char* meta_index_dir_format = "%/lib/";
static const char* meta_index_format = "%/lib/meta-index";
char* meta_index = format_boot_path(meta_index_format, home, home_len, fileSep, pathSep);
if (meta_index == NULL) return false;
char* meta_index_dir = format_boot_path(meta_index_dir_format, home, home_len, fileSep, pathSep);
if (meta_index_dir == NULL) return false;
Arguments::set_meta_index_path(meta_index, meta_index_dir);
static const char classpath_format[] =
"%/lib/resources.jar:"
"%/lib/rt.jar:"
"%/lib/sunrsasign.jar:"
"%/lib/jsse.jar:"
"%/lib/jce.jar:"
"%/lib/charsets.jar:"
"%/lib/jfr.jar:"
"%/classes";
char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep);
if (sysclasspath == NULL) return false;
Arguments::set_sysclasspath(sysclasspath);
return true;
}
char** os::split_path(const char* path, int* n) {
if (path == NULL || strlen(path) == 0) {
return NULL;
}
const char psepchar = *os::path_separator();
char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1, mtInternal);
if (inpath == NULL) {
return NULL;
}
strcpy(inpath, path);
int count = 1;
char* p = strchr(inpath, psepchar);
while (p != NULL) {
count++;
p++;
p = strchr(p, psepchar);
}
char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count, mtInternal);
if (opath == NULL) {
return NULL;
}
p = inpath;
for (int i = 0 ; i < count ; i++) {
size_t len = strcspn(p, os::path_separator());
if (len > JVM_MAXPATHLEN) {
return NULL;
}
char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
if (s == NULL) {
return NULL;
}
strncpy(s, p, len);
s[len] = '\0';
opath[i] = s;
p += len + 1;
}
FREE_C_HEAP_ARRAY(char, inpath, mtInternal);
return opath;
}
sssssssss73
最新推荐文章于 2024-10-11 10:08:02 发布