Allocate TextureReadLock at TextureClient creation and drop file handles immediately after. (bug 1416726, r=aosmond) draft
authorRyan Hunt <rhunt@eqrion.net>
Mon, 12 Mar 2018 08:10:13 -0500
changeset 766309 c8d997beec2c6880bc825b0fdd5fa134666915de
parent 766174 fdd1a0082c71673239fc2f3a6a93de889c07a1be
push id102273
push userbmo:rhunt@eqrion.net
push dateMon, 12 Mar 2018 15:39:52 +0000
reviewersaosmond
bugs1416726
milestone60.0a1
Allocate TextureReadLock at TextureClient creation and drop file handles immediately after. (bug 1416726, r=aosmond) This changes the lifecycle and API for TextureReadLock to fix file descriptor exhaustion crashes. These changes are partially superficial and mostly align the API of TextureReadLocks with their actual usage. The changes are: 1. Create the TextureReadLock in the TextureClient constructor so it's available before IPC creation a. This is superficial as EnableReadLock was always called before IPC creation 1. Send the ReadLockDescriptor in the PTextureConstructor message and close the file handle 1. Receive the ReadLockDescriptor in TextureHost and close the file handle 1. Send a boolean flag in layer transactions if the texture is read locked instead of a descriptor 1. Use a boolean flag in TextureHost to determine if the ReadLock must be unlocked instead of a nullptr I believe that we can remove the InitReadLocks code from LayerTransaction as that was added to prevent file descriptor limits in IPDL messages and is no longer needed with this change. But that is a non-essential change and this patch is already big enough. MozReview-Commit-ID: DzHujrOQejH
gfx/layers/CompositorTypes.h
gfx/layers/PersistentBufferProvider.cpp
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/ContentClient.cpp
gfx/layers/client/SingleTiledContentClient.cpp
gfx/layers/client/TextureClient.cpp
gfx/layers/client/TextureClient.h
gfx/layers/client/TiledContentClient.cpp
gfx/layers/composite/TextureHost.cpp
gfx/layers/composite/TextureHost.h
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/ipc/CompositableTransactionParent.cpp
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeChild.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeChild.h
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/LayersMessages.ipdlh
gfx/layers/ipc/PCompositorBridge.ipdl
gfx/layers/ipc/PImageBridge.ipdl
gfx/layers/ipc/PVideoBridge.ipdl
gfx/layers/ipc/ShadowLayers.cpp
gfx/layers/ipc/TextureForwarder.h
gfx/layers/ipc/VideoBridgeChild.cpp
gfx/layers/ipc/VideoBridgeChild.h
gfx/layers/ipc/VideoBridgeParent.cpp
gfx/layers/ipc/VideoBridgeParent.h
gfx/layers/wr/WebRenderBridgeChild.cpp
gfx/tests/gtest/TextureHelper.h
ipc/glue/CrossProcessSemaphore.h
ipc/glue/CrossProcessSemaphore_posix.cpp
ipc/glue/CrossProcessSemaphore_unimplemented.cpp
ipc/glue/CrossProcessSemaphore_windows.cpp
--- a/gfx/layers/CompositorTypes.h
+++ b/gfx/layers/CompositorTypes.h
@@ -68,19 +68,23 @@ enum class TextureFlags : uint32_t {
   COMPONENT_ALPHA    = 1 << 11,
   // The texture is being allocated for a compositor that no longer exists.
   // This flag is only used in the parent process.
   INVALID_COMPOSITOR = 1 << 12,
   // The texture was created by converting from YCBCR to RGB
   RGB_FROM_YCBCR     = 1 << 13,
   // The texture is used for snapshot.
   SNAPSHOT           = 1 << 14,
+  // Enable a non blocking read lock.
+  NON_BLOCKING_READ_LOCK = 1 << 15,
+  // Enable a blocking read lock.
+  BLOCKING_READ_LOCK = 1 << 16,
 
   // OR union of all valid bits
-  ALL_BITS           = (1 << 15) - 1,
+  ALL_BITS           = (1 << 17) - 1,
   // the default flags
   DEFAULT = NO_FLAGS
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextureFlags)
 
 static inline bool
 TextureRequiresLocking(TextureFlags aFlags)
 {
--- a/gfx/layers/PersistentBufferProvider.cpp
+++ b/gfx/layers/PersistentBufferProvider.cpp
@@ -101,17 +101,17 @@ PersistentBufferProviderShared::Create(g
 {
   if (!aKnowsCompositor || !aKnowsCompositor->GetTextureForwarder()->IPCOpen()) {
     return nullptr;
   }
 
   RefPtr<TextureClient> texture = TextureClient::CreateForDrawing(
     aKnowsCompositor, aFormat, aSize,
     BackendSelector::Canvas,
-    TextureFlags::DEFAULT,
+    TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK,
     TextureAllocationFlags::ALLOC_DEFAULT
   );
 
   if (!texture) {
     return nullptr;
   }
 
   RefPtr<PersistentBufferProviderShared> provider =
@@ -185,17 +185,17 @@ PersistentBufferProviderShared::SetKnows
 
     // Get rid of everything else
     Destroy();
 
     if (prevTexture) {
       RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
         aKnowsCompositor, mFormat, mSize,
         BackendSelector::Canvas,
-        TextureFlags::DEFAULT,
+        TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK,
         TextureAllocationFlags::ALLOC_DEFAULT
       );
 
       MOZ_ASSERT(newTexture);
       if (!newTexture) {
         return false;
       }
 
@@ -317,17 +317,17 @@ PersistentBufferProviderShared::BorrowDr
         // Give up now. The caller can fall-back to a non-shared buffer provider.
         return nullptr;
       }
     }
 
     RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing(
       mKnowsCompositor, mFormat, mSize,
       BackendSelector::Canvas,
-      TextureFlags::DEFAULT,
+      TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK,
       TextureAllocationFlags::ALLOC_DEFAULT
     );
 
     MOZ_ASSERT(newTexture);
     if (newTexture) {
       if (mTextures.append(newTexture)) {
         tex = newTexture;
         mBack = Some<uint32_t>(mTextures.length() - 1);
@@ -378,19 +378,17 @@ PersistentBufferProviderShared::ReturnDr
 }
 
 TextureClient*
 PersistentBufferProviderShared::GetTextureClient()
 {
   // Can't access the front buffer while drawing.
   MOZ_ASSERT(!mDrawTarget);
   TextureClient* texture = GetTexture(mFront);
-  if (texture) {
-    texture->EnableReadLock();
-  } else {
+  if (!texture) {
     gfxCriticalNote << "PersistentBufferProviderShared: front buffer unavailable";
   }
   return texture;
 }
 
 already_AddRefed<gfx::SourceSurface>
 PersistentBufferProviderShared::BorrowSnapshot()
 {
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -106,23 +106,23 @@ CanvasClient2D::Update(gfx::IntSize aSiz
     gfxContentType contentType =
       aCanvasRenderer->IsOpaque() ? gfxContentType::COLOR : gfxContentType::COLOR_ALPHA;
     gfx::SurfaceFormat surfaceFormat
       = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(contentType);
     TextureFlags flags = TextureFlags::DEFAULT;
     if (mTextureFlags & TextureFlags::ORIGIN_BOTTOM_LEFT) {
       flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
     }
+    flags |= TextureFlags::NON_BLOCKING_READ_LOCK;
 
     mBackBuffer = CreateTextureClientForCanvas(surfaceFormat, aSize, flags, aCanvasRenderer);
     if (!mBackBuffer) {
       NS_WARNING("Failed to allocate the TextureClient");
       return;
     }
-    mBackBuffer->EnableReadLock();
     MOZ_ASSERT(mBackBuffer->CanExposeDrawTarget());
 
     bufferCreated = true;
   }
 
   bool updated = false;
   {
     TextureClientAutoLock autoLock(mBackBuffer, OpenMode::OPEN_WRITE_ONLY);
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -745,30 +745,29 @@ ContentClientRemoteBuffer::CreateBufferI
 {
   TextureAllocationFlags textureAllocFlags
                          = (aFlags & TextureFlags::COMPONENT_ALPHA) ?
                             TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK :
                             TextureAllocationFlags::ALLOC_CLEAR_BUFFER;
 
   RefPtr<TextureClient> textureClient = CreateTextureClientForDrawing(
     aFormat, aRect.Size(), BackendSelector::Content,
-    aFlags | ExtraTextureFlags(),
+    aFlags | ExtraTextureFlags() | TextureFlags::BLOCKING_READ_LOCK,
     textureAllocFlags
   );
 
   if (!textureClient || !AddTextureClient(textureClient)) {
     return nullptr;
   }
-  textureClient->EnableBlockingReadLock();
 
   RefPtr<TextureClient> textureClientOnWhite;
   if (aFlags & TextureFlags::COMPONENT_ALPHA) {
     textureClientOnWhite = textureClient->CreateSimilar(
       mForwarder->GetCompositorBackendType(),
-      aFlags | ExtraTextureFlags(),
+      aFlags | ExtraTextureFlags() | TextureFlags::BLOCKING_READ_LOCK,
       TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE
     );
     if (!textureClientOnWhite || !AddTextureClient(textureClientOnWhite)) {
       return nullptr;
     }
     // We don't enable the readlock for the white buffer since we always
     // use them together and waiting on the lock for the black
     // should be sufficient.
--- a/gfx/layers/client/SingleTiledContentClient.cpp
+++ b/gfx/layers/client/SingleTiledContentClient.cpp
@@ -92,17 +92,17 @@ ClientSingleTiledLayerBuffer::GetSurface
 }
 
 already_AddRefed<TextureClient>
 ClientSingleTiledLayerBuffer::GetTextureClient()
 {
   MOZ_ASSERT(mFormat != gfx::SurfaceFormat::UNKNOWN);
   return mCompositableClient.CreateTextureClientForDrawing(
     gfx::ImageFormatToSurfaceFormat(mFormat), mSize, BackendSelector::Content,
-    TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD);
+    TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::NON_BLOCKING_READ_LOCK);
 }
 
 void
 ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
                                           const nsIntRegion& aPaintRegion,
                                           const nsIntRegion& aDirtyRegion,
                                           LayerManager::DrawPaintedLayerCallback aCallback,
                                           void* aCallbackData,
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -592,33 +592,30 @@ void
 TextureClient::EnableReadLock()
 {
   if (!mReadLock) {
     mReadLock = NonBlockingTextureReadLock::Create(mAllocator);
   }
 }
 
 bool
-TextureClient::SerializeReadLock(ReadLockDescriptor& aDescriptor)
+TextureClient::OnForwardedToHost()
 {
   if (mData) {
     mData->OnForwardedToHost();
   }
 
   if (mReadLock && mUpdated) {
     // Take a read lock on behalf of the TextureHost. The latter will unlock
     // after the shared data is available again for drawing.
     mReadLock->ReadLock();
     mUpdated = false;
-    if (mReadLock->Serialize(aDescriptor, GetAllocator()->GetParentPid())) {
-      return true;
-    }
+    return true;
   }
 
-  aDescriptor = null_t();
   return false;
 }
 
 TextureClient::~TextureClient()
 {
   // TextureClients should be kept alive while there are references on the
   // paint thread.
   MOZ_ASSERT(mPaintThreadRefs == 0);
@@ -923,18 +920,24 @@ TextureClient::InitIPDLActor(Compositabl
   mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
 
   nsIEventTarget* target = nullptr;
   // Get the layers id if the forwarder is a ShadowLayerForwarder.
   if (ShadowLayerForwarder* forwarder = aForwarder->AsLayerForwarder()) {
     target = forwarder->GetEventTarget();
   }
 
+  ReadLockDescriptor readLockDescriptor = null_t();
+  if (mReadLock) {
+    mReadLock->Serialize(readLockDescriptor, GetAllocator()->GetParentPid());
+  }
+
   PTextureChild* actor = aForwarder->GetTextureForwarder()->CreateTexture(
     desc,
+    readLockDescriptor,
     aForwarder->GetCompositorBackendType(),
     GetFlags(),
     mSerial,
     mExternalImageId,
     target);
 
   if (!actor) {
     gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
@@ -985,18 +988,24 @@ TextureClient::InitIPDLActor(KnowsCompos
   SurfaceDescriptor desc;
   if (!ToSurfaceDescriptor(desc)) {
     return false;
   }
 
   // Try external image id allocation.
   mExternalImageId = aForwarder->GetTextureForwarder()->GetNextExternalImageId();
 
+  ReadLockDescriptor readLockDescriptor = null_t();
+  if (mReadLock) {
+    mReadLock->Serialize(readLockDescriptor, GetAllocator()->GetParentPid());
+  }
+
   PTextureChild* actor = fwd->CreateTexture(
     desc,
+    readLockDescriptor,
     aForwarder->GetCompositorBackendType(),
     GetFlags(),
     mSerial,
     mExternalImageId);
   if (!actor) {
     gfxCriticalNote << static_cast<int32_t>(desc.type()) << ", "
                     << static_cast<int32_t>(aForwarder->GetCompositorBackendType()) << ", "
                     << static_cast<uint32_t>(GetFlags())
@@ -1345,16 +1354,22 @@ TextureClient::TextureClient(TextureData
   , mFwdTransactionId(0)
   , mSerial(++sSerialCounter)
 #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
   , mPoolTracker(nullptr)
 #endif
 {
   mData->FillInfo(mInfo);
   mFlags |= mData->GetTextureFlags();
+
+  if (mFlags & TextureFlags::NON_BLOCKING_READ_LOCK) {
+    EnableReadLock();
+  } else if (mFlags & TextureFlags::BLOCKING_READ_LOCK) {
+    EnableBlockingReadLock();
+  }
 }
 
 bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
                                         const gfx::IntRect* aRect,
                                         const gfx::IntPoint* aPoint)
 {
   MOZ_ASSERT(IsLocked());
   MOZ_ASSERT(aTarget->IsLocked());
@@ -1508,19 +1523,21 @@ public:
   bool mAllocSuccess;
 };
 
 class CrossProcessSemaphoreReadLock : public TextureReadLock
 {
 public:
   CrossProcessSemaphoreReadLock()
     : mSemaphore(CrossProcessSemaphore::Create("TextureReadLock", 1))
+    , mShared(false)
   {}
   explicit CrossProcessSemaphoreReadLock(CrossProcessSemaphoreHandle aHandle)
     : mSemaphore(CrossProcessSemaphore::Create(aHandle))
+    , mShared(false)
   {}
 
   virtual bool ReadLock() override
   {
     if (!IsValid()) {
       return false;
     }
     return mSemaphore->Wait();
@@ -1542,16 +1559,17 @@ public:
   }
   virtual bool IsValid() const override { return !!mSemaphore; }
 
   virtual bool Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther) override;
 
   virtual LockType GetType() override { return TYPE_CROSS_PROCESS_SEMAPHORE; }
 
   UniquePtr<CrossProcessSemaphore> mSemaphore;
+  bool mShared;
 };
 
 // static
 already_AddRefed<TextureReadLock>
 TextureReadLock::Deserialize(const ReadLockDescriptor& aDescriptor, ISurfaceAllocator* aAllocator)
 {
   switch (aDescriptor.type()) {
     case ReadLockDescriptor::TShmemSection: {
@@ -1723,21 +1741,23 @@ ShmemTextureReadLock::GetReadCount() {
   }
   ShmReadLockInfo* info = GetShmReadLockInfoPtr();
   return info->readCount;
 }
 
 bool
 CrossProcessSemaphoreReadLock::Serialize(ReadLockDescriptor& aOutput, base::ProcessId aOther)
 {
-  if (IsValid()) {
+  if (!mShared && IsValid()) {
     aOutput = ReadLockDescriptor(CrossProcessSemaphoreDescriptor(mSemaphore->ShareToProcess(aOther)));
+    mSemaphore->CloseHandle();
+    mShared = true;
     return true;
   } else {
-    return false;
+    return mShared;
   }
 }
 
 void
 TextureClient::EnableBlockingReadLock()
 {
   if (!mReadLock) {
     mReadLock = new CrossProcessSemaphoreReadLock();
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -630,27 +630,24 @@ public:
   void SetLastFwdTransactionId(uint64_t aTransactionId)
   {
     MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
     mFwdTransactionId = aTransactionId;
   }
 
   uint64_t GetLastFwdTransactionId() { return mFwdTransactionId; }
 
-  void EnableReadLock();
-  void EnableBlockingReadLock();
-
   TextureReadLock* GetReadLock() { return mReadLock; }
 
   bool IsReadLocked() const;
 
   bool TryReadLock();
   void ReadUnlock();
 
-  bool SerializeReadLock(ReadLockDescriptor& aDescriptor);
+  bool OnForwardedToHost();
 
   // Mark that the TextureClient will be used by the paint thread, and should not
   // free its underlying texture data. This must only be called from the main
   // thread.
   void AddPaintThreadRef();
 
   // Mark that the TextureClient is no longer in use by the PaintThread. This
   // must only be called from the PaintThread.
@@ -678,16 +675,19 @@ private:
   CreateForRawBufferAccess(LayersIPCChannel* aAllocator,
                            gfx::SurfaceFormat aFormat,
                            gfx::IntSize aSize,
                            gfx::BackendType aMoz2dBackend,
                            LayersBackend aLayersBackend,
                            TextureFlags aTextureFlags,
                            TextureAllocationFlags flags = ALLOC_DEFAULT);
 
+  void EnableReadLock();
+  void EnableBlockingReadLock();
+
   /**
    * Called once, during the destruction of the Texture, on the thread in which
    * texture's reference count reaches 0 (could be any thread).
    *
    * Here goes the shut-down code that uses virtual methods.
    * Must only be called by Release().
    */
   void Finalize() {}
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -637,18 +637,16 @@ CreateBackBufferTexture(TextureClient* a
 
   RefPtr<TextureClient> texture = aAllocator->GetTextureClient();
 
   if (!texture) {
     gfxCriticalError() << "[Tiling:Client] Failed to allocate a TextureClient";
     return nullptr;
   }
 
-  texture->EnableReadLock();
-
   if (!aCompositable.AddTextureClient(texture)) {
     gfxCriticalError() << "[Tiling:Client] Failed to connect a TextureClient";
     return nullptr;
   }
 
   return texture.forget();
 }
 
@@ -749,28 +747,27 @@ TileClient::GetTileDescriptor()
 {
   if (IsPlaceholderTile()) {
     mWasPlaceholder = true;
     return PlaceholderTileDescriptor();
   }
   bool wasPlaceholder = mWasPlaceholder;
   mWasPlaceholder = false;
 
-  ReadLockDescriptor lock;
-  mFrontBuffer->SerializeReadLock(lock);
+  bool readLocked = mFrontBuffer->OnForwardedToHost();
+  bool readLockedOnWhite = false;
 
-  ReadLockDescriptor lockOnWhite = null_t();
   if (mFrontBufferOnWhite) {
-    mFrontBufferOnWhite->SerializeReadLock(lockOnWhite);
+    readLockedOnWhite = mFrontBufferOnWhite->OnForwardedToHost();
   }
 
   return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
                                 mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
                                 mUpdateRect,
-                                lock, lockOnWhite,
+                                readLocked, readLockedOnWhite,
                                 wasPlaceholder);
 }
 
 void
 ClientMultiTiledLayerBuffer::DiscardBuffers()
 {
   for (TileClient& tile : mRetainedTiles) {
     tile.DiscardBuffers();
@@ -1114,17 +1111,17 @@ ClientMultiTiledLayerBuffer::ValidateTil
 
   SurfaceMode mode;
   gfxContentType content = GetContentType(&mode);
 
   if (!aTile.mAllocator) {
     aTile.SetTextureAllocator(mManager->GetCompositorBridgeChild()->GetTexturePool(
       mManager->AsShadowForwarder(),
       gfxPlatform::GetPlatform()->Optimal2DFormatForContent(content),
-      TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD));
+      TextureFlags::DISALLOW_BIGIMAGE | TextureFlags::IMMEDIATE_UPLOAD | TextureFlags::NON_BLOCKING_READ_LOCK));
     MOZ_ASSERT(aTile.mAllocator);
   }
 
   nsIntRegion offsetScaledDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin);
   offsetScaledDirtyRegion.ScaleRoundOut(mResolution, mResolution);
 
   std::vector<CapturedTiledPaintState::Copy> asyncPaintCopies;
   std::vector<RefPtr<TextureClient>> asyncPaintClients;
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -69,16 +69,17 @@ namespace layers {
 class TextureParent : public ParentActor<PTextureParent>
 {
 public:
   explicit TextureParent(HostIPCAllocator* aAllocator, uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId);
 
   ~TextureParent();
 
   bool Init(const SurfaceDescriptor& aSharedData,
+            const ReadLockDescriptor& aReadLock,
             const LayersBackend& aLayersBackend,
             const TextureFlags& aFlags);
 
   void NotifyNotUsed(uint64_t aTransactionId);
 
   virtual mozilla::ipc::IPCResult RecvRecycleTexture(const TextureFlags& aTextureFlags) override;
 
   TextureHost* GetTextureHost() { return mTextureHost; }
@@ -106,23 +107,24 @@ WrapWithWebRenderTextureHost(ISurfaceAll
   }
   return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 PTextureParent*
 TextureHost::CreateIPDLActor(HostIPCAllocator* aAllocator,
                              const SurfaceDescriptor& aSharedData,
+                             const ReadLockDescriptor& aReadLock,
                              LayersBackend aLayersBackend,
                              TextureFlags aFlags,
                              uint64_t aSerial,
                              const wr::MaybeExternalImageId& aExternalImageId)
 {
   TextureParent* actor = new TextureParent(aAllocator, aSerial, aExternalImageId);
-  if (!actor->Init(aSharedData, aLayersBackend, aFlags)) {
+  if (!actor->Init(aSharedData, aReadLock, aLayersBackend, aFlags)) {
     actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
     delete actor;
     return nullptr;
   }
   return actor;
 }
 
 // static
@@ -188,16 +190,17 @@ already_AddRefed<TextureHost> CreateText
 // implemented in TextureD3D11.cpp
 already_AddRefed<TextureHost> CreateTextureHostD3D11(const SurfaceDescriptor& aDesc,
                                                      ISurfaceAllocator* aDeallocator,
                                                      LayersBackend aBackend,
                                                      TextureFlags aFlags);
 
 already_AddRefed<TextureHost>
 TextureHost::Create(const SurfaceDescriptor& aDesc,
+                    const ReadLockDescriptor& aReadLock,
                     ISurfaceAllocator* aDeallocator,
                     LayersBackend aBackend,
                     TextureFlags aFlags,
                     wr::MaybeExternalImageId& aExternalImageId)
 {
   RefPtr<TextureHost> result;
 
   switch (aDesc.type()) {
@@ -247,16 +250,20 @@ TextureHost::Create(const SurfaceDescrip
       MOZ_CRASH("GFX: Unsupported Surface type host");
   }
 
   if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
     MOZ_ASSERT(aExternalImageId.isSome());
     result = new WebRenderTextureHost(aDesc, aFlags, result, aExternalImageId.ref());
   }
 
+  if (result) {
+    result->DeserializeReadLock(aReadLock, aDeallocator);
+  }
+
   return result.forget();
 }
 
 already_AddRefed<TextureHost>
 CreateBackendIndependentTextureHost(const SurfaceDescriptor& aDesc,
                                     ISurfaceAllocator* aDeallocator,
                                     LayersBackend aBackend,
                                     TextureFlags aFlags)
@@ -350,16 +357,17 @@ CreateBackendIndependentTextureHost(cons
 }
 
 TextureHost::TextureHost(TextureFlags aFlags)
     : AtomicRefCountedWithFinalize("TextureHost")
     , mActor(nullptr)
     , mFlags(aFlags)
     , mCompositableCount(0)
     , mFwdTransactionId(0)
+    , mReadLocked(false)
 {
 }
 
 TextureHost::~TextureHost()
 {
   // If we still have a ReadLock, unlock it. At this point we don't care about
   // the texture client being written into on the other side since it should be
   // destroyed by now. But we will hit assertions if we don't ReadUnlock before
@@ -373,17 +381,17 @@ void TextureHost::Finalize()
     DeallocateSharedData();
     DeallocateDeviceData();
   }
 }
 
 void
 TextureHost::UnbindTextureSource()
 {
-  if (mReadLock) {
+  if (mReadLocked) {
     // This TextureHost is not used anymore. Since most compositor backends are
     // working asynchronously under the hood a compositor could still be using
     // this texture, so it is generally best to wait until the end of the next
     // composition before calling ReadUnlock. We ask the compositor to take care
     // of that for us.
     if (mProvider) {
       mProvider->UnlockAfterComposition(this);
     } else {
@@ -669,45 +677,41 @@ BufferTextureHost::PushDisplayItems(wr::
                                   aFilter);
   }
 }
 
 void
 TextureHost::DeserializeReadLock(const ReadLockDescriptor& aDesc,
                                  ISurfaceAllocator* aAllocator)
 {
-  RefPtr<TextureReadLock> lock = TextureReadLock::Deserialize(aDesc, aAllocator);
-  if (!lock) {
+  if (mReadLock) {
     return;
   }
 
-  // If mReadLock is not null it means we haven't unlocked it yet and the content
-  // side should not have been able to write into this texture and send a new lock!
-  MOZ_ASSERT(!mReadLock);
-  mReadLock = lock.forget();
+  mReadLock = TextureReadLock::Deserialize(aDesc, aAllocator);
 }
 
 void
-TextureHost::SetReadLock(TextureReadLock* aReadLock)
+TextureHost::SetReadLocked()
 {
-  if (!aReadLock) {
+  if (!mReadLock) {
     return;
   }
-  // If mReadLock is not null it means we haven't unlocked it yet and the content
-  // side should not have been able to write into this texture and send a new lock!
-  MOZ_ASSERT(!mReadLock);
-  mReadLock = aReadLock;
+  // If mReadLocked is true it means we haven't read unlocked yet and the content
+  // side should not have been able to write into this texture and read lock again!
+  MOZ_ASSERT(!mReadLocked);
+  mReadLocked = true;
 }
 
 void
 TextureHost::ReadUnlock()
 {
-  if (mReadLock) {
+  if (mReadLock && mReadLocked) {
     mReadLock->ReadUnlock();
-    mReadLock = nullptr;
+    mReadLocked = false;
   }
 }
 
 bool
 BufferTextureHost::EnsureWrappingTextureSource()
 {
   MOZ_ASSERT(!mHasIntermediateBuffer);
 
@@ -1243,20 +1247,22 @@ TextureParent::NotifyNotUsed(uint64_t aT
   if (!mTextureHost) {
     return;
   }
   mSurfaceAllocator->NotifyNotUsed(this, aTransactionId);
 }
 
 bool
 TextureParent::Init(const SurfaceDescriptor& aSharedData,
+                    const ReadLockDescriptor& aReadLock,
                     const LayersBackend& aBackend,
                     const TextureFlags& aFlags)
 {
   mTextureHost = TextureHost::Create(aSharedData,
+                                     aReadLock,
                                      mSurfaceAllocator,
                                      aBackend,
                                      aFlags,
                                      mExternalImageId);
   if (mTextureHost) {
     mTextureHost->mActor = this;
   }
 
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -396,16 +396,17 @@ protected:
   virtual ~TextureHost();
 
 public:
   /**
    * Factory method.
    */
   static already_AddRefed<TextureHost> Create(
     const SurfaceDescriptor& aDesc,
+    const ReadLockDescriptor& aReadLock,
     ISurfaceAllocator* aDeallocator,
     LayersBackend aBackend,
     TextureFlags aFlags,
     wr::MaybeExternalImageId& aExternalImageId);
 
   /**
    * Lock the texture host for compositing.
    */
@@ -543,16 +544,17 @@ public:
    *
    * TextureParent< is an implementation detail of TextureHost that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
    * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPTextureParent and DeallocPTextureParent).
    */
   static PTextureParent* CreateIPDLActor(HostIPCAllocator* aAllocator,
                                          const SurfaceDescriptor& aSharedData,
+                                         const ReadLockDescriptor& aDescriptor,
                                          LayersBackend aLayersBackend,
                                          TextureFlags aFlags,
                                          uint64_t aSerial,
                                          const wr::MaybeExternalImageId& aExternalImageId);
   static bool DestroyIPDLActor(PTextureParent* actor);
 
   /**
    * Destroy the TextureChild/Parent pair.
@@ -607,17 +609,17 @@ public:
   }
 
   int NumCompositableRefs() const { return mCompositableCount; }
 
   void SetLastFwdTransactionId(uint64_t aTransactionId);
 
   void DeserializeReadLock(const ReadLockDescriptor& aDesc,
                            ISurfaceAllocator* aAllocator);
-  void SetReadLock(TextureReadLock* aReadLock);
+  void SetReadLocked();
 
   TextureReadLock* GetReadLock() { return mReadLock; }
 
   virtual BufferTextureHost* AsBufferTextureHost() { return nullptr; }
   virtual MacIOSurfaceTextureHostOGL* AsMacIOSurfaceTextureHost() { return nullptr; }
   virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
 
   // Create the corresponding RenderTextureHost type of this texture, and
@@ -676,16 +678,17 @@ protected:
   void CallNotifyNotUsed();
 
   PTextureParent* mActor;
   RefPtr<TextureSourceProvider> mProvider;
   RefPtr<TextureReadLock> mReadLock;
   TextureFlags mFlags;
   int mCompositableCount;
   uint64_t mFwdTransactionId;
+  bool mReadLocked;
 
   friend class Compositor;
   friend class TextureParent;
   friend class TiledLayerBufferComposite;
   friend class TextureSourceProvider;
 };
 
 /**
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -316,25 +316,27 @@ TiledLayerBufferComposite::UseTiles(cons
         "Unrecognised tile descriptor type");
       continue;
     }
 
     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
 
     tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
     tile.mTextureHost->SetTextureSourceProvider(aLayerManager->GetCompositor());
-    tile.mTextureHost->DeserializeReadLock(texturedDesc.sharedLock(), aAllocator);
+    if (texturedDesc.readLocked()) {
+      tile.mTextureHost->SetReadLocked();
+    }
 
     if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
       tile.mTextureHostOnWhite = TextureHost::AsTextureHost(
         texturedDesc.textureOnWhite().get_PTextureParent()
       );
-      tile.mTextureHostOnWhite->DeserializeReadLock(
-        texturedDesc.sharedLockOnWhite(), aAllocator
-      );
+      if (texturedDesc.readLockedOnWhite()) {
+        tile.mTextureHostOnWhite->SetReadLocked();
+      }
     }
 
     tile.mTilePosition = newTiles.TilePosition(i);
 
     // If this same tile texture existed in the old tile set then this will move the texture
     // source into our new tile.
     oldRetainedTiles.RecycleTextureSourceForTile(tile);
 
--- a/gfx/layers/ipc/CompositableTransactionParent.cpp
+++ b/gfx/layers/ipc/CompositableTransactionParent.cpp
@@ -156,17 +156,19 @@ CompositableParentManager::ReceiveCompos
         CompositableHost::TimedTexture* t = textures.AppendElement();
         t->mTexture =
             TextureHost::AsTextureHost(timedTexture.textureParent());
         MOZ_ASSERT(t->mTexture);
         t->mTimeStamp = timedTexture.timeStamp();
         t->mPictureRect = timedTexture.picture();
         t->mFrameID = timedTexture.frameID();
         t->mProducerID = timedTexture.producerID();
-        t->mTexture->SetReadLock(FindReadLock(timedTexture.sharedLock()));
+        if (timedTexture.readLocked()) {
+          t->mTexture->SetReadLocked();
+        }
       }
       if (textures.Length() > 0) {
         compositable->UseTextureHost(textures);
 
         for (auto& timedTexture : op.textures()) {
           RefPtr<TextureHost> texture = TextureHost::AsTextureHost(timedTexture.textureParent());
           if (texture) {
             texture->SetLastFwdTransactionId(mFwdTransactionId);
@@ -181,18 +183,22 @@ CompositableParentManager::ReceiveCompos
         ScheduleComposition(compositable);
       }
       break;
     }
     case CompositableOperationDetail::TOpUseComponentAlphaTextures: {
       const OpUseComponentAlphaTextures& op = aEdit.detail().get_OpUseComponentAlphaTextures();
       RefPtr<TextureHost> texOnBlack = TextureHost::AsTextureHost(op.textureOnBlackParent());
       RefPtr<TextureHost> texOnWhite = TextureHost::AsTextureHost(op.textureOnWhiteParent());
-      texOnBlack->SetReadLock(FindReadLock(op.sharedLockBlack()));
-      texOnWhite->SetReadLock(FindReadLock(op.sharedLockWhite()));
+      if (op.readLockedBlack()) {
+        texOnBlack->SetReadLocked();
+      }
+      if (op.readLockedWhite()) {
+        texOnWhite->SetReadLocked();
+      }
 
       MOZ_ASSERT(texOnBlack && texOnWhite);
       compositable->UseComponentAlphaTextures(texOnBlack, texOnWhite);
 
       if (texOnBlack) {
         texOnBlack->SetLastFwdTransactionId(mFwdTransactionId);
         // Make sure that each texture was handled by the compositable
         // because the recycling logic depends on it.
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -847,16 +847,17 @@ CompositorBridgeChild::SendAllPluginsCap
   if (!mCanSend) {
     return false;
   }
   return PCompositorBridgeChild::SendAllPluginsCaptured();
 }
 
 PTextureChild*
 CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+                                          const ReadLockDescriptor&,
                                           const LayersBackend&,
                                           const TextureFlags&,
                                           const uint64_t&,
                                           const uint64_t& aSerial,
                                           const wr::MaybeExternalImageId& aExternalImageId)
 {
   return TextureClient::CreateIPDLActor();
 }
@@ -999,32 +1000,33 @@ CompositorBridgeChild::GetTileLockAlloca
   if (!mSectionAllocator) {
     mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this);
   }
   return mSectionAllocator;
 }
 
 PTextureChild*
 CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+                                     const ReadLockDescriptor& aReadLock,
                                      LayersBackend aLayersBackend,
                                      TextureFlags aFlags,
                                      uint64_t aSerial,
                                      wr::MaybeExternalImageId& aExternalImageId,
                                      nsIEventTarget* aTarget)
 {
   PTextureChild* textureChild = AllocPTextureChild(
-    aSharedData, aLayersBackend, aFlags, 0 /* FIXME */, aSerial, aExternalImageId);
+    aSharedData, aReadLock, aLayersBackend, aFlags, 0 /* FIXME */, aSerial, aExternalImageId);
 
   // Do the DOM labeling.
   if (aTarget) {
     SetEventTargetForActor(textureChild, aTarget);
   }
 
   return SendPTextureConstructor(
-    textureChild, aSharedData, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial, aExternalImageId);
+    textureChild, aSharedData, aReadLock, aLayersBackend, aFlags, 0 /* FIXME? */, aSerial, aExternalImageId);
 }
 
 bool
 CompositorBridgeChild::AllocUnsafeShmem(size_t aSize,
                                    ipc::SharedMemory::SharedMemoryType aType,
                                    ipc::Shmem* aShmem)
 {
   ShmemAllocated(this);
--- a/gfx/layers/ipc/CompositorBridgeChild.h
+++ b/gfx/layers/ipc/CompositorBridgeChild.h
@@ -99,27 +99,29 @@ public:
 
   virtual mozilla::ipc::IPCResult
   RecvCaptureAllPlugins(const uintptr_t& aParentWidget) override;
 
   virtual mozilla::ipc::IPCResult
   RecvHideAllPlugins(const uintptr_t& aParentWidget) override;
 
   virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+                                            const ReadLockDescriptor& aReadLock,
                                             const LayersBackend& aLayersBackend,
                                             const TextureFlags& aFlags,
                                             const uint64_t& aId,
                                             const uint64_t& aSerial,
                                             const wr::MaybeExternalImageId& aExternalImageId) override;
 
   virtual bool DeallocPTextureChild(PTextureChild* actor) override;
 
   virtual mozilla::ipc::IPCResult
   RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) override;
   virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+                                       const ReadLockDescriptor& aReadLock,
                                        LayersBackend aLayersBackend,
                                        TextureFlags aFlags,
                                        uint64_t aSerial,
                                        wr::MaybeExternalImageId& aExternalImageId,
                                        nsIEventTarget* aTarget) override;
 
   /**
    * Request that the parent tell us when graphics are ready on GPU.
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -2221,23 +2221,24 @@ CompositorBridgeParent::GetGeckoContentC
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   CompositorBridgeParent::LayerTreeState* state =
       GetStateForRoot(aContentLayersId, lock);
   return state ? state->mController.get() : nullptr;
 }
 
 PTextureParent*
 CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                            const ReadLockDescriptor& aReadLock,
                                             const LayersBackend& aLayersBackend,
                                             const TextureFlags& aFlags,
                                             const uint64_t& aId,
                                             const uint64_t& aSerial,
                                             const wr::MaybeExternalImageId& aExternalImageId)
 {
-  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
+  return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId);
 }
 
 bool
 CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -263,16 +263,17 @@ public:
   void GetAPZTestData(const uint64_t& aLayersId,
                       APZTestData* aOutData) override;
   void SetConfirmedTargetAPZC(const uint64_t& aLayersId,
                               const uint64_t& aInputBlockId,
                               const nsTArray<ScrollableLayerGuid>& aTargets) override;
   AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; }
 
   PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                      const ReadLockDescriptor& aReadLock,
                                       const LayersBackend& aLayersBackend,
                                       const TextureFlags& aFlags,
                                       const uint64_t& aId,
                                       const uint64_t& aSerial,
                                       const wr::MaybeExternalImageId& aExternalImageId) override;
   bool DeallocPTextureParent(PTextureParent* actor) override;
 
   bool IsSameProcess() const override;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -566,16 +566,17 @@ CrossProcessCompositorBridgeParent::Defe
 
 CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent()
 {
   MOZ_ASSERT(XRE_GetIOMessageLoop());
 }
 
 PTextureParent*
 CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                                        const ReadLockDescriptor& aReadLock,
                                                         const LayersBackend& aLayersBackend,
                                                         const TextureFlags& aFlags,
                                                         const uint64_t& aId,
                                                         const uint64_t& aSerial,
                                                         const wr::MaybeExternalImageId& aExternalImageId)
 {
   CompositorBridgeParent::LayerTreeState* state = nullptr;
 
@@ -597,17 +598,17 @@ CrossProcessCompositorBridgeParent::Allo
     // return null because this will mess up deserialization later and we'll
     // kill the content process. Instead, we signal that the underlying
     // TextureHost should not attempt to access the compositor.
     flags |= TextureFlags::INVALID_COMPOSITOR;
   } else if (actualBackend != LayersBackend::LAYERS_NONE && aLayersBackend != actualBackend) {
     gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong";
   }
 
-  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
+  return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId);
 }
 
 bool
 CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.h
@@ -117,16 +117,17 @@ public:
   void DidCompositeLocked(uint64_t aId,
                                   TimeStamp& aCompositeStart,
                                   TimeStamp& aCompositeEnd);
   void DidComposite(uint64_t aId,
                     TimeStamp& aCompositeStart,
                     TimeStamp& aCompositeEnd) override;
 
   PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                      const ReadLockDescriptor& aReadLock,
                                       const LayersBackend& aLayersBackend,
                                       const TextureFlags& aFlags,
                                       const uint64_t& aId,
                                       const uint64_t& aSerial,
                                       const wr::MaybeExternalImageId& aExternalImageId) override;
 
   bool DeallocPTextureParent(PTextureParent* actor) override;
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -136,26 +136,21 @@ ImageBridgeChild::UseTextures(Compositab
   for (auto& t : aTextures) {
     MOZ_ASSERT(t.mTextureClient);
     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
 
     if (!t.mTextureClient->IsSharedWithCompositor()) {
       return;
     }
 
-    ReadLockDescriptor readLock;
-    ReadLockHandle readLockHandle;
-    if (t.mTextureClient->SerializeReadLock(readLock)) {
-      readLockHandle = mTxn->AddReadLock(readLock);
-    }
-
+    bool readLocked = t.mTextureClient->OnForwardedToHost();
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
-                                        readLockHandle,
                                         t.mTimeStamp, t.mPictureRect,
-                                        t.mFrameID, t.mProducerID));
+                                        t.mFrameID, t.mProducerID,
+                                        readLocked));
 
     // Wait end of usage on host side if TextureFlags::RECYCLE is set
     HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
   mTxn->AddNoSwapEdit(CompositableOperation(aCompositable->GetIPCHandle(),
                                             OpUseTexture(textures)));
 }
 
@@ -960,16 +955,17 @@ ImageBridgeChild::DeallocShmem(ipc::Shme
   GetMessageLoop()->PostTask(runnable.forget());
 
   task.Wait();
   return result;
 }
 
 PTextureChild*
 ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+                                     const ReadLockDescriptor&,
                                      const LayersBackend&,
                                      const TextureFlags&,
                                      const uint64_t& aSerial,
                                      const wr::MaybeExternalImageId& aExternalImageId)
 {
   MOZ_ASSERT(CanSend());
   return TextureClient::CreateIPDLActor();
 }
@@ -1030,24 +1026,25 @@ ImageBridgeChild::RecvDidComposite(Infal
       listener->NotifyComposite(n);
     }
   }
   return IPC_OK();
 }
 
 PTextureChild*
 ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+                                const ReadLockDescriptor& aReadLock,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags,
                                 uint64_t aSerial,
                                 wr::MaybeExternalImageId& aExternalImageId,
                                 nsIEventTarget* aTarget)
 {
   MOZ_ASSERT(CanSend());
-  return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
+  return SendPTextureConstructor(aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId);
 }
 
 static bool
 IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op)
 {
   if (aTxn->Finished()) {
     return false;
   }
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -168,16 +168,17 @@ public:
    * Can be called from any thread.
    */
   virtual MessageLoop * GetMessageLoop() const override;
 
   virtual base::ProcessId GetParentPid() const override { return OtherPid(); }
 
   virtual PTextureChild*
   AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+                     const ReadLockDescriptor& aReadLock,
                      const LayersBackend& aLayersBackend,
                      const TextureFlags& aFlags,
                      const uint64_t& aSerial,
                      const wr::MaybeExternalImageId& aExternalImageId) override;
 
   virtual bool
   DeallocPTextureChild(PTextureChild* actor) override;
 
@@ -326,16 +327,17 @@ public:
    * Can be used from any thread.
    * If used outside the ImageBridgeChild thread, it will proxy a synchronous
    * call on the ImageBridgeChild thread.
    */
   virtual bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
 
   virtual PTextureChild* CreateTexture(
     const SurfaceDescriptor& aSharedData,
+    const ReadLockDescriptor& aReadLock,
     LayersBackend aLayersBackend,
     TextureFlags aFlags,
     uint64_t aSerial,
     wr::MaybeExternalImageId& aExternalImageId,
     nsIEventTarget* aTarget = nullptr) override;
 
   virtual bool IsSameProcess() const override;
 
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -315,22 +315,23 @@ mozilla::ipc::IPCResult
 ImageBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
 {
   ReleaseCompositable(aHandle);
   return IPC_OK();
 }
 
 PTextureParent*
 ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                       const ReadLockDescriptor& aReadLock,
                                        const LayersBackend& aLayersBackend,
                                        const TextureFlags& aFlags,
                                        const uint64_t& aSerial,
                                        const wr::MaybeExternalImageId& aExternalImageId)
 {
-  return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial, aExternalImageId);
+  return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId);
 }
 
 bool
 ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   return TextureHost::DestroyIPDLActor(actor);
 }
 
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -77,16 +77,17 @@ public:
 
   // PImageBridge
   virtual mozilla::ipc::IPCResult RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
   virtual mozilla::ipc::IPCResult RecvInitReadLocks(ReadLockArray&& aReadLocks) override;
   virtual mozilla::ipc::IPCResult RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                                           const uint64_t& aFwdTransactionId) override;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                              const ReadLockDescriptor& aReadLock,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aSerial,
                                               const wr::MaybeExternalImageId& aExternalImageId) override;
   virtual bool DeallocPTextureParent(PTextureParent* actor) override;
 
   virtual mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
                                                       const TextureInfo& aInfo,
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -388,18 +388,18 @@ union MaybeTexture {
   PTexture;
   null_t;
 };
 
 struct TexturedTileDescriptor {
   PTexture texture;
   MaybeTexture textureOnWhite;
   IntRect updateRect;
-  ReadLockDescriptor sharedLock;
-  ReadLockDescriptor sharedLockOnWhite;
+  bool readLocked;
+  bool readLockedOnWhite;
   bool wasPlaceholder;
 };
 
 struct PlaceholderTileDescriptor {
 };
 
 union TileDescriptor {
   TexturedTileDescriptor;
@@ -434,21 +434,21 @@ struct OpPaintTextureRegion {
  * Tells the CompositableHost to remove the corresponding TextureHost
  */
 struct OpRemoveTexture {
   PTexture texture;
 };
 
 struct TimedTexture {
   PTexture texture;
-  ReadLockHandle sharedLock;
   TimeStamp timeStamp;
   IntRect picture;
   uint32_t frameID;
   uint32_t producerID;
+  bool readLocked;
 };
 
 /**
  * Tells the compositor-side which textures to use (for example, as front buffer
  * if there are several textures for double buffering).
  * This provides a list of textures with timestamps, ordered by timestamp.
  * The newest texture whose timestamp is <= the current time is rendered
  * (where null is considered less than every other timestamp). If there is no
@@ -458,18 +458,18 @@ struct TimedTexture {
  */
 struct OpUseTexture {
   TimedTexture[] textures;
 };
 
 struct OpUseComponentAlphaTextures {
   PTexture textureOnBlack;
   PTexture textureOnWhite;
-  ReadLockHandle sharedLockBlack;
-  ReadLockHandle sharedLockWhite;
+  bool readLockedBlack;
+  bool readLockedWhite;
 };
 
 union MaybeRegion {
   nsIntRegion;
   null_t;
 };
 
 struct OpNotifyNotUsed {
--- a/gfx/layers/ipc/PCompositorBridge.ipdl
+++ b/gfx/layers/ipc/PCompositorBridge.ipdl
@@ -241,17 +241,17 @@ parent:
   // We visualize this information in the APZ minimap.
   async NotifyApproximatelyVisibleRegion(ScrollableLayerGuid guid, CSSIntRegion region);
 
   /**
    * Sent when the child has finished CaptureAllPlugins.
    */
   async AllPluginsCaptured();
 
-  async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
+  async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
 
   sync SyncWithCompositor();
 
   // The pipelineId is the same as the layersId
   sync PWebRenderBridge(PipelineId pipelineId, LayoutDeviceIntSize aSize)
     returns (TextureFactoryIdentifier textureFactoryIdentifier, IdNamespace idNamespace);
 
   sync CheckContentOnlyTDR(uint32_t sequenceNum)
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -52,17 +52,17 @@ parent:
   // in a state in which it can't send asynchronous messages
   // so as to not race with the channel getting closed.
   // In the child side, the Closing the channel does not happen right after WillClose,
   // it is scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all of the messages from the parent side have been received and processed
   // before sending closing the channel.
   sync WillClose();
 
-  async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
+  async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
   async PMediaSystemResourceManager();
 
   sync NewCompositable(CompositableHandle aHandle, TextureInfo aInfo, LayersBackend aBackend);
   async ReleaseCompositable(CompositableHandle aHandle);
 };
 
 
 } // namespace
--- a/gfx/layers/ipc/PVideoBridge.ipdl
+++ b/gfx/layers/ipc/PVideoBridge.ipdl
@@ -19,15 +19,15 @@ namespace layers {
  * The PVideoBridge protocol is used to share textures from the video decoders
  * to the compositor.
  */
 sync protocol PVideoBridge
 {
   manages PTexture;
 
 parent:
-  async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend,
+  async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend,
                  TextureFlags aTextureFlags, uint64_t aSerial);
 };
 
 } // namespace
 } // namespace
 
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -488,25 +488,21 @@ ShadowLayerForwarder::UseTextures(Compos
   }
 
   AutoTArray<TimedTexture,4> textures;
 
   for (auto& t : aTextures) {
     MOZ_ASSERT(t.mTextureClient);
     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
     MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
-    ReadLockDescriptor readLock;
-    ReadLockHandle readLockHandle;
-    if (t.mTextureClient->SerializeReadLock(readLock)) {
-      readLockHandle = mTxn->AddReadLock(readLock);
-    }
+    bool readLocked = t.mTextureClient->OnForwardedToHost();
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
-                                        readLockHandle,
                                         t.mTimeStamp, t.mPictureRect,
-                                        t.mFrameID, t.mProducerID));
+                                        t.mFrameID, t.mProducerID,
+                                        readLocked));
     mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
   mTxn->AddEdit(CompositableOperation(aCompositable->GetIPCHandle(),
                                       OpUseTexture(textures)));
 }
 
 void
 ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositable,
@@ -523,37 +519,29 @@ ShadowLayerForwarder::UseComponentAlphaT
   MOZ_ASSERT(aTextureOnBlack);
   MOZ_ASSERT(aCompositable->GetIPCHandle());
   MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
   MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
   MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
   MOZ_RELEASE_ASSERT(aTextureOnWhite->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
   MOZ_RELEASE_ASSERT(aTextureOnBlack->GetIPDLActor()->GetIPCChannel() == mShadowManager->GetIPCChannel());
 
-  ReadLockDescriptor readLockB;
-  ReadLockHandle readLockHandleB;
-  ReadLockDescriptor readLockW;
-  ReadLockHandle readLockHandleW;
-  if (aTextureOnBlack->SerializeReadLock(readLockB)) {
-    readLockHandleB = mTxn->AddReadLock(readLockB);
-  }
-  if (aTextureOnWhite->SerializeReadLock(readLockW)) {
-    readLockHandleW = mTxn->AddReadLock(readLockW);
-  }
+  bool readLockedB = aTextureOnBlack->OnForwardedToHost();
+  bool readLockedW = aTextureOnWhite->OnForwardedToHost();
 
   mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
   mClientLayerManager->GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
 
   mTxn->AddEdit(
     CompositableOperation(
       aCompositable->GetIPCHandle(),
       OpUseComponentAlphaTextures(
         nullptr, aTextureOnBlack->GetIPDLActor(),
         nullptr, aTextureOnWhite->GetIPDLActor(),
-        readLockHandleB, readLockHandleW)
+        readLockedB, readLockedW)
       )
     );
 }
 
 static bool
 AddOpDestroy(Transaction* aTxn, const OpDestroy& op)
 {
   if (!aTxn->Opened()) {
--- a/gfx/layers/ipc/TextureForwarder.h
+++ b/gfx/layers/ipc/TextureForwarder.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOZILLA_LAYERS_TEXTUREFORWARDER
 #define MOZILLA_LAYERS_TEXTUREFORWARDER
 
 #include <stdint.h>                     // for int32_t, uint64_t
 #include "gfxTypes.h"
+#include "mozilla/layers/LayersMessages.h"  // for Edit, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "mozilla/layers/TextureClient.h"  // for TextureClient
 #include "mozilla/layers/KnowsCompositor.h"
 
 namespace mozilla {
 namespace ipc {
 class IShmemAllocator;
 }
@@ -64,16 +65,17 @@ protected:
  */
 class TextureForwarder : public LayersIPCChannel {
 public:
   /**
    * Create a TextureChild/Parent pair as as well as the TextureHost on the parent side.
    */
   virtual PTextureChild* CreateTexture(
     const SurfaceDescriptor& aSharedData,
+    const ReadLockDescriptor& aReadLock,
     LayersBackend aLayersBackend,
     TextureFlags aFlags,
     uint64_t aSerial,
     wr::MaybeExternalImageId& aExternalImageId,
     nsIEventTarget* aTarget = nullptr) = 0;
 };
 
 } // namespace layers
--- a/gfx/layers/ipc/VideoBridgeChild.cpp
+++ b/gfx/layers/ipc/VideoBridgeChild.cpp
@@ -73,16 +73,17 @@ VideoBridgeChild::AllocShmem(size_t aSiz
 bool
 VideoBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
 {
   return PVideoBridgeChild::DeallocShmem(aShmem);
 }
 
 PTextureChild*
 VideoBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+                                     const ReadLockDescriptor&,
                                      const LayersBackend&,
                                      const TextureFlags&,
                                      const uint64_t& aSerial)
 {
   MOZ_ASSERT(CanSend());
   return TextureClient::CreateIPDLActor();
 }
 
@@ -101,24 +102,25 @@ VideoBridgeChild::ActorDestroy(ActorDest
 void
 VideoBridgeChild::DeallocPVideoBridgeChild()
 {
   mIPDLSelfRef = nullptr;
 }
 
 PTextureChild*
 VideoBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+                                const ReadLockDescriptor& aReadLock,
                                 LayersBackend aLayersBackend,
                                 TextureFlags aFlags,
                                 uint64_t aSerial,
                                 wr::MaybeExternalImageId& aExternalImageId,
                                 nsIEventTarget* aTarget)
 {
   MOZ_ASSERT(CanSend());
-  return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
+  return SendPTextureConstructor(aSharedData, aReadLock, aLayersBackend, aFlags, aSerial);
 }
 
 bool VideoBridgeChild::IsSameProcess() const
 {
   return OtherPid() == base::GetCurrentProcId();
 }
 
 } // namespace layers
--- a/gfx/layers/ipc/VideoBridgeChild.h
+++ b/gfx/layers/ipc/VideoBridgeChild.h
@@ -22,16 +22,17 @@ public:
 
   static void Startup();
   static void Shutdown();
 
   static VideoBridgeChild* GetSingleton();
 
   // PVideoBridgeChild
   PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData,
+                                    const ReadLockDescriptor& aReadLock,
                                     const LayersBackend& aLayersBackend,
                                     const TextureFlags& aFlags,
                                     const uint64_t& aSerial) override;
   bool DeallocPTextureChild(PTextureChild* actor) override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void DeallocPVideoBridgeChild() override;
 
@@ -42,16 +43,17 @@ public:
                         mozilla::ipc::Shmem* aShmem) override;
   bool AllocShmem(size_t aSize,
                   mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
                   mozilla::ipc::Shmem* aShmem) override;
   bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
 
   // TextureForwarder
   PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
+                               const ReadLockDescriptor& aReadLock,
                                LayersBackend aLayersBackend,
                                TextureFlags aFlags,
                                uint64_t aSerial,
                                wr::MaybeExternalImageId& aExternalImageId,
                                nsIEventTarget* aTarget = nullptr) override;
 
   // ClientIPCAllocator
   base::ProcessId GetParentPid() const override { return OtherPid(); }
--- a/gfx/layers/ipc/VideoBridgeParent.cpp
+++ b/gfx/layers/ipc/VideoBridgeParent.cpp
@@ -52,22 +52,23 @@ void
 VideoBridgeParent::DeallocPVideoBridgeParent()
 {
   mCompositorThreadRef = nullptr;
   mSelfRef = nullptr;
 }
 
 PTextureParent*
 VideoBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                       const ReadLockDescriptor& aReadLock,
                                        const LayersBackend& aLayersBackend,
                                        const TextureFlags& aFlags,
                                        const uint64_t& aSerial)
 {
   PTextureParent* parent =
-    TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial, Nothing());
+    TextureHost::CreateIPDLActor(this, aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, Nothing());
   mTextureMap[aSerial] = parent;
   return parent;
 }
 
 bool
 VideoBridgeParent::DeallocPTextureParent(PTextureParent* actor)
 {
   mTextureMap.erase(TextureHost::GetTextureSerial(actor));
--- a/gfx/layers/ipc/VideoBridgeParent.h
+++ b/gfx/layers/ipc/VideoBridgeParent.h
@@ -24,16 +24,17 @@ public:
   ~VideoBridgeParent();
 
   static VideoBridgeParent* GetSingleton();
   TextureHost* LookupTexture(uint64_t aSerial);
 
   // PVideoBridgeParent
   void ActorDestroy(ActorDestroyReason aWhy) override;
   PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
+                                      const ReadLockDescriptor& aReadLock,
                                       const LayersBackend& aLayersBackend,
                                       const TextureFlags& aFlags,
                                       const uint64_t& aSerial) override;
   bool DeallocPTextureParent(PTextureParent* actor) override;
 
   // HostIPCAllocator
   base::ProcessId GetChildProcessId() override
   {
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -534,29 +534,22 @@ WebRenderBridgeChild::UseTextures(Compos
   }
 
   AutoTArray<TimedTexture,4> textures;
 
   for (auto& t : aTextures) {
     MOZ_ASSERT(t.mTextureClient);
     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
     MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == GetIPCChannel());
-    ReadLockDescriptor readLock;
-    ReadLockHandle readLockHandle;
-    if (t.mTextureClient->SerializeReadLock(readLock)) {
-      readLockHandle = ReadLockHandle(++mReadLockSequenceNumber);
-      if (mReadLocks.LastElement().Length() >= GetMaxFileDescriptorsPerMessage()) {
-        mReadLocks.AppendElement();
-      }
-      mReadLocks.LastElement().AppendElement(ReadLockInit(readLock, readLockHandle));
-    }
+    bool readLocked = t.mTextureClient->OnForwardedToHost();
+
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
-                                        readLockHandle,
                                         t.mTimeStamp, t.mPictureRect,
-                                        t.mFrameID, t.mProducerID));
+                                        t.mFrameID, t.mProducerID,
+                                        readLocked));
     GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
   AddWebRenderParentCommand(CompositableOperation(aCompositable->GetIPCHandle(),
                                             OpUseTexture(textures)));
 }
 
 void
 WebRenderBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
--- a/gfx/tests/gtest/TextureHelper.h
+++ b/gfx/tests/gtest/TextureHelper.h
@@ -144,19 +144,20 @@ CreateTextureHostWithBackend(TextureClie
                              LayersBackend& aLayersBackend)
 {
   if (!aClient) {
     return nullptr;
   }
 
   // client serialization
   SurfaceDescriptor descriptor;
+  ReadLockDescriptor readLock = null_t();
   RefPtr<TextureHost> textureHost;
 
   aClient->ToSurfaceDescriptor(descriptor);
 
   wr::MaybeExternalImageId id = Nothing();
-  return TextureHost::Create(descriptor, aDeallocator, aLayersBackend,
+  return TextureHost::Create(descriptor, readLock, aDeallocator, aLayersBackend,
                              aClient->GetFlags(), id);
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/ipc/glue/CrossProcessSemaphore.h
+++ b/ipc/glue/CrossProcessSemaphore.h
@@ -73,16 +73,18 @@ public:
    * ShareToProcess
    * This function is called to generate a serializable structure that can
    * be sent to the specified process and opened on the other side.
    *
    * @returns A handle that can be shared to another process
    */
   CrossProcessSemaphoreHandle ShareToProcess(base::ProcessId aTargetPid);
 
+  void CloseHandle();
+
 private:
   friend struct IPC::ParamTraits<CrossProcessSemaphore>;
 
   CrossProcessSemaphore();
   CrossProcessSemaphore(const CrossProcessSemaphore&);
   CrossProcessSemaphore &operator=(const CrossProcessSemaphore&);
 
 #if defined(OS_WIN)
--- a/ipc/glue/CrossProcessSemaphore_posix.cpp
+++ b/ipc/glue/CrossProcessSemaphore_posix.cpp
@@ -71,16 +71,18 @@ CrossProcessSemaphore::Create(CrossProce
   if (!sharedBuffer->SetHandle(aHandle, ipc::SharedMemory::RightsReadWrite)) {
     return nullptr;
   }
 
   if (!sharedBuffer->Map(sizeof(SemaphoreData))) {
     return nullptr;
   }
 
+  sharedBuffer->CloseHandle();
+
   SemaphoreData* data = static_cast<SemaphoreData*>(sharedBuffer->memory());
 
   if (!data) {
     return nullptr;
   }
 
   int32_t oldCount = data->mRefCount++;
   if (oldCount == 0) {
@@ -157,9 +159,15 @@ CrossProcessSemaphore::ShareToProcess(ba
 
   if (mSharedBuffer && !mSharedBuffer->ShareToProcess(aTargetPid, &result)) {
     MOZ_CRASH();
   }
 
   return result;
 }
 
+void
+CrossProcessSemaphore::CloseHandle()
+{
+  mSharedBuffer->CloseHandle();
+}
+
 } // namespace mozilla
--- a/ipc/glue/CrossProcessSemaphore_unimplemented.cpp
+++ b/ipc/glue/CrossProcessSemaphore_unimplemented.cpp
@@ -49,9 +49,15 @@ CrossProcessSemaphore::Signal()
 
 CrossProcessSemaphoreHandle
 CrossProcessSemaphore::ShareToProcess(base::ProcessId aTargetPid)
 {
   MOZ_CRASH("Cross-process semaphores not allowed on this platform - woah! We should've aborted by now!");
   return 0;
 }
 
+void
+CrossProcessSemaphore::CloseHandle()
+{
+  MOZ_CRASH("Cross-process semaphores not allowed on this platform - woah! We should've aborted by now!");
 }
+
+}
--- a/ipc/glue/CrossProcessSemaphore_windows.cpp
+++ b/ipc/glue/CrossProcessSemaphore_windows.cpp
@@ -80,9 +80,14 @@ CrossProcessSemaphore::ShareToProcess(ba
 
   if (!succeeded) {
     return nullptr;
   }
 
   return newHandle;
 }
 
+void
+CrossProcessSemaphore::CloseHandle()
+{
 }
+
+}