Bug 1704812 - Broadcast newly-added FontList shm blocks to Content Processes instead of waiting and doing sync IPC. r=emilio,jld
authorJonathan Kew <jkew@mozilla.com>
Thu, 13 May 2021 14:30:09 +0000
changeset 579594 f3ff56bb28ba28675ce43cbf5b7d9efec957e031
parent 579593 dc799cfb8718d43cdda81a5263ec4f09071bfbe1
child 579595 5220c9563acd5bc87370f436b259b0fccd8aa0a3
push id143093
push userjkew@mozilla.com
push dateThu, 13 May 2021 17:30:24 +0000
treeherderautoland@f3ff56bb28ba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio, jld
bugs1704812
milestone90.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1704812 - Broadcast newly-added FontList shm blocks to Content Processes instead of waiting and doing sync IPC. r=emilio,jld Differential Revision: https://phabricator.services.mozilla.com/D112666
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
gfx/thebes/SharedFontList-impl.h
gfx/thebes/SharedFontList.cpp
gfx/thebes/gfxPlatformFontList.cpp
gfx/thebes/gfxPlatformFontList.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2342,23 +2342,37 @@ mozilla::ipc::IPCResult ContentChild::Re
   mAvailableDictionaries = std::move(aDictionaries);
   mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking();
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvUpdateFontList(
     dom::SystemFontList&& aFontList) {
   mFontList = std::move(aFontList);
-  gfxPlatform::GetPlatform()->UpdateFontList(true);
+  if (gfxPlatform::Initialized()) {
+    gfxPlatform::GetPlatform()->UpdateFontList(true);
+  }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvRebuildFontList(
     const bool& aFullRebuild) {
-  gfxPlatform::GetPlatform()->UpdateFontList(aFullRebuild);
+  if (gfxPlatform::Initialized()) {
+    gfxPlatform::GetPlatform()->UpdateFontList(aFullRebuild);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult ContentChild::RecvFontListShmBlockAdded(
+    const uint32_t& aGeneration, const uint32_t& aIndex,
+    const base::SharedMemoryHandle& aHandle) {
+  if (gfxPlatform::Initialized()) {
+    gfxPlatformFontList::PlatformFontList()->ShmBlockAdded(aGeneration, aIndex,
+                                                           aHandle);
+  }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult ContentChild::RecvUpdateAppLocales(
     nsTArray<nsCString>&& aAppLocales) {
   LocaleService::GetInstance()->AssignAppLocales(aAppLocales);
   return IPC_OK();
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -347,16 +347,19 @@ class ContentChild final : public PConte
   MOZ_CAN_RUN_SCRIPT_BOUNDARY
   mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
 
   mozilla::ipc::IPCResult RecvUpdateDictionaryList(
       nsTArray<nsCString>&& aDictionaries);
 
   mozilla::ipc::IPCResult RecvUpdateFontList(SystemFontList&&);
   mozilla::ipc::IPCResult RecvRebuildFontList(const bool& aFullRebuild);
+  mozilla::ipc::IPCResult RecvFontListShmBlockAdded(
+      const uint32_t& aGeneration, const uint32_t& aIndex,
+      const base::SharedMemoryHandle& aHandle);
 
   mozilla::ipc::IPCResult RecvUpdateAppLocales(
       nsTArray<nsCString>&& aAppLocales);
   mozilla::ipc::IPCResult RecvUpdateRequestedLocales(
       nsTArray<nsCString>&& aRequestedLocales);
 
   mozilla::ipc::IPCResult RecvAddPermission(const IPC::Permission& permission);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1627,16 +1627,31 @@ void ContentParent::BroadcastStringBundl
 }
 
 void ContentParent::BroadcastFontListChanged() {
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendFontListChanged();
   }
 }
 
+void ContentParent::BroadcastShmBlockAdded(uint32_t aGeneration,
+                                           uint32_t aIndex) {
+  auto* pfl = gfxPlatformFontList::PlatformFontList();
+  for (auto* cp : AllProcesses(eLive)) {
+    base::SharedMemoryHandle handle =
+        pfl->ShareShmBlockToProcess(aIndex, cp->Pid());
+    if (handle == base::SharedMemory::NULLHandle()) {
+      // If something went wrong here, we just skip it; the child will need to
+      // request the block as needed, at some performance cost.
+      continue;
+    }
+    Unused << cp->SendFontListShmBlockAdded(aGeneration, aIndex, handle);
+  }
+}
+
 void ContentParent::BroadcastThemeUpdate(widget::ThemeChangeKind aKind) {
   const FullLookAndFeel& lnf = *RemoteLookAndFeel::ExtractData();
   for (auto* cp : AllProcesses(eLive)) {
     Unused << cp->SendThemeChanged(lnf, aKind);
   }
 }
 
 /*static */
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -254,16 +254,17 @@ class ContentParent final
    */
   static void GetAll(nsTArray<ContentParent*>& aArray);
 
   static void GetAllEvenIfDead(nsTArray<ContentParent*>& aArray);
 
   static void BroadcastStringBundle(const StringBundleDescriptor&);
 
   static void BroadcastFontListChanged();
+  static void BroadcastShmBlockAdded(uint32_t aGeneration, uint32_t aIndex);
 
   static void BroadcastThemeUpdate(widget::ThemeChangeKind);
 
   static void BroadcastMediaCodecsSupportedUpdate(
       RemoteDecodeIn aLocation,
       const PDMFactory::MediaCodecsSupported& aSupported);
 
   const nsACString& GetRemoteType() const override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -630,16 +630,23 @@ child:
 
     /**
      * The shared font list has been modified, potentially adding matches
      * for src:local() names that were previously not known, so content
      * may need to be reflowed.
      */
     async FontListChanged();
 
+    /**
+     * A new shmem block has been added to the font list; the child process
+     * should map the new block and add to its index.
+     */
+    async FontListShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
+                                SharedMemoryHandle aHandle);
+
     async UpdateAppLocales(nsCString[] appLocales);
     async UpdateRequestedLocales(nsCString[] requestedLocales);
 
     async RegisterStringBundles(StringBundleDescriptor[] stringBundles);
 
     async UpdateSharedData(FileDescriptor mapFile, uint32_t aSize,
                            IPCBlob[] blobs,
                            nsCString[] changedKeys);
--- a/gfx/thebes/SharedFontList-impl.h
+++ b/gfx/thebes/SharedFontList-impl.h
@@ -261,16 +261,21 @@ class FontList {
   /**
    * Collect an array of handles to all the shmem blocks, ready to be
    * shared to the given process. This is used at child process startup
    * to pass the complete list at once.
    */
   void ShareBlocksToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
                             base::ProcessId aPid);
 
+  base::SharedMemoryHandle ShareBlockToProcess(uint32_t aIndex,
+                                               base::ProcessId aPid);
+
+  void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
+                     base::SharedMemoryHandle aHandle);
   /**
    * Support for memory reporter.
    */
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t AllocatedShmemSize() const;
 
   /**
--- a/gfx/thebes/SharedFontList.cpp
+++ b/gfx/thebes/SharedFontList.cpp
@@ -4,16 +4,17 @@
 
 #include "SharedFontList-impl.h"
 #include "gfxPlatformFontList.h"
 #include "gfxFontUtils.h"
 #include "gfxFont.h"
 #include "nsReadableUtils.h"
 #include "prerror.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/Logging.h"
 
 #define LOG_FONTLIST(args) \
   MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug, args)
 #define LOG_FONTLIST_ENABLED() \
   MOZ_LOG_TEST(gfxPlatform::GetLog(eGfxLog_fontlist), LogLevel::Debug)
 
 namespace mozilla {
@@ -620,19 +621,63 @@ bool FontList::AppendShmBlock(uint32_t a
   block->Allocated() = sizeof(BlockHeader);
   block->BlockSize() = size;
 
   mBlocks.AppendElement(block);
   GetHeader().mBlockCount.store(mBlocks.Length());
 
   mReadOnlyShmems.AppendElement(std::move(readOnly));
 
+  // We don't need to broadcast the addition of the initial block,
+  // because child processes can't have initialized their list at all
+  // prior to the first block being set up.
+  if (mBlocks.Length() > 1) {
+    dom::ContentParent::BroadcastShmBlockAdded(GetGeneration(),
+                                               mBlocks.Length() - 1);
+  }
+
   return true;
 }
 
+void FontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
+                             base::SharedMemoryHandle aHandle) {
+  MOZ_ASSERT(!XRE_IsParentProcess());
+  MOZ_ASSERT(mBlocks.Length() > 0);
+
+  auto newShm = MakeUnique<base::SharedMemory>();
+  if (!newShm->IsHandleValid(aHandle)) {
+    return;
+  }
+  if (!newShm->SetHandle(aHandle, true)) {
+    MOZ_CRASH("failed to set shm handle");
+  }
+
+  if (aIndex != mBlocks.Length()) {
+    return;
+  }
+  if (aGeneration != GetGeneration()) {
+    return;
+  }
+
+  if (!newShm->Map(SHM_BLOCK_SIZE) || !newShm->memory()) {
+    MOZ_CRASH("failed to map shared memory");
+  }
+
+  uint32_t size = static_cast<BlockHeader*>(newShm->memory())->mBlockSize;
+  MOZ_ASSERT(size >= SHM_BLOCK_SIZE);
+  if (size != SHM_BLOCK_SIZE) {
+    newShm->Unmap();
+    if (!newShm->Map(size) || !newShm->memory()) {
+      MOZ_CRASH("failed to map shared memory");
+    }
+  }
+
+  mBlocks.AppendElement(new ShmBlock(std::move(newShm)));
+}
+
 void FontList::DetachShmBlocks() {
   for (auto& i : mBlocks) {
     i->mShmem = nullptr;
   }
   mBlocks.Clear();
   mReadOnlyShmems.Clear();
 }
 
@@ -691,16 +736,30 @@ void FontList::ShareBlocksToProcess(nsTA
       // practice this may mean resources are so constrained the child process
       // isn't really going to work at all. But that's not our problem here.)
       aBlocks->Clear();
       return;
     }
   }
 }
 
+base::SharedMemoryHandle FontList::ShareBlockToProcess(uint32_t aIndex,
+                                                       base::ProcessId aPid) {
+  MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
+  MOZ_RELEASE_ASSERT(mReadOnlyShmems.Length() == mBlocks.Length());
+  MOZ_RELEASE_ASSERT(aIndex < mReadOnlyShmems.Length());
+
+  base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
+  if (mReadOnlyShmems[aIndex]->ShareToProcess(aPid, &handle)) {
+    return handle;
+  }
+
+  return base::SharedMemory::NULLHandle();
+}
+
 Pointer FontList::Alloc(uint32_t aSize) {
   // Only the parent process does allocation.
   MOZ_ASSERT(XRE_IsParentProcess());
 
   // 4-byte alignment is good enough for anything we allocate in the font list,
   // as our "Pointer" (block index/offset) is a 32-bit value even on x64.
   auto align = [](uint32_t aSize) -> size_t { return (aSize + 3u) & ~3u; };
 
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -2652,16 +2652,29 @@ void gfxPlatformFontList::ShareFontListS
 void gfxPlatformFontList::ShareFontListToProcess(
     nsTArray<base::SharedMemoryHandle>* aBlocks, base::ProcessId aPid) {
   auto list = SharedFontList();
   if (list) {
     list->ShareBlocksToProcess(aBlocks, aPid);
   }
 }
 
+base::SharedMemoryHandle gfxPlatformFontList::ShareShmBlockToProcess(
+    uint32_t aIndex, base::ProcessId aPid) {
+  MOZ_RELEASE_ASSERT(SharedFontList());
+  return SharedFontList()->ShareBlockToProcess(aIndex, aPid);
+}
+
+void gfxPlatformFontList::ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
+                                        base::SharedMemoryHandle aHandle) {
+  if (SharedFontList()) {
+    SharedFontList()->ShmBlockAdded(aGeneration, aIndex, aHandle);
+  }
+}
+
 void gfxPlatformFontList::InitializeFamily(uint32_t aGeneration,
                                            uint32_t aFamilyIndex,
                                            bool aLoadCmaps) {
   auto list = SharedFontList();
   MOZ_ASSERT(list);
   if (!list) {
     return;
   }
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -272,16 +272,22 @@ class gfxPlatformFontList : public gfxFo
                                       base::ProcessId aPid,
                                       base::SharedMemoryHandle* aOut);
 
   // Populate the array aBlocks with the complete list of shmem handles ready
   // to be shared to the given processId.
   void ShareFontListToProcess(nsTArray<base::SharedMemoryHandle>* aBlocks,
                               base::ProcessId aPid);
 
+  void ShmBlockAdded(uint32_t aGeneration, uint32_t aIndex,
+                     base::SharedMemoryHandle aHandle);
+
+  base::SharedMemoryHandle ShareShmBlockToProcess(uint32_t aIndex,
+                                                  base::ProcessId aPid);
+
   void SetCharacterMap(uint32_t aGeneration,
                        const mozilla::fontlist::Pointer& aFacePtr,
                        const gfxSparseBitSet& aMap);
 
   void SetupFamilyCharMap(uint32_t aGeneration,
                           const mozilla::fontlist::Pointer& aFamilyPtr);
 
   // Start the async cmap loading process, if not already under way, from the