summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--openjdkjvmti/deopt_manager.cc15
-rw-r--r--runtime/gc/heap.h1
-rw-r--r--runtime/gc/scoped_gc_critical_section.cc36
-rw-r--r--runtime/gc/scoped_gc_critical_section.h22
4 files changed, 60 insertions, 14 deletions
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index 2f24d7ea3d..d20c756522 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -40,6 +40,8 @@
#include "dex/dex_file_annotations.h"
#include "dex/modifiers.h"
#include "events-inl.h"
+#include "gc/heap.h"
+#include "gc/scoped_gc_critical_section.h"
#include "jit/jit.h"
#include "jni/jni_internal.h"
#include "mirror/class-inl.h"
@@ -266,29 +268,35 @@ void DeoptManager::WaitForDeoptimizationToFinish(art::Thread* self) {
deoptimization_status_lock_.ExclusiveUnlock(self);
}
+// Users should make sure that only gc-critical-section safe code is used while a
+// ScopedDeoptimizationContext exists.
class ScopedDeoptimizationContext : public art::ValueObject {
public:
ScopedDeoptimizationContext(art::Thread* self, DeoptManager* deopt)
RELEASE(deopt->deoptimization_status_lock_)
ACQUIRE(art::Locks::mutator_lock_)
ACQUIRE(art::Roles::uninterruptible_)
- : self_(self), deopt_(deopt), uninterruptible_cause_(nullptr) {
+ : self_(self),
+ deopt_(deopt),
+ critical_section_(self_, "JVMTI Deoptimizing methods"),
+ uninterruptible_cause_(nullptr) {
deopt_->WaitForDeoptimizationToFinishLocked(self_);
DCHECK(!deopt->performing_deoptimization_)
<< "Already performing deoptimization on another thread!";
// Use performing_deoptimization_ to keep track of the lock.
deopt_->performing_deoptimization_ = true;
deopt_->deoptimization_status_lock_.Unlock(self_);
+ uninterruptible_cause_ = critical_section_.Enter(art::gc::kGcCauseInstrumentation,
+ art::gc::kCollectorTypeCriticalSection);
art::Runtime::Current()->GetThreadList()->SuspendAll("JMVTI Deoptimizing methods",
/*long_suspend*/ false);
- uninterruptible_cause_ = self_->StartAssertNoThreadSuspension("JVMTI deoptimizing methods");
}
~ScopedDeoptimizationContext()
RELEASE(art::Locks::mutator_lock_)
RELEASE(art::Roles::uninterruptible_) {
// Can be suspended again.
- self_->EndAssertNoThreadSuspension(uninterruptible_cause_);
+ critical_section_.Exit(uninterruptible_cause_);
// Release the mutator lock.
art::Runtime::Current()->GetThreadList()->ResumeAll();
// Let other threads know it's fine to proceed.
@@ -300,6 +308,7 @@ class ScopedDeoptimizationContext : public art::ValueObject {
private:
art::Thread* self_;
DeoptManager* deopt_;
+ art::gc::GCCriticalSection critical_section_;
const char* uninterruptible_cause_;
};
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d01437299f..5c34c56e09 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -1425,6 +1425,7 @@ class Heap {
friend class collector::ConcurrentCopying;
friend class collector::MarkSweep;
friend class collector::SemiSpace;
+ friend class GCCriticalSection;
friend class ReferenceQueue;
friend class ScopedGCCriticalSection;
friend class VerifyReferenceCardVisitor;
diff --git a/runtime/gc/scoped_gc_critical_section.cc b/runtime/gc/scoped_gc_critical_section.cc
index 2976dd0252..7a0a6e8736 100644
--- a/runtime/gc/scoped_gc_critical_section.cc
+++ b/runtime/gc/scoped_gc_critical_section.cc
@@ -24,21 +24,39 @@
namespace art {
namespace gc {
-ScopedGCCriticalSection::ScopedGCCriticalSection(Thread* self,
- GcCause cause,
- CollectorType collector_type)
- : self_(self) {
- Runtime::Current()->GetHeap()->StartGC(self, cause, collector_type);
- if (self != nullptr) {
- old_cause_ = self->StartAssertNoThreadSuspension("ScopedGCCriticalSection");
+const char* GCCriticalSection::Enter(GcCause cause, CollectorType type) {
+ Runtime::Current()->GetHeap()->StartGC(self_, cause, type);
+ if (self_ != nullptr) {
+ return self_->StartAssertNoThreadSuspension(section_name_);
+ } else {
+ // Workaround to avoid having to mark the whole function as NO_THREAD_SAFETY_ANALYSIS.
+ auto kludge = []() ACQUIRE(Roles::uninterruptible_) NO_THREAD_SAFETY_ANALYSIS {};
+ kludge();
+ return nullptr;
}
}
-ScopedGCCriticalSection::~ScopedGCCriticalSection() {
+
+void GCCriticalSection::Exit(const char* old_cause) {
if (self_ != nullptr) {
- self_->EndAssertNoThreadSuspension(old_cause_);
+ self_->EndAssertNoThreadSuspension(old_cause);
+ } else {
+ // Workaround to avoid having to mark the whole function as NO_THREAD_SAFETY_ANALYSIS.
+ auto kludge = []() RELEASE(Roles::uninterruptible_) NO_THREAD_SAFETY_ANALYSIS {};
+ kludge();
}
Runtime::Current()->GetHeap()->FinishGC(self_, collector::kGcTypeNone);
}
+ScopedGCCriticalSection::ScopedGCCriticalSection(Thread* self,
+ GcCause cause,
+ CollectorType collector_type)
+ : critical_section_(self, "ScopedGCCriticalSection") {
+ old_no_suspend_reason_ = critical_section_.Enter(cause, collector_type);
+}
+
+ScopedGCCriticalSection::~ScopedGCCriticalSection() {
+ critical_section_.Exit(old_no_suspend_reason_);
+}
+
} // namespace gc
} // namespace art
diff --git a/runtime/gc/scoped_gc_critical_section.h b/runtime/gc/scoped_gc_critical_section.h
index 1271ff7af3..864bf878f6 100644
--- a/runtime/gc/scoped_gc_critical_section.h
+++ b/runtime/gc/scoped_gc_critical_section.h
@@ -27,6 +27,24 @@ class Thread;
namespace gc {
+// The use of ScopedGCCriticalSection should be preferred whenever possible.
+class GCCriticalSection {
+ public:
+ GCCriticalSection(Thread* self, const char* name)
+ : self_(self), section_name_(name) {}
+ ~GCCriticalSection() {}
+
+ // Starts a GCCriticalSection. Returns the previous no-suspension reason.
+ const char* Enter(GcCause cause, CollectorType type) ACQUIRE(Roles::uninterruptible_);
+
+ // Ends a GCCriticalSection. Takes the old no-suspension reason.
+ void Exit(const char* old_reason) RELEASE(Roles::uninterruptible_);
+
+ private:
+ Thread* const self_;
+ const char* section_name_;
+};
+
// Wait until the GC is finished and then prevent the GC from starting until the destructor. Used
// to prevent deadlocks in places where we call ClassLinker::VisitClass with all the threads
// suspended.
@@ -37,8 +55,8 @@ class ScopedGCCriticalSection {
~ScopedGCCriticalSection() RELEASE(Roles::uninterruptible_);
private:
- Thread* const self_;
- const char* old_cause_;
+ GCCriticalSection critical_section_;
+ const char* old_no_suspend_reason_;
};
} // namespace gc