Bug 1205559: Make TextureChild/TextureClient thread-safe. r=nical

This commit is contained in:
Jean-Yves Avenard 2015-10-16 14:46:33 +02:00
Родитель 077cb7307e
Коммит 70773dbaa0
1 изменённых файлов: 31 добавлений и 8 удалений

Просмотреть файл

@ -8,6 +8,7 @@
#include "Layers.h" // for Layer, etc
#include "gfx2DGlue.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "mozilla/Atomics.h"
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/ISurfaceAllocator.h"
@ -101,9 +102,11 @@ public:
TextureChild()
: mForwarder(nullptr)
, mTextureClient(nullptr)
, mMainThreadOnly(false)
, mIPCOpen(false)
, mMonitor("TextureChild")
, mTextureClient(nullptr)
, mDestroyed(false)
{
}
@ -118,7 +121,10 @@ public:
void WaitForCompositorRecycle()
{
mWaitForRecycle = mTextureClient;
{
MonitorAutoLock mon(mMonitor);
mWaitForRecycle = mDestroyed ? nullptr : mTextureClient;
}
RECYCLE_LOG("[CLIENT] Wait for recycle %p\n", mWaitForRecycle.get());
SendClientRecycle();
}
@ -148,10 +154,19 @@ private:
Release();
}
void SetTextureClient(TextureClient* aTextureClient) {
MonitorAutoLock mon(mMonitor);
mTextureClient = aTextureClient;
}
RefPtr<CompositableForwarder> mForwarder;
RefPtr<TextureClient> mWaitForRecycle;
// Monitor protecting mTextureClient.
Monitor mMonitor;
TextureClient* mTextureClient;
UniquePtr<KeepAlive> mKeep;
Atomic<bool> mDestroyed;
bool mMainThreadOnly;
bool mIPCOpen;
@ -210,7 +225,7 @@ TextureClient::AddFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags |= aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -221,7 +236,7 @@ TextureClient::RemoveFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags &= ~aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -234,7 +249,7 @@ TextureClient::RecycleTexture(TextureFlags aFlags)
mAddedToCompositableClient = false;
if (mFlags != aFlags) {
mFlags = aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -276,10 +291,10 @@ bool
TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
{
MOZ_ASSERT(aForwarder && aForwarder->GetMessageLoop() == mAllocator->GetMessageLoop());
if (mActor && mActor->GetForwarder() == aForwarder) {
if (mActor && !mActor->mDestroyed && mActor->GetForwarder() == aForwarder) {
return true;
}
MOZ_ASSERT(!mActor, "Cannot use a texture on several IPC channels.");
MOZ_ASSERT(!mActor || mActor->mDestroyed, "Cannot use a texture on several IPC channels.");
SurfaceDescriptor desc;
if (!ToSurfaceDescriptor(desc)) {
@ -562,6 +577,9 @@ TextureClient::KeepUntilFullDeallocation(UniquePtr<KeepAlive> aKeep, bool aMainT
void TextureClient::ForceRemove(bool sync)
{
if (mActor && mActor->mDestroyed) {
mActor = nullptr;
}
if (mValid && mActor) {
FinalizeOnIPDLThread();
if (sync || GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
@ -613,15 +631,20 @@ void
TextureClient::Finalize()
{
MOZ_ASSERT(!IsLocked());
// Always make a temporary strong reference to the actor before we use it,
// in case TextureChild::ActorDestroy might null mActor concurrently.
RefPtr<TextureChild> actor = mActor;
if (actor) {
if (actor->mDestroyed) {
actor = nullptr;
return;
}
// The actor has a raw pointer to us, actor->mTextureClient.
// Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
// when calling TextureChild::ActorDestroy()
actor->mTextureClient = nullptr;
actor->SetTextureClient(nullptr);
// `actor->mWaitForRecycle` may not be null, as we may be being called from setting
// this RefPtr to null! Clearing it here will double-Release() it.