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
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Thu Feb 24 21:38:37 2011 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Sat Feb 26 13:33:23 2011 -0500
@@ -1805,6 +1805,10 @@
void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
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,
("JVMTI [%s] method dynamic code generated event triggered",
JvmtiTrace::safe_get_thread_name(thread)));
@@ -1826,19 +1830,18 @@
}
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();
if (phase == JVMTI_PHASE_PRIMORDIAL || phase == JVMTI_PHASE_START) {
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);
}
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp Thu Feb 24 21:38:37 2011 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp Sat Feb 26 13:33:23 2011 -0500
@@ -140,12 +140,12 @@
char sig_type, jvalue *value);
- private:
// posts a DynamicCodeGenerated event (internal/private implementation).
// 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;
+ private:
// GenerateEvents support to allow posting of CompiledMethodLoad and
// DynamicCodeGenerated events for a given environment.
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Thu Feb 24 21:38:37 2011 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Sat Feb 26 13:33:23 2011 -0500
@@ -918,7 +918,7 @@
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
nmethod* nm) {
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
return event;
}
@@ -926,23 +926,39 @@
JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_unload_event(
jmethodID id, const void* code) {
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;
}
void JvmtiDeferredEvent::post() {
+ assert(ServiceThread::is_service_thread(Thread::current()),
+ "Service thread must post enqueued events");
switch(_type) {
- case TYPE_COMPILED_METHOD_LOAD:
- JvmtiExport::post_compiled_method_load(compiled_method_load());
- nmethodLocker::unlock_nmethod(compiled_method_load());
+ case TYPE_COMPILED_METHOD_LOAD: {
+ nmethod* nm = _event_data.compiled_method_load;
+ JvmtiExport::post_compiled_method_load(nm);
+ nmethodLocker::unlock_nmethod(nm);
break;
+ }
case TYPE_COMPILED_METHOD_UNLOAD:
JvmtiExport::post_compiled_method_unload(
- compiled_method_unload_method_id(),
- compiled_method_unload_code_begin());
+ _event_data.compiled_method_unload.method_id,
+ _event_data.compiled_method_unload.code_begin);
break;
- case TYPE_FLUSH:
- JvmtiDeferredEventQueue::flush_complete(flush_state_addr());
+ case TYPE_DYNAMIC_CODE_GENERATED:
+ 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;
default:
ShouldNotReachHere();
@@ -1065,54 +1081,4 @@
}
}
-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
--- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp Thu Feb 24 21:38:37 2011 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp Sat Feb 26 13:33:23 2011 -0500
@@ -451,7 +451,7 @@
TYPE_NONE,
TYPE_COMPILED_METHOD_LOAD,
TYPE_COMPILED_METHOD_UNLOAD,
- TYPE_FLUSH // pseudo-event used to implement flush_queue()
+ TYPE_DYNAMIC_CODE_GENERATED
} Type;
Type _type;
@@ -461,49 +461,15 @@
jmethodID method_id;
const void* code_begin;
} compiled_method_unload;
- int* flush_state_addr;
+ struct {
+ const char* name;
+ const void* code_begin;
+ const void* code_end;
+ } dynamic_code_generated;
} _event_data;
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:
JvmtiDeferredEvent() : _type(TYPE_NONE) {}
@@ -513,6 +479,9 @@
KERNEL_RETURN_(JvmtiDeferredEvent());
static JvmtiDeferredEvent compiled_method_unload_event(
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.
void post() KERNEL_RETURN;
@@ -548,25 +517,12 @@
// Transfers events from the _pending_list to the _queue.
static void process_pending_events() KERNEL_RETURN;
- static void flush_complete(int* flush_state) KERNEL_RETURN;
-
public:
// Must be holding Service_lock when calling these
static bool has_events() KERNEL_RETURN_(false);
static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN;
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
// safepoint) when we can't or don't want to lock the Service_lock.
//