OLD | NEW |
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 4859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4870 | 4870 |
4871 // Regression test for out of bounds call through vtable. | 4871 // Regression test for out of bounds call through vtable. |
4872 // Passes if it doesn't crash. | 4872 // Passes if it doesn't crash. |
4873 TEST(HeapTest, GarbageCollectionDuringMixinConstruction) | 4873 TEST(HeapTest, GarbageCollectionDuringMixinConstruction) |
4874 { | 4874 { |
4875 ClassWithGarbageCollectingMixinConstructor* a = | 4875 ClassWithGarbageCollectingMixinConstructor* a = |
4876 new ClassWithGarbageCollectingMixinConstructor(); | 4876 new ClassWithGarbageCollectingMixinConstructor(); |
4877 a->verify(); | 4877 a->verify(); |
4878 } | 4878 } |
4879 | 4879 |
| 4880 static RecursiveMutex& recursiveMutex() |
| 4881 { |
| 4882 AtomicallyInitializedStatic(RecursiveMutex&, recursiveMutex = *new Recursive
Mutex); |
| 4883 return recursiveMutex; |
| 4884 } |
| 4885 |
| 4886 class DestructorLockingObject : public GarbageCollectedFinalized<DestructorLocki
ngObject> { |
| 4887 public: |
| 4888 static DestructorLockingObject* create() |
| 4889 { |
| 4890 return new DestructorLockingObject(); |
| 4891 } |
| 4892 |
| 4893 virtual ~DestructorLockingObject() |
| 4894 { |
| 4895 SafePointAwareMutexLocker lock(recursiveMutex()); |
| 4896 ++s_destructorCalls; |
| 4897 } |
| 4898 |
| 4899 static int s_destructorCalls; |
| 4900 void trace(Visitor* visitor) { } |
| 4901 |
| 4902 private: |
| 4903 DestructorLockingObject() { } |
| 4904 }; |
| 4905 |
| 4906 int DestructorLockingObject::s_destructorCalls = 0; |
| 4907 |
| 4908 class RecursiveLockingTester { |
| 4909 public: |
| 4910 static void test() |
| 4911 { |
| 4912 DestructorLockingObject::s_destructorCalls = 0; |
| 4913 |
| 4914 MutexLocker locker(mainThreadMutex()); |
| 4915 createThread(&workerThreadMain, 0, "Worker Thread"); |
| 4916 |
| 4917 // Park the main thread until the worker thread has initialized. |
| 4918 parkMainThread(); |
| 4919 |
| 4920 { |
| 4921 SafePointAwareMutexLocker recursiveLocker(recursiveMutex()); |
| 4922 |
| 4923 // Let the worker try to acquire the above mutex. It won't get it |
| 4924 // until the main thread has done its GC. |
| 4925 wakeWorkerThread(); |
| 4926 |
| 4927 Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); |
| 4928 |
| 4929 // The worker thread should not have swept yet since it is waiting |
| 4930 // to get the global mutex. |
| 4931 EXPECT_EQ(0, DestructorLockingObject::s_destructorCalls); |
| 4932 } |
| 4933 // At this point the main thread releases the global lock and the worker |
| 4934 // can acquire it and do its sweep of its heaps. Just wait for the worke
r |
| 4935 // to complete its sweep and check the result. |
| 4936 parkMainThread(); |
| 4937 EXPECT_EQ(1, DestructorLockingObject::s_destructorCalls); |
| 4938 } |
| 4939 |
| 4940 private: |
| 4941 static void workerThreadMain(void* data) |
| 4942 { |
| 4943 MutexLocker locker(workerThreadMutex()); |
| 4944 ThreadState::attach(); |
| 4945 |
| 4946 DestructorLockingObject* dlo = DestructorLockingObject::create(); |
| 4947 ASSERT_UNUSED(dlo, dlo); |
| 4948 |
| 4949 // Wake up the main thread which is waiting for the worker to do its |
| 4950 // allocation. |
| 4951 wakeMainThread(); |
| 4952 |
| 4953 // Wait for the main thread to get the global lock to ensure it has |
| 4954 // it before the worker tries to acquire it. We want the worker to |
| 4955 // block in the SafePointAwareMutexLocker until the main thread |
| 4956 // has done a GC. The GC will not mark the "dlo" object since the worker |
| 4957 // is entering the safepoint with NoHeapPointersOnStack. When the worker |
| 4958 // subsequently gets the global lock and leaves the safepoint it will |
| 4959 // sweep its heap and finalize "dlo". The destructor of "dlo" will try |
| 4960 // to acquire the same global lock that the thread just got and deadlock |
| 4961 // unless the global lock is recursive. |
| 4962 parkWorkerThread(); |
| 4963 SafePointAwareMutexLocker recursiveLocker(recursiveMutex(), ThreadState:
:NoHeapPointersOnStack); |
| 4964 |
| 4965 // We won't get here unless the lock is recursive since the sweep done |
| 4966 // in the constructor of SafePointAwareMutexLocker after |
| 4967 // getting the lock will not complete given the "dlo" destructor is |
| 4968 // waiting to get the same lock. |
| 4969 // Tell the main thread the worker has done its sweep. |
| 4970 wakeMainThread(); |
| 4971 |
| 4972 ThreadState::detach(); |
| 4973 } |
| 4974 |
| 4975 static volatile IntWrapper* s_workerObjectPointer; |
| 4976 }; |
| 4977 |
| 4978 TEST(HeapTest, RecursiveMutex) |
| 4979 { |
| 4980 RecursiveLockingTester::test(); |
| 4981 } |
| 4982 |
4880 } // WebCore namespace | 4983 } // WebCore namespace |
OLD | NEW |