Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: Source/platform/heap/HeapTest.cpp

Issue 371623002: [oilpan]: Make thread shutdown more robust. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 1679 matching lines...) Expand 10 before | Expand all | Expand 10 after
1690 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 1690 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
1691 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls); 1691 EXPECT_EQ(2, HeapTestSubClass::s_destructorCalls);
1692 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls); 1692 EXPECT_EQ(3, HeapTestSuperClass::s_destructorCalls);
1693 } 1693 }
1694 1694
1695 TEST(HeapTest, TypedHeapSanity) 1695 TEST(HeapTest, TypedHeapSanity)
1696 { 1696 {
1697 // We use TraceCounter for allocating an object on the general heap. 1697 // We use TraceCounter for allocating an object on the general heap.
1698 Persistent<TraceCounter> generalHeapObject = TraceCounter::create(); 1698 Persistent<TraceCounter> generalHeapObject = TraceCounter::create();
1699 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create( ); 1699 Persistent<TestTypedHeapClass> typedHeapObject = TestTypedHeapClass::create( );
1700 EXPECT_NE(pageHeaderAddress(reinterpret_cast<Address>(generalHeapObject.get( ))), 1700 EXPECT_NE(pageHeaderFromObject(generalHeapObject.get()),
1701 pageHeaderAddress(reinterpret_cast<Address>(typedHeapObject.get()))); 1701 pageHeaderFromObject(typedHeapObject.get()));
1702 } 1702 }
1703 1703
1704 TEST(HeapTest, NoAllocation) 1704 TEST(HeapTest, NoAllocation)
1705 { 1705 {
1706 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed()); 1706 EXPECT_TRUE(ThreadState::current()->isAllocationAllowed());
1707 { 1707 {
1708 // Disallow allocation 1708 // Disallow allocation
1709 NoAllocationScope<AnyThread> noAllocationScope; 1709 NoAllocationScope<AnyThread> noAllocationScope;
1710 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed()); 1710 EXPECT_FALSE(ThreadState::current()->isAllocationAllowed());
1711 } 1711 }
(...skipping 1710 matching lines...) Expand 10 before | Expand all | Expand 10 after
3422 { 3422 {
3423 HeapStats initialHeapSize; 3423 HeapStats initialHeapSize;
3424 IntWrapper::s_destructorCalls = 0; 3424 IntWrapper::s_destructorCalls = 0;
3425 3425
3426 typedef HeapVector<Member<IntWrapper> > Vec; 3426 typedef HeapVector<Member<IntWrapper> > Vec;
3427 typedef PersistentHeapVector<Member<IntWrapper> > PVec; 3427 typedef PersistentHeapVector<Member<IntWrapper> > PVec;
3428 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet; 3428 typedef PersistentHeapHashSet<Member<IntWrapper> > PSet;
3429 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet; 3429 typedef PersistentHeapListHashSet<Member<IntWrapper> > PListSet;
3430 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet; 3430 typedef PersistentHeapLinkedHashSet<Member<IntWrapper> > PLinkedSet;
3431 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap; 3431 typedef PersistentHeapHashMap<Member<IntWrapper>, Member<IntWrapper> > PMap;
3432 typedef PersistentHeapHashMap<WeakMember<IntWrapper>, Member<IntWrapper> > W eakPMap;
3432 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque; 3433 typedef PersistentHeapDeque<Member<IntWrapper> > PDeque;
3433 3434
3434 clearOutOldGarbage(&initialHeapSize); 3435 clearOutOldGarbage(&initialHeapSize);
3435 { 3436 {
3436 PVec pVec; 3437 PVec pVec;
3437 PDeque pDeque; 3438 PDeque pDeque;
3438 PSet pSet; 3439 PSet pSet;
3439 PListSet pListSet; 3440 PListSet pListSet;
3440 PLinkedSet pLinkedSet; 3441 PLinkedSet pLinkedSet;
3441 PMap pMap; 3442 PMap pMap;
3443 WeakPMap wpMap;
3442 3444
3443 IntWrapper* one(IntWrapper::create(1)); 3445 IntWrapper* one(IntWrapper::create(1));
3444 IntWrapper* two(IntWrapper::create(2)); 3446 IntWrapper* two(IntWrapper::create(2));
3445 IntWrapper* three(IntWrapper::create(3)); 3447 IntWrapper* three(IntWrapper::create(3));
3446 IntWrapper* four(IntWrapper::create(4)); 3448 IntWrapper* four(IntWrapper::create(4));
3447 IntWrapper* five(IntWrapper::create(5)); 3449 IntWrapper* five(IntWrapper::create(5));
3448 IntWrapper* six(IntWrapper::create(6)); 3450 IntWrapper* six(IntWrapper::create(6));
3449 IntWrapper* seven(IntWrapper::create(7)); 3451 IntWrapper* seven(IntWrapper::create(7));
3450 IntWrapper* eight(IntWrapper::create(8)); 3452 IntWrapper* eight(IntWrapper::create(8));
3451 IntWrapper* nine(IntWrapper::create(9)); 3453 IntWrapper* nine(IntWrapper::create(9));
3454 Persistent<IntWrapper> ten(IntWrapper::create(10));
3455 IntWrapper* eleven(IntWrapper::create(11));
3452 3456
3453 pVec.append(one); 3457 pVec.append(one);
3454 pVec.append(two); 3458 pVec.append(two);
3455 3459
3456 pDeque.append(seven); 3460 pDeque.append(seven);
3457 pDeque.append(two); 3461 pDeque.append(two);
3458 3462
3459 Vec* vec = new Vec(); 3463 Vec* vec = new Vec();
3460 vec->swap(pVec); 3464 vec->swap(pVec);
3461 3465
3462 pVec.append(two); 3466 pVec.append(two);
3463 pVec.append(three); 3467 pVec.append(three);
3464 3468
3465 pSet.add(four); 3469 pSet.add(four);
3466 pListSet.add(eight); 3470 pListSet.add(eight);
3467 pLinkedSet.add(nine); 3471 pLinkedSet.add(nine);
3468 pMap.add(five, six); 3472 pMap.add(five, six);
3473 wpMap.add(ten, eleven);
3469 3474
3470 // Collect |vec| and |one|. 3475 // Collect |vec| and |one|.
3471 vec = 0; 3476 vec = 0;
3472 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3477 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3473 EXPECT_EQ(1, IntWrapper::s_destructorCalls); 3478 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
3474 3479
3475 EXPECT_EQ(2u, pVec.size()); 3480 EXPECT_EQ(2u, pVec.size());
3476 EXPECT_EQ(two, pVec.at(0)); 3481 EXPECT_EQ(two, pVec.at(0));
3477 EXPECT_EQ(three, pVec.at(1)); 3482 EXPECT_EQ(three, pVec.at(1));
3478 3483
3479 EXPECT_EQ(2u, pDeque.size()); 3484 EXPECT_EQ(2u, pDeque.size());
3480 EXPECT_EQ(seven, pDeque.first()); 3485 EXPECT_EQ(seven, pDeque.first());
3481 EXPECT_EQ(seven, pDeque.takeFirst()); 3486 EXPECT_EQ(seven, pDeque.takeFirst());
3482 EXPECT_EQ(two, pDeque.first()); 3487 EXPECT_EQ(two, pDeque.first());
3483 3488
3484 EXPECT_EQ(1u, pDeque.size()); 3489 EXPECT_EQ(1u, pDeque.size());
3485 3490
3486 EXPECT_EQ(1u, pSet.size()); 3491 EXPECT_EQ(1u, pSet.size());
3487 EXPECT_TRUE(pSet.contains(four)); 3492 EXPECT_TRUE(pSet.contains(four));
3488 3493
3489 EXPECT_EQ(1u, pListSet.size()); 3494 EXPECT_EQ(1u, pListSet.size());
3490 EXPECT_TRUE(pListSet.contains(eight)); 3495 EXPECT_TRUE(pListSet.contains(eight));
3491 3496
3492 EXPECT_EQ(1u, pLinkedSet.size()); 3497 EXPECT_EQ(1u, pLinkedSet.size());
3493 EXPECT_TRUE(pLinkedSet.contains(nine)); 3498 EXPECT_TRUE(pLinkedSet.contains(nine));
3494 3499
3495 EXPECT_EQ(1u, pMap.size()); 3500 EXPECT_EQ(1u, pMap.size());
3496 EXPECT_EQ(six, pMap.get(five)); 3501 EXPECT_EQ(six, pMap.get(five));
3502
3503 EXPECT_EQ(1u, wpMap.size());
3504 EXPECT_EQ(eleven, wpMap.get(ten));
3505 ten.clear();
3506 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3507 EXPECT_EQ(0u, wpMap.size());
3497 } 3508 }
3498 3509
3499 // Collect previous roots. 3510 // Collect previous roots.
3500 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 3511 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
3501 EXPECT_EQ(9, IntWrapper::s_destructorCalls); 3512 EXPECT_EQ(11, IntWrapper::s_destructorCalls);
3502 } 3513 }
3503 3514
3504 TEST(HeapTest, CollectionNesting) 3515 TEST(HeapTest, CollectionNesting)
3505 { 3516 {
3506 HeapStats initialStats; 3517 HeapStats initialStats;
3507 clearOutOldGarbage(&initialStats); 3518 clearOutOldGarbage(&initialStats);
3508 int* key = &IntWrapper::s_destructorCalls; 3519 int* key = &IntWrapper::s_destructorCalls;
3509 IntWrapper::s_destructorCalls = 0; 3520 IntWrapper::s_destructorCalls = 0;
3510 typedef HeapVector<Member<IntWrapper> > IntVector; 3521 typedef HeapVector<Member<IntWrapper> > IntVector;
3511 typedef HeapDeque<Member<IntWrapper> > IntDeque; 3522 typedef HeapDeque<Member<IntWrapper> > IntDeque;
(...skipping 1064 matching lines...) Expand 10 before | Expand all | Expand 10 after
4576 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4587 EXPECT_EQ(lifeObject, map->get(lifeObject)->link());
4577 deadObject.clear(); // Now it can live up to its name. 4588 deadObject.clear(); // Now it can live up to its name.
4578 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4589 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4579 EXPECT_EQ(1u, map->size()); 4590 EXPECT_EQ(1u, map->size());
4580 EXPECT_EQ(lifeObject, map->get(lifeObject)->link()); 4591 EXPECT_EQ(lifeObject, map->get(lifeObject)->link());
4581 lifeObject.clear(); // Despite its name. 4592 lifeObject.clear(); // Despite its name.
4582 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); 4593 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4583 EXPECT_EQ(0u, map->size()); 4594 EXPECT_EQ(0u, map->size());
4584 } 4595 }
4585 4596
4597 static Mutex& mainThreadMutex()
4598 {
4599 AtomicallyInitializedStatic(Mutex&, mainMutex = *new Mutex);
4600 return mainMutex;
4601 }
4602
4603 static ThreadCondition& mainThreadCondition()
4604 {
4605 AtomicallyInitializedStatic(ThreadCondition&, mainCondition = *new ThreadCon dition);
4606 return mainCondition;
4607 }
4608
4609 static void parkMainThread()
4610 {
4611 mainThreadCondition().wait(mainThreadMutex());
4612 }
4613
4614 static void wakeMainThread()
4615 {
4616 MutexLocker locker(mainThreadMutex());
4617 mainThreadCondition().signal();
4618 }
4619
4620 static Mutex& workerThreadMutex()
4621 {
4622 AtomicallyInitializedStatic(Mutex&, workerMutex = *new Mutex);
4623 return workerMutex;
4624 }
4625
4626 static ThreadCondition& workerThreadCondition()
4627 {
4628 AtomicallyInitializedStatic(ThreadCondition&, workerCondition = *new ThreadC ondition);
4629 return workerCondition;
4630 }
4631
4632 static void parkWorkerThread()
4633 {
4634 workerThreadCondition().wait(workerThreadMutex());
4635 }
4636
4637 static void wakeWorkerThread()
4638 {
4639 MutexLocker locker(workerThreadMutex());
4640 workerThreadCondition().signal();
4641 }
4642
4643 class CrossThreadObject : public GarbageCollectedFinalized<CrossThreadObject> {
4644 public:
4645 static CrossThreadObject* create(IntWrapper* workerObjectPointer)
4646 {
4647 return new CrossThreadObject(workerObjectPointer);
4648 }
4649
4650 virtual ~CrossThreadObject()
4651 {
4652 ++s_destructorCalls;
4653 }
4654
4655 static int s_destructorCalls;
4656 void trace(Visitor* visitor) { visitor->trace(m_workerObject); }
4657
4658 private:
4659 CrossThreadObject(IntWrapper* workerObjectPointer) : m_workerObject(workerOb jectPointer) { }
4660
4661 private:
4662 Member<IntWrapper> m_workerObject;
4663 };
4664
4665 int CrossThreadObject::s_destructorCalls = 0;
4666
4667 class CrossThreadPointerTester {
4668 public:
4669 static void test()
4670 {
4671 CrossThreadObject::s_destructorCalls = 0;
4672 IntWrapper::s_destructorCalls = 0;
4673
4674 MutexLocker locker(mainThreadMutex());
4675 createThread(&workerThreadMain, 0, "Worker Thread");
4676
4677 parkMainThread();
4678
4679 uintptr_t stackPtrValue = 0;
4680 {
4681 // Create an object with a pointer to the other heap's IntWrapper.
4682 Persistent<CrossThreadObject> cto = CrossThreadObject::create(const_ cast<IntWrapper*>(s_workerObjectPointer));
4683 s_workerObjectPointer = 0;
4684
4685 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4686
4687 // Nothing should have been collected/destructed.
4688 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4689 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4690
4691 // Put cto into a stack value. This is used to check that a conserva tive
4692 // GC succeeds even though we are tracing the other thread heap afte r
4693 // shutting it down.
4694 stackPtrValue = reinterpret_cast<uintptr_t>(cto.get());
4695 }
4696
4697 // At this point it is "programatically" okay to shut down the worker th read
4698 // since the cto object should be dead. However out stackPtrValue will c ause a
4699 // trace of the object when doing a conservative GC.
4700 // The worker thread's thread local GC's should just add the worker thre ad's
4701 // pages to the heap after finalizing IntWrapper.
4702 wakeWorkerThread();
4703
4704 // Wait for the worker to shutdown.
4705 parkMainThread();
4706
4707 // After the worker thread has detached it should have finalized the
4708 // IntWrapper object on its heaps. Since there has been no global GC
4709 // the cto object should not have been finalized.
4710 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4711 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4712
4713 // Now do a conservative GC. The stackPtrValue should keep cto alive
4714 // and will also cause the orphaned page of the other thread to be
4715 // traced. At this point cto should still not be finalized.
4716 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4717 EXPECT_EQ(0, CrossThreadObject::s_destructorCalls);
4718 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4719
4720 // Do a GC with no pointers on the stack to see the cto being collected.
4721 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4722 EXPECT_EQ(1, CrossThreadObject::s_destructorCalls);
4723 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4724 }
4725
4726 private:
4727 static void workerThreadMain(void* data)
4728 {
4729 MutexLocker locker(workerThreadMutex());
4730 ThreadState::attach();
4731
4732 {
4733 // Create a worker object that is only kept alive by a cross thread
4734 // pointer (from CrossThreadObject).
4735 IntWrapper* workerObject = IntWrapper::create(42);
4736 s_workerObjectPointer = workerObject;
4737 }
4738
4739 // Wake up the main thread which is waiting for the worker to do its
4740 // allocation and passing the pointer.
4741 wakeMainThread();
4742
4743 // Wait for main thread to signal the worker to shutdown.
4744 {
4745 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack );
4746 parkWorkerThread();
4747 }
4748
4749 ThreadState::detach();
4750
4751 // Tell the main thread the worker has done its shutdown.
4752 wakeMainThread();
4753 }
4754
4755 static volatile IntWrapper* s_workerObjectPointer;
4756 };
4757
4758 volatile IntWrapper* CrossThreadPointerTester::s_workerObjectPointer = 0;
4759
4760 TEST(HeapTest, CrossThreadPointerToOrphanedPage)
4761 {
4762 CrossThreadPointerTester::test();
4763 }
4764
4765 class DeadBitTester {
4766 public:
4767 static void test()
4768 {
4769 IntWrapper::s_destructorCalls = 0;
4770
4771 MutexLocker locker(mainThreadMutex());
4772 createThread(&workerThreadMain, 0, "Worker Thread");
4773
4774 // Wait for the worker thread to have done its initialization,
4775 // IE. the worker allocates an object and then throw aways any
4776 // pointers to it.
4777 parkMainThread();
4778
4779 // Now do a GC. This will not find the worker threads object since it
4780 // is not referred from any of the threads. Even a conservative
4781 // GC will not find it.
4782 // Also at this point the worker is waiting for the main thread
4783 // to be parked and will not do any sweep of its heap.
4784 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack);
4785
4786 // Since the worker thread is not sweeping the worker object should
4787 // not have been finalized.
4788 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4789
4790 // Put the worker thread's object address on the stack and do a
4791 // conservative GC. This should find the worker object, but since
4792 // it was dead in the previous GC it should not be traced in this
4793 // GC.
4794 uintptr_t stackPtrValue = s_workerObjectPointer;
4795 s_workerObjectPointer = 0;
4796 ASSERT_UNUSED(stackPtrValue, stackPtrValue);
4797 Heap::collectGarbage(ThreadState::HeapPointersOnStack);
4798
4799 // Since the worker thread is not sweeping the worker object should
4800 // not have been finalized.
4801 EXPECT_EQ(0, IntWrapper::s_destructorCalls);
4802
4803 // Wake up the worker thread so it can continue with its sweeping.
4804 // This should finalized the worker object which we test below.
4805 // The worker thread will go back to sleep once sweeping to ensure
4806 // we don't have thread local GCs until after validating the destructor
4807 // was called.
4808 wakeWorkerThread();
4809
4810 // Wait for the worker thread to sweep its heaps before checking.
4811 parkMainThread();
4812 EXPECT_EQ(1, IntWrapper::s_destructorCalls);
4813
4814 // Wake up the worker to allow it thread to continue with thread
4815 // shutdown.
4816 wakeWorkerThread();
4817 }
4818
4819 private:
4820
4821 static void workerThreadMain(void* data)
4822 {
4823 MutexLocker locker(workerThreadMutex());
4824
4825 ThreadState::attach();
4826
4827 {
4828 // Create a worker object that is not kept alive except the
4829 // main thread will keep it as an integer value on its stack.
4830 IntWrapper* workerObject = IntWrapper::create(42);
4831 s_workerObjectPointer = reinterpret_cast<uintptr_t>(workerObject);
4832 }
4833
4834 // Signal the main thread that the worker is done with its allocation.
4835 wakeMainThread();
4836
4837 {
4838 // Wait for the main thread to do two GCs without sweeping this thre ad
4839 // heap. The worker waits within a safepoint, but there is no sweepi ng
4840 // until leaving the safepoint scope.
4841 ThreadState::SafePointScope scope(ThreadState::NoHeapPointersOnStack );
4842 parkWorkerThread();
4843 }
4844
4845 // Wake up the main thread when done sweeping.
4846 wakeMainThread();
4847
4848 // Wait with detach until the main thread says so. This is not strictly
4849 // necessary, but it means the worker thread will not do its thread loca l
4850 // GCs just yet, making it easier to reason about that no new GC has occ urred
4851 // and the above sweep was the one finalizing the worker object.
4852 parkWorkerThread();
4853
4854 ThreadState::detach();
4855 }
4856
4857 static volatile uintptr_t s_workerObjectPointer;
4858 };
4859
4860 volatile uintptr_t DeadBitTester::s_workerObjectPointer = 0;
4861
4862 TEST(HeapTest, ObjectDeadBit)
4863 {
4864 DeadBitTester::test();
4865 }
4586 4866
4587 } // WebCore namespace 4867 } // WebCore namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698