diff options
author | Mathieu Chartier <mathieuc@google.com> | 2014-12-11 18:43:48 -0800 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2014-12-12 12:08:16 -0800 |
commit | 9e2094f921b63582e84d65849b1c5c6dc4d22b44 (patch) | |
tree | 02613d533bdc382988b7fc70954c15c2ea4575aa | |
parent | 6b1497421c7c81cb9bf2ce077f1ef3d8ac24cfcb (diff) | |
download | art-9e2094f921b63582e84d65849b1c5c6dc4d22b44.zip art-9e2094f921b63582e84d65849b1c5c6dc4d22b44.tar.gz art-9e2094f921b63582e84d65849b1c5c6dc4d22b44.tar.bz2 |
Add ReferenceQueue test
Also cleaned up reference queue.
TODO: Add tests for missing functionality.
Bug: 10808403
Change-Id: I182f9cb69022fe542ea9e53d4c6d35cff90af332
-rw-r--r-- | build/Android.gtest.mk | 1 | ||||
-rw-r--r-- | runtime/gc/reference_queue.cc | 19 | ||||
-rw-r--r-- | runtime/gc/reference_queue.h | 17 | ||||
-rw-r--r-- | runtime/gc/reference_queue_test.cc | 85 |
4 files changed, 111 insertions, 11 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 340304a..1347849 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -102,6 +102,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/gc/accounting/card_table_test.cc \ runtime/gc/accounting/space_bitmap_test.cc \ runtime/gc/heap_test.cc \ + runtime/gc/reference_queue_test.cc \ runtime/gc/space/dlmalloc_space_base_test.cc \ runtime/gc/space/dlmalloc_space_static_test.cc \ runtime/gc/space/dlmalloc_space_random_test.cc \ diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc index 4003524..f4efe3c 100644 --- a/runtime/gc/reference_queue.cc +++ b/runtime/gc/reference_queue.cc @@ -91,15 +91,30 @@ mirror::Reference* ReferenceQueue::DequeuePendingReference() { void ReferenceQueue::Dump(std::ostream& os) const { mirror::Reference* cur = list_; os << "Reference starting at list_=" << list_ << "\n"; - while (cur != nullptr) { + if (cur == nullptr) { + return; + } + do { mirror::Reference* pending_next = cur->GetPendingNext(); - os << "PendingNext=" << pending_next; + os << "Reference= " << cur << " PendingNext=" << pending_next; if (cur->IsFinalizerReferenceInstance()) { os << " Zombie=" << cur->AsFinalizerReference()->GetZombie(); } os << "\n"; cur = pending_next; + } while (cur != list_); +} + +size_t ReferenceQueue::GetLength() const { + size_t count = 0; + mirror::Reference* cur = list_; + if (cur != nullptr) { + do { + ++count; + cur = cur->GetPendingNext(); + } while (cur != list_); } + return count; } void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references, diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h index 4ef8478..f7d89d0 100644 --- a/runtime/gc/reference_queue.h +++ b/runtime/gc/reference_queue.h @@ -56,12 +56,14 @@ class ReferenceQueue { // overhead. void EnqueueReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Enqueue a reference without checking that it is enqueable. void EnqueuePendingReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Dequeue the first reference (returns list_). mirror::Reference* DequeuePendingReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Enqueues finalizer references with white referents. White referents are blackened, moved to the - // zombie field, and the referent field is cleared. + // Enqueues finalizer references with white referents. White referents are blackened, moved to + // the zombie field, and the referent field is cleared. void EnqueueFinalizerReferences(ReferenceQueue* cleared_references, IsHeapReferenceMarkedCallback* is_marked_callback, MarkObjectCallback* mark_object_callback, void* arg) @@ -73,24 +75,22 @@ class ReferenceQueue { void ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Unlink the reference list clearing references objects with white referents. Cleared references + // Unlink the reference list clearing references objects with white referents. Cleared references // registered to a reference queue are scheduled for appending by the heap worker thread. void ClearWhiteReferences(ReferenceQueue* cleared_references, IsHeapReferenceMarkedCallback* is_marked_callback, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - void Dump(std::ostream& os) const - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void Dump(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + size_t GetLength() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsEmpty() const { return list_ == nullptr; } - void Clear() { list_ = nullptr; } - - mirror::Reference* GetList() { + mirror::Reference* GetList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return list_; } @@ -102,7 +102,6 @@ class ReferenceQueue { // Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously // calling AtomicEnqueueIfNotEnqueued. Mutex* const lock_; - // The actual reference list. Only a root for the mark compact GC since it will be null for other // GC types. mirror::Reference* list_; diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc new file mode 100644 index 0000000..888c0d2 --- /dev/null +++ b/runtime/gc/reference_queue_test.cc @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_runtime_test.h" +#include "reference_queue.h" +#include "handle_scope-inl.h" +#include "mirror/class-inl.h" +#include "scoped_thread_state_change.h" + +namespace art { +namespace gc { + +class ReferenceQueueTest : public CommonRuntimeTest {}; + +TEST_F(ReferenceQueueTest, EnqueueDequeue) { + Thread* self = Thread::Current(); + StackHandleScope<20> hs(self); + Mutex lock("Reference queue lock"); + ReferenceQueue queue(&lock); + ASSERT_TRUE(queue.IsEmpty()); + ScopedObjectAccess soa(self); + ASSERT_EQ(queue.GetLength(), 0U); + auto ref_class = hs.NewHandle( + Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;", + NullHandle<mirror::ClassLoader>())); + ASSERT_TRUE(ref_class.Get() != nullptr); + auto ref1(hs.NewHandle(ref_class->AllocObject(self)->AsReference())); + ASSERT_TRUE(ref1.Get() != nullptr); + auto ref2(hs.NewHandle(ref_class->AllocObject(self)->AsReference())); + ASSERT_TRUE(ref2.Get() != nullptr); + // FIFO ordering. + queue.EnqueuePendingReference(ref1.Get()); + ASSERT_TRUE(!queue.IsEmpty()); + ASSERT_EQ(queue.GetLength(), 1U); + queue.EnqueuePendingReference(ref2.Get()); + ASSERT_TRUE(!queue.IsEmpty()); + ASSERT_EQ(queue.GetLength(), 2U); + ASSERT_EQ(queue.DequeuePendingReference(), ref2.Get()); + ASSERT_TRUE(!queue.IsEmpty()); + ASSERT_EQ(queue.GetLength(), 1U); + ASSERT_EQ(queue.DequeuePendingReference(), ref1.Get()); + ASSERT_EQ(queue.GetLength(), 0U); + ASSERT_TRUE(queue.IsEmpty()); +} + +TEST_F(ReferenceQueueTest, Dump) { + Thread* self = Thread::Current(); + StackHandleScope<20> hs(self); + Mutex lock("Reference queue lock"); + ReferenceQueue queue(&lock); + ScopedObjectAccess soa(self); + queue.Dump(LOG(INFO)); + auto weak_ref_class = hs.NewHandle( + Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;", + NullHandle<mirror::ClassLoader>())); + ASSERT_TRUE(weak_ref_class.Get() != nullptr); + auto finalizer_ref_class = hs.NewHandle( + Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/FinalizerReference;", + NullHandle<mirror::ClassLoader>())); + ASSERT_TRUE(finalizer_ref_class.Get() != nullptr); + auto ref1(hs.NewHandle(weak_ref_class->AllocObject(self)->AsReference())); + ASSERT_TRUE(ref1.Get() != nullptr); + auto ref2(hs.NewHandle(finalizer_ref_class->AllocObject(self)->AsReference())); + ASSERT_TRUE(ref2.Get() != nullptr); + queue.EnqueuePendingReference(ref1.Get()); + queue.Dump(LOG(INFO)); + queue.EnqueuePendingReference(ref2.Get()); + queue.Dump(LOG(INFO)); +} + +} // namespace gc +} // namespace art |