提交 7933877a 编写于 作者: K kamg

7017640: Fix for 6766644 deadlocks on some NSK tests when running with -Xcomp

Summary: Dynamic-code generated events should be deferred and processed by service thread
Reviewed-by: dsamersoff, dcubed
上级 20602f04
...@@ -1805,6 +1805,10 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID metho ...@@ -1805,6 +1805,10 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID metho
void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) { void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
JavaThread* thread = JavaThread::current(); JavaThread* thread = JavaThread::current();
// In theory everyone coming thru here is in_vm but we need to be certain
// because a callee will do a vm->native transition
ThreadInVMfromUnknown __tiv;
EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED, EVT_TRIG_TRACE(JVMTI_EVENT_DYNAMIC_CODE_GENERATED,
("JVMTI [%s] method dynamic code generated event triggered", ("JVMTI [%s] method dynamic code generated event triggered",
JvmtiTrace::safe_get_thread_name(thread))); JvmtiTrace::safe_get_thread_name(thread)));
...@@ -1826,19 +1830,18 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v ...@@ -1826,19 +1830,18 @@ void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const v
} }
void JvmtiExport::post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) { void JvmtiExport::post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) {
// In theory everyone coming thru here is in_vm but we need to be certain
// because a callee will do a vm->native transition
ThreadInVMfromUnknown __tiv;
jvmtiPhase phase = JvmtiEnv::get_phase(); jvmtiPhase phase = JvmtiEnv::get_phase();
if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) { if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) {
post_dynamic_code_generated_internal(name, code_begin, code_end); post_dynamic_code_generated_internal(name, code_begin, code_end);
return; } else {
// It may not be safe to post the event from this thread. Defer all
// postings to the service thread so that it can perform them in a safe
// context and in-order.
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
JvmtiDeferredEvent event = JvmtiDeferredEvent::dynamic_code_generated_event(
name, code_begin, code_end);
JvmtiDeferredEventQueue::enqueue(event);
} }
// Blocks until everything now in the queue has been posted
JvmtiDeferredEventQueue::flush_queue(Thread::current());
post_dynamic_code_generated_internal(name, code_begin, code_end);
} }
......
...@@ -140,12 +140,12 @@ class JvmtiExport : public AllStatic { ...@@ -140,12 +140,12 @@ class JvmtiExport : public AllStatic {
char sig_type, jvalue *value); char sig_type, jvalue *value);
private:
// posts a DynamicCodeGenerated event (internal/private implementation). // posts a DynamicCodeGenerated event (internal/private implementation).
// The public post_dynamic_code_generated* functions make use of the // The public post_dynamic_code_generated* functions make use of the
// internal implementation. // internal implementation. Also called from JvmtiDeferredEvent::post()
static void post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) KERNEL_RETURN; static void post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) KERNEL_RETURN;
private:
// GenerateEvents support to allow posting of CompiledMethodLoad and // GenerateEvents support to allow posting of CompiledMethodLoad and
// DynamicCodeGenerated events for a given environment. // DynamicCodeGenerated events for a given environment.
......
...@@ -918,7 +918,7 @@ void JvmtiSuspendControl::print() { ...@@ -918,7 +918,7 @@ void JvmtiSuspendControl::print() {
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
nmethod* nm) { nmethod* nm) {
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD); JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
event.set_compiled_method_load(nm); event._event_data.compiled_method_load = nm;
nmethodLocker::lock_nmethod(nm); // will be unlocked when posted nmethodLocker::lock_nmethod(nm); // will be unlocked when posted
return event; return event;
} }
...@@ -926,23 +926,39 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event( ...@@ -926,23 +926,39 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event( JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event(
jmethodID id, const void* code) { jmethodID id, const void* code) {
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD); JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_UNLOAD);
event.set_compiled_method_unload(id, code); event._event_data.compiled_method_unload.method_id = id;
event._event_data.compiled_method_unload.code_begin = code;
return event;
}
JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event(
const char* name, const void* code_begin, const void* code_end) {
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_DYNAMIC_CODE_GENERATED);
event._event_data.dynamic_code_generated.name = name;
event._event_data.dynamic_code_generated.code_begin = code_begin;
event._event_data.dynamic_code_generated.code_end = code_end;
return event; return event;
} }
void JvmtiDeferredEvent::post() { void JvmtiDeferredEvent::post() {
assert(ServiceThread::is_service_thread(Thread::current()),
"Service thread must post enqueued events");
switch(_type) { switch(_type) {
case TYPE_COMPILED_METHOD_LOAD: case TYPE_COMPILED_METHOD_LOAD: {
JvmtiExport::post_compiled_method_load(compiled_method_load()); nmethod* nm = _event_data.compiled_method_load;
nmethodLocker::unlock_nmethod(compiled_method_load()); JvmtiExport::post_compiled_method_load(nm);
nmethodLocker::unlock_nmethod(nm);
break; break;
}
case TYPE_COMPILED_METHOD_UNLOAD: case TYPE_COMPILED_METHOD_UNLOAD:
JvmtiExport::post_compiled_method_unload( JvmtiExport::post_compiled_method_unload(
compiled_method_unload_method_id(), _event_data.compiled_method_unload.method_id,
compiled_method_unload_code_begin()); _event_data.compiled_method_unload.code_begin);
break; break;
case TYPE_FLUSH: case TYPE_DYNAMIC_CODE_GENERATED:
JvmtiDeferredEventQueue::flush_complete(flush_state_addr()); JvmtiExport::post_dynamic_code_generated_internal(
_event_data.dynamic_code_generated.name,
_event_data.dynamic_code_generated.code_begin,
_event_data.dynamic_code_generated.code_end);
break; break;
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
...@@ -1065,54 +1081,4 @@ void JvmtiDeferredEventQueue::process_pending_events() { ...@@ -1065,54 +1081,4 @@ void JvmtiDeferredEventQueue::process_pending_events() {
} }
} }
enum {
// Random - used for debugging
FLUSHING = 0x50403020,
FLUSHED = 0x09080706
};
void JvmtiDeferredEventQueue::flush_queue(Thread* thread) {
volatile int flush_state = FLUSHING;
JvmtiDeferredEvent flush(JvmtiDeferredEvent::TYPE_FLUSH);
flush.set_flush_state_addr((int*)&flush_state);
if (ServiceThread::is_service_thread(thread)) {
// If we are the service thread we have to post all preceding events
// Use the flush event as a token to indicate when we can stop
JvmtiDeferredEvent event;
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
enqueue(flush);
event = dequeue();
}
while (!event.is_flush_event() ||
event.flush_state_addr() != &flush_state) {
event.post();
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
event = dequeue();
}
}
} else {
// Wake up the service thread so it will process events. When it gets
// to the flush event it will set 'flush_complete' and notify us.
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
enqueue(flush);
while (flush_state != FLUSHED) {
assert(flush_state == FLUSHING || flush_state == FLUSHED,
"only valid values for this");
Service_lock->wait(Mutex::_no_safepoint_check_flag);
}
}
}
void JvmtiDeferredEventQueue::flush_complete(int* state_addr) {
assert(state_addr != NULL && *state_addr == FLUSHING, "must be");
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
*state_addr = FLUSHED;
Service_lock->notify_all();
}
#endif // ndef KERNEL #endif // ndef KERNEL
...@@ -451,7 +451,7 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC { ...@@ -451,7 +451,7 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
TYPE_NONE, TYPE_NONE,
TYPE_COMPILED_METHOD_LOAD, TYPE_COMPILED_METHOD_LOAD,
TYPE_COMPILED_METHOD_UNLOAD, TYPE_COMPILED_METHOD_UNLOAD,
TYPE_FLUSH // pseudo-event used to implement flush_queue() TYPE_DYNAMIC_CODE_GENERATED
} Type; } Type;
Type _type; Type _type;
...@@ -461,49 +461,15 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC { ...@@ -461,49 +461,15 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
jmethodID method_id; jmethodID method_id;
const void* code_begin; const void* code_begin;
} compiled_method_unload; } compiled_method_unload;
int* flush_state_addr; struct {
const char* name;
const void* code_begin;
const void* code_end;
} dynamic_code_generated;
} _event_data; } _event_data;
JvmtiDeferredEvent(Type t) : _type(t) {} JvmtiDeferredEvent(Type t) : _type(t) {}
void set_compiled_method_load(nmethod* nm) {
assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
_event_data.compiled_method_load = nm;
}
nmethod* compiled_method_load() const {
assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be");
return _event_data.compiled_method_load;
}
void set_compiled_method_unload(jmethodID id, const void* code) {
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
_event_data.compiled_method_unload.method_id = id;
_event_data.compiled_method_unload.code_begin = code;
}
jmethodID compiled_method_unload_method_id() const {
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
return _event_data.compiled_method_unload.method_id;
}
const void* compiled_method_unload_code_begin() const {
assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be");
return _event_data.compiled_method_unload.code_begin;
}
bool is_flush_event() const { return _type == TYPE_FLUSH; }
int* flush_state_addr() const {
assert(is_flush_event(), "must be");
return _event_data.flush_state_addr;
}
void set_flush_state_addr(int* flag) {
assert(is_flush_event(), "must be");
_event_data.flush_state_addr = flag;
}
public: public:
JvmtiDeferredEvent() : _type(TYPE_NONE) {} JvmtiDeferredEvent() : _type(TYPE_NONE) {}
...@@ -513,6 +479,9 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC { ...@@ -513,6 +479,9 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
KERNEL_RETURN_(JvmtiDeferredEvent()); KERNEL_RETURN_(JvmtiDeferredEvent());
static JvmtiDeferredEvent compiled_method_unload_event( static JvmtiDeferredEvent compiled_method_unload_event(
jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent()); jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent());
static JvmtiDeferredEvent dynamic_code_generated_event(
const char* name, const void* begin, const void* end)
KERNEL_RETURN_(JvmtiDeferredEvent());
// Actually posts the event. // Actually posts the event.
void post() KERNEL_RETURN; void post() KERNEL_RETURN;
...@@ -548,25 +517,12 @@ class JvmtiDeferredEventQueue : AllStatic { ...@@ -548,25 +517,12 @@ class JvmtiDeferredEventQueue : AllStatic {
// Transfers events from the _pending_list to the _queue. // Transfers events from the _pending_list to the _queue.
static void process_pending_events() KERNEL_RETURN; static void process_pending_events() KERNEL_RETURN;
static void flush_complete(int* flush_state) KERNEL_RETURN;
public: public:
// Must be holding Service_lock when calling these // Must be holding Service_lock when calling these
static bool has_events() KERNEL_RETURN_(false); static bool has_events() KERNEL_RETURN_(false);
static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN; static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN;
static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent()); static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent());
// This call blocks until all events enqueued prior to this call
// have been posted. The Service_lock is acquired and waited upon.
//
// Implemented by creating a "flush" event and placing it in the queue.
// When the flush event is "posted" it will call flush_complete(), which
// will release the caller.
//
// Can be called by any thread (maybe even the service thread itself).
// Not necessary for the caller to be a JavaThread.
static void flush_queue(Thread* current) KERNEL_RETURN;
// Used to enqueue events without using a lock, for times (such as during // Used to enqueue events without using a lock, for times (such as during
// safepoint) when we can't or don't want to lock the Service_lock. // safepoint) when we can't or don't want to lock the Service_lock.
// //
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册