Revert "Revert "Make JVMTI DisposeEnvironment and GetEnv thread safe.""
This reverts commit af9341087aab0146b8323ece156bde8130948465.
We needed to allow TopLockLevel locks to be acquired when the
mutator_lock_ is exclusive held. This is required for spec
conformance. To ensure there are no deadlocks the mutator_lock_ is the
only lock level with this exception and one cannot acquire the
mutator_lock_ when one holds any kTopLockLevel locks.
Reason for revert: Fixed issue causing test 913 failure in art-gc-gss-tlab
Test: ART_DEFAULT_GC_TYPE=GSS \
ART_USE_TLAB=true \
ART_USE_READ_BARRIER=false
./test.py --host -j50
Bug: 69465262
Change-Id: Ic1a4d9bb3ff64382ba7ae22ba27a4f44628ed095
diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h
index a99ed7b..c73215f 100644
--- a/openjdkjvmti/events.h
+++ b/openjdkjvmti/events.h
@@ -158,6 +158,10 @@
void HandleChangedCapabilities(const jvmtiCapabilities& caps, bool caps_added);
};
+namespace impl {
+template <ArtJvmtiEvent kEvent> struct EventHandlerFunc { };
+} // namespace impl
+
// Helper class for event handling.
class EventHandler {
public:
@@ -169,10 +173,10 @@
// Register an env. It is assumed that this happens on env creation, that is, no events are
// enabled, yet.
- void RegisterArtJvmTiEnv(ArtJvmTiEnv* env);
+ void RegisterArtJvmTiEnv(ArtJvmTiEnv* env) REQUIRES(!envs_lock_);
// Remove an env.
- void RemoveArtJvmTiEnv(ArtJvmTiEnv* env);
+ void RemoveArtJvmTiEnv(ArtJvmTiEnv* env) REQUIRES(!envs_lock_);
bool IsEventEnabledAnywhere(ArtJvmtiEvent event) const {
if (!EventMask::EventIsInRange(event)) {
@@ -184,13 +188,15 @@
jvmtiError SetEvent(ArtJvmTiEnv* env,
art::Thread* thread,
ArtJvmtiEvent event,
- jvmtiEventMode mode);
+ jvmtiEventMode mode)
+ REQUIRES(!envs_lock_);
// Dispatch event to all registered environments. Since this one doesn't have a JNIEnv* it doesn't
// matter if it has the mutator_lock.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- inline void DispatchEvent(art::Thread* thread, Args... args) const;
+ inline void DispatchEvent(art::Thread* thread, Args... args) const
+ REQUIRES(!envs_lock_);
// Dispatch event to all registered environments stashing exceptions as needed. This works since
// JNIEnv* is always the second argument if it is passed to an event. Needed since C++ does not
@@ -200,7 +206,8 @@
// the event to allocate local references.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- inline void DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const;
+ inline void DispatchEvent(art::Thread* thread, JNIEnv* jnienv, Args... args) const
+ REQUIRES(!envs_lock_);
// Tell the event handler capabilities were added/lost so it can adjust the sent events.If
// caps_added is true then caps is all the newly set capabilities of the jvmtiEnv. If it is false
@@ -208,30 +215,50 @@
ALWAYS_INLINE
inline void HandleChangedCapabilities(ArtJvmTiEnv* env,
const jvmtiCapabilities& caps,
- bool added);
+ bool added)
+ REQUIRES(!envs_lock_);
// Dispatch event to the given environment, only.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- inline void DispatchEventOnEnv(
- ArtJvmTiEnv* env, art::Thread* thread, JNIEnv* jnienv, Args... args) const;
+ inline void DispatchEventOnEnv(ArtJvmTiEnv* env,
+ art::Thread* thread,
+ JNIEnv* jnienv,
+ Args... args) const
+ REQUIRES(!envs_lock_);
// Dispatch event to the given environment, only.
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- inline void DispatchEventOnEnv(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const;
+ inline void DispatchEventOnEnv(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const
+ REQUIRES(!envs_lock_);
private:
+ template <ArtJvmtiEvent kEvent, typename ...Args>
+ ALWAYS_INLINE
+ inline std::vector<impl::EventHandlerFunc<kEvent>> CollectEvents(art::Thread* thread,
+ Args... args) const
+ REQUIRES(!envs_lock_);
+
template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE
- static inline bool ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread);
+ inline bool ShouldDispatchOnThread(ArtJvmTiEnv* env, art::Thread* thread) const;
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
- static inline void ExecuteCallback(ArtJvmTiEnv* env, Args... args);
+ static inline void ExecuteCallback(impl::EventHandlerFunc<kEvent> handler,
+ JNIEnv* env,
+ Args... args)
+ REQUIRES(!envs_lock_);
template <ArtJvmtiEvent kEvent, typename ...Args>
ALWAYS_INLINE
+ static inline void ExecuteCallback(impl::EventHandlerFunc<kEvent> handler, Args... args)
+ REQUIRES(!envs_lock_);
+
+ // Public for use to collect dispatches
+ template <ArtJvmtiEvent kEvent, typename ...Args>
+ ALWAYS_INLINE
inline bool ShouldDispatch(ArtJvmTiEnv* env, art::Thread* thread, Args... args) const;
ALWAYS_INLINE
@@ -241,7 +268,9 @@
// Recalculates the event mask for the given event.
ALWAYS_INLINE
- inline void RecalculateGlobalEventMask(ArtJvmtiEvent event);
+ inline void RecalculateGlobalEventMask(ArtJvmtiEvent event) REQUIRES(!envs_lock_);
+ ALWAYS_INLINE
+ inline void RecalculateGlobalEventMaskLocked(ArtJvmtiEvent event) REQUIRES(envs_lock_);
template <ArtJvmtiEvent kEvent>
ALWAYS_INLINE inline void DispatchClassFileLoadHookEvent(art::Thread* thread,
@@ -253,7 +282,8 @@
jint class_data_len,
const unsigned char* class_data,
jint* new_class_data_len,
- unsigned char** new_class_data) const;
+ unsigned char** new_class_data) const
+ REQUIRES(!envs_lock_);
void HandleEventType(ArtJvmtiEvent event, bool enable);
void HandleLocalAccessCapabilityAdded();
@@ -261,10 +291,13 @@
bool OtherMonitorEventsEnabledAnywhere(ArtJvmtiEvent event);
- // List of all JvmTiEnv objects that have been created, in their creation order.
- // NB Some elements might be null representing envs that have been deleted. They should be skipped
- // anytime this list is used.
- std::vector<ArtJvmTiEnv*> envs;
+ // List of all JvmTiEnv objects that have been created, in their creation order. It is a std::list
+ // since we mostly access it by iterating over the entire thing, only ever append to the end, and
+ // need to be able to remove arbitrary elements from it.
+ std::list<ArtJvmTiEnv*> envs GUARDED_BY(envs_lock_);
+
+ // Top level lock. Nothing at all should be held when we lock this.
+ mutable art::Mutex envs_lock_ ACQUIRED_BEFORE(art::Locks::instrument_entrypoints_lock_);
// A union of all enabled events, anywhere.
EventMask global_mask;