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