Commit 55a4e0c3 authored by yutak@chromium.org's avatar yutak@chromium.org

Oilpan: Add CrossThreadWeakPersistent.

The necessity of CrossThreadWeakPersistent arose in
https://codereview.chromium.org/1296243004/.

BUG=420515
R=haraken@chromium.org, oilpan-reviews@chromium.org, sigbjornf@opera.com

Review URL: https://codereview.chromium.org/1304573002

git-svn-id: svn://svn.chromium.org/blink/trunk@200889 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent b444eee5
...@@ -48,13 +48,17 @@ ...@@ -48,13 +48,17 @@
namespace blink { namespace blink {
enum PersistentConfiguration { enum WeaknessPersistentConfiguration {
NormalPersistentConfiguration, NonWeakPersistentConfiguration,
WeakPersistentConfiguration, WeakPersistentConfiguration
CrossThreadPersistentConfiguration,
}; };
template<typename T, PersistentConfiguration persistentConfiguration> enum CrossThreadnessPersistentConfiguration {
SingleThreadPersistentConfiguration,
CrossThreadPersistentConfiguration
};
template<typename T, WeaknessPersistentConfiguration weaknessConfiguration, CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
class PersistentBase { class PersistentBase {
public: public:
PersistentBase() : m_raw(nullptr) PersistentBase() : m_raw(nullptr)
...@@ -89,7 +93,7 @@ public: ...@@ -89,7 +93,7 @@ public:
} }
template<typename U> template<typename U>
PersistentBase(const PersistentBase<U, persistentConfiguration>& other) : m_raw(other) PersistentBase(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other) : m_raw(other)
{ {
initialize(); initialize();
checkPointer(); checkPointer();
...@@ -123,7 +127,7 @@ public: ...@@ -123,7 +127,7 @@ public:
{ {
static_assert(sizeof(T), "T must be fully defined"); static_assert(sizeof(T), "T must be fully defined");
static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object"); static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object");
if (persistentConfiguration == WeakPersistentConfiguration) { if (weaknessConfiguration == WeakPersistentConfiguration) {
visitor->registerWeakCell(&m_raw); visitor->registerWeakCell(&m_raw);
} else { } else {
visitor->mark(m_raw); visitor->mark(m_raw);
...@@ -169,7 +173,7 @@ public: ...@@ -169,7 +173,7 @@ public:
} }
template<typename U> template<typename U>
PersistentBase& operator=(const PersistentBase<U, persistentConfiguration>& other) PersistentBase& operator=(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other)
{ {
m_raw = other; m_raw = other;
checkPointer(); checkPointer();
...@@ -200,8 +204,8 @@ private: ...@@ -200,8 +204,8 @@ private:
NO_LAZY_SWEEP_SANITIZE_ADDRESS NO_LAZY_SWEEP_SANITIZE_ADDRESS
void initialize() void initialize()
{ {
TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, persistentConfiguration>, &PersistentBase<T, persistentConfiguration>::trace>::trampoline; TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>, &PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>::trace>::trampoline;
if (persistentConfiguration == CrossThreadPersistentConfiguration) { if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback); m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback);
} else { } else {
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
...@@ -216,7 +220,7 @@ private: ...@@ -216,7 +220,7 @@ private:
void uninitialize() void uninitialize()
{ {
if (persistentConfiguration == CrossThreadPersistentConfiguration) { if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode); ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode);
} else { } else {
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state(); ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
...@@ -272,8 +276,8 @@ private: ...@@ -272,8 +276,8 @@ private:
// //
// We have to construct and destruct Persistent in the same thread. // We have to construct and destruct Persistent in the same thread.
template<typename T> template<typename T>
class Persistent : public PersistentBase<T, NormalPersistentConfiguration> { class Persistent : public PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, NormalPersistentConfiguration> Parent; typedef PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public: public:
Persistent() : Parent() { } Persistent() : Parent() { }
Persistent(std::nullptr_t) : Parent(nullptr) { } Persistent(std::nullptr_t) : Parent(nullptr) { }
...@@ -300,8 +304,8 @@ public: ...@@ -300,8 +304,8 @@ public:
// HashSet<WeakPersistent<T>> m_set; // wrong // HashSet<WeakPersistent<T>> m_set; // wrong
// PersistentHeapHashSet<WeakMember<T>> m_set; // correct // PersistentHeapHashSet<WeakMember<T>> m_set; // correct
template<typename T> template<typename T>
class WeakPersistent : public PersistentBase<T, WeakPersistentConfiguration> { class WeakPersistent : public PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration> Parent; typedef PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public: public:
WeakPersistent() : Parent() { } WeakPersistent() : Parent() { }
WeakPersistent(std::nullptr_t) : Parent(nullptr) { } WeakPersistent(std::nullptr_t) : Parent(nullptr) { }
...@@ -319,8 +323,8 @@ public: ...@@ -319,8 +323,8 @@ public:
// Unlike Persistent, we can destruct a CrossThreadPersistent in a thread // Unlike Persistent, we can destruct a CrossThreadPersistent in a thread
// different from the construction thread. // different from the construction thread.
template<typename T> template<typename T>
class CrossThreadPersistent : public PersistentBase<T, CrossThreadPersistentConfiguration> { class CrossThreadPersistent : public PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, CrossThreadPersistentConfiguration> Parent; typedef PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> Parent;
public: public:
CrossThreadPersistent() : Parent() { } CrossThreadPersistent() : Parent() { }
CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) { } CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) { }
...@@ -335,6 +339,23 @@ public: ...@@ -335,6 +339,23 @@ public:
CrossThreadPersistent(const RawPtr<U>& other) : Parent(other.get()) { } CrossThreadPersistent(const RawPtr<U>& other) : Parent(other.get()) { }
}; };
template<typename T>
class CrossThreadWeakPersistent : public PersistentBase<T, WeakPersistentConfiguration, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration, CrossThreadPersistentConfiguration> Parent;
public:
CrossThreadWeakPersistent() : Parent() { }
CrossThreadWeakPersistent(std::nullptr_t) : Parent(nullptr) { }
CrossThreadWeakPersistent(T* raw) : Parent(raw) { }
CrossThreadWeakPersistent(T& raw) : Parent(raw) { }
CrossThreadWeakPersistent(const CrossThreadWeakPersistent& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent(const CrossThreadWeakPersistent<U>& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent(const Member<U>& other) : Parent(other) { }
template<typename U>
CrossThreadWeakPersistent(const RawPtr<U>& other) : Parent(other.get()) { }
};
// PersistentNode must be the left-most class to let the // PersistentNode must be the left-most class to let the
// visitor->trace(static_cast<Collection*>(this)) trace the correct position. // visitor->trace(static_cast<Collection*>(this)) trace the correct position.
// FIXME: derive affinity based on the collection. // FIXME: derive affinity based on the collection.
......
...@@ -6361,4 +6361,69 @@ TEST(HeapTest, WeakPersistent) ...@@ -6361,4 +6361,69 @@ TEST(HeapTest, WeakPersistent)
EXPECT_FALSE(holder->object()); EXPECT_FALSE(holder->object());
} }
namespace {
void workerThreadMainForCrossThreadWeakPersistentTest(DestructorLockingObject** object)
{
// Step 2: Create an object and store the pointer.
MutexLocker locker(workerThreadMutex());
ThreadState::attach();
*object = DestructorLockingObject::create();
wakeMainThread();
parkWorkerThread();
// Step 4: Run a GC.
Heap::collectGarbage(ThreadState::NoHeapPointersOnStack, ThreadState::GCWithSweep, Heap::ForcedGC);
wakeMainThread();
parkWorkerThread();
// Step 6: Finish.
ThreadState::detach();
wakeMainThread();
}
} // anonymous namespace
TEST(HeapTest, CrossThreadWeakPersistent)
{
// Create an object in the worker thread, have a CrossThreadWeakPersistent pointing to it on the main thread,
// clear the reference in the worker thread, run a GC in the worker thread, and see if the
// CrossThreadWeakPersistent is cleared.
DestructorLockingObject::s_destructorCalls = 0;
// Step 1: Initiate a worker thread, and wait for |object| to get allocated on the worker thread.
MutexLocker mainThreadMutexLocker(mainThreadMutex());
OwnPtr<WebThread> workerThread = adoptPtr(Platform::current()->createThread("Test Worker Thread"));
DestructorLockingObject* object = nullptr;
workerThread->postTask(FROM_HERE, new Task(threadSafeBind(workerThreadMainForCrossThreadWeakPersistentTest, AllowCrossThreadAccessWrapper<DestructorLockingObject**>(&object))));
parkMainThread();
// Step 3: Set up a CrossThreadWeakPersistent.
ASSERT_TRUE(object);
CrossThreadWeakPersistent<DestructorLockingObject> crossThreadWeakPersistent(object);
object = nullptr;
{
SafePointAwareMutexLocker recursiveMutexLocker(recursiveMutex());
EXPECT_EQ(0, DestructorLockingObject::s_destructorCalls);
}
{
// Pretend we have no pointers on stack during the step 4.
SafePointScope scope(ThreadState::NoHeapPointersOnStack);
wakeWorkerThread();
parkMainThread();
}
// Step 5: Make sure the weak persistent is cleared.
EXPECT_FALSE(crossThreadWeakPersistent.get());
{
SafePointAwareMutexLocker recursiveMutexLocker(recursiveMutex());
EXPECT_EQ(1, DestructorLockingObject::s_destructorCalls);
}
wakeWorkerThread();
parkMainThread();
}
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment