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 @@
namespace blink {
enum PersistentConfiguration {
NormalPersistentConfiguration,
WeakPersistentConfiguration,
CrossThreadPersistentConfiguration,
enum WeaknessPersistentConfiguration {
NonWeakPersistentConfiguration,
WeakPersistentConfiguration
};
template<typename T, PersistentConfiguration persistentConfiguration>
enum CrossThreadnessPersistentConfiguration {
SingleThreadPersistentConfiguration,
CrossThreadPersistentConfiguration
};
template<typename T, WeaknessPersistentConfiguration weaknessConfiguration, CrossThreadnessPersistentConfiguration crossThreadnessConfiguration>
class PersistentBase {
public:
PersistentBase() : m_raw(nullptr)
......@@ -89,7 +93,7 @@ public:
}
template<typename U>
PersistentBase(const PersistentBase<U, persistentConfiguration>& other) : m_raw(other)
PersistentBase(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other) : m_raw(other)
{
initialize();
checkPointer();
......@@ -123,7 +127,7 @@ public:
{
static_assert(sizeof(T), "T must be fully defined");
static_assert(IsGarbageCollectedType<T>::value, "T needs to be a garbage collected object");
if (persistentConfiguration == WeakPersistentConfiguration) {
if (weaknessConfiguration == WeakPersistentConfiguration) {
visitor->registerWeakCell(&m_raw);
} else {
visitor->mark(m_raw);
......@@ -169,7 +173,7 @@ public:
}
template<typename U>
PersistentBase& operator=(const PersistentBase<U, persistentConfiguration>& other)
PersistentBase& operator=(const PersistentBase<U, weaknessConfiguration, crossThreadnessConfiguration>& other)
{
m_raw = other;
checkPointer();
......@@ -200,8 +204,8 @@ private:
NO_LAZY_SWEEP_SANITIZE_ADDRESS
void initialize()
{
TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, persistentConfiguration>, &PersistentBase<T, persistentConfiguration>::trace>::trampoline;
if (persistentConfiguration == CrossThreadPersistentConfiguration) {
TraceCallback traceCallback = TraceMethodDelegate<PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>, &PersistentBase<T, weaknessConfiguration, crossThreadnessConfiguration>::trace>::trampoline;
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
m_persistentNode = ThreadState::crossThreadPersistentRegion().allocatePersistentNode(this, traceCallback);
} else {
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
......@@ -216,7 +220,7 @@ private:
void uninitialize()
{
if (persistentConfiguration == CrossThreadPersistentConfiguration) {
if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) {
ThreadState::crossThreadPersistentRegion().freePersistentNode(m_persistentNode);
} else {
ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::state();
......@@ -272,8 +276,8 @@ private:
//
// We have to construct and destruct Persistent in the same thread.
template<typename T>
class Persistent : public PersistentBase<T, NormalPersistentConfiguration> {
typedef PersistentBase<T, NormalPersistentConfiguration> Parent;
class Persistent : public PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, NonWeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public:
Persistent() : Parent() { }
Persistent(std::nullptr_t) : Parent(nullptr) { }
......@@ -300,8 +304,8 @@ public:
// HashSet<WeakPersistent<T>> m_set; // wrong
// PersistentHeapHashSet<WeakMember<T>> m_set; // correct
template<typename T>
class WeakPersistent : public PersistentBase<T, WeakPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration> Parent;
class WeakPersistent : public PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> {
typedef PersistentBase<T, WeakPersistentConfiguration, SingleThreadPersistentConfiguration> Parent;
public:
WeakPersistent() : Parent() { }
WeakPersistent(std::nullptr_t) : Parent(nullptr) { }
......@@ -319,8 +323,8 @@ public:
// Unlike Persistent, we can destruct a CrossThreadPersistent in a thread
// different from the construction thread.
template<typename T>
class CrossThreadPersistent : public PersistentBase<T, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, CrossThreadPersistentConfiguration> Parent;
class CrossThreadPersistent : public PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> {
typedef PersistentBase<T, NonWeakPersistentConfiguration, CrossThreadPersistentConfiguration> Parent;
public:
CrossThreadPersistent() : Parent() { }
CrossThreadPersistent(std::nullptr_t) : Parent(nullptr) { }
......@@ -335,6 +339,23 @@ public:
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
// visitor->trace(static_cast<Collection*>(this)) trace the correct position.
// FIXME: derive affinity based on the collection.
......
......@@ -6361,4 +6361,69 @@ TEST(HeapTest, WeakPersistent)
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
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