Bug 1479960 - Convert MemMapSnapshot to use frozen shared memory. r=kmag
authorJed Davis <jld@mozilla.com>
Wed, 14 Aug 2019 22:48:40 +0000
changeset 488145 c3ca7014893cd993088b4e6ad5f333ef7eed10a9
parent 488144 1fa598bf26998154cfc2c189a2a5f7fb862c7640
child 488146 f936472f7576d515b673a4e42811a7daf0f3214d
push id113900
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:53:50 +0000
treeherdermozilla-inbound@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1479960
milestone70.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 1479960 - Convert MemMapSnapshot to use frozen shared memory. r=kmag Depends on D26745 Differential Revision: https://phabricator.services.mozilla.com/D26746
dom/ipc/MemMapSnapshot.cpp
dom/ipc/MemMapSnapshot.h
--- a/dom/ipc/MemMapSnapshot.cpp
+++ b/dom/ipc/MemMapSnapshot.cpp
@@ -1,151 +1,46 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "MemMapSnapshot.h"
 
-#include "base/eintr_wrapper.h"
-#include "base/file_util.h"
-#include "mozilla/Assertions.h"
+#include "mozilla/AutoMemMap.h"
 #include "mozilla/ResultExtensions.h"
-#include "mozilla/ScopeExit.h"
-#include "mozilla/ipc/FileDescriptorUtils.h"
-#include "nsIFile.h"
-
-#ifdef XP_WIN
-#  include "mozilla/RandomNum.h"
-#  include "mozilla/WindowsVersion.h"
-#  include "nsDebug.h"
-#  include "nsString.h"
-#  include <windows.h>
-#endif
-
-#ifdef XP_UNIX
-#  include <sys/stat.h>
-#endif
 
 namespace mozilla {
 
-using loader::AutoMemMap;
-
 namespace ipc {
 
 Result<Ok, nsresult> MemMapSnapshot::Init(size_t aSize) {
   MOZ_ASSERT(!mInitialized);
 
-  MOZ_TRY(Create(aSize));
+  if (NS_WARN_IF(!mMem.CreateFreezeable(aSize))) {
+    return Err(NS_ERROR_FAILURE);
+  }
+  if (NS_WARN_IF(!mMem.Map(aSize))) {
+    return Err(NS_ERROR_FAILURE);
+  }
 
   mInitialized = true;
   return Ok();
 }
 
-Result<Ok, nsresult> MemMapSnapshot::Finalize(AutoMemMap& aMem) {
+Result<Ok, nsresult> MemMapSnapshot::Finalize(loader::AutoMemMap& aMem) {
   MOZ_ASSERT(mInitialized);
 
-  MOZ_TRY(Freeze(aMem));
+  if (NS_WARN_IF(!mMem.Freeze())) {
+    return Err(NS_ERROR_FAILURE);
+  }
+  // TakeHandle resets mMem, so call max_size first.
+  size_t size = mMem.max_size();
+  FileDescriptor memHandle(mMem.TakeHandle());
+  MOZ_TRY(aMem.initWithHandle(memHandle, size));
 
   mInitialized = false;
   return Ok();
 }
 
-#if defined(XP_WIN)
-
-Result<Ok, nsresult> MemMapSnapshot::Create(size_t aSize) {
-  SECURITY_ATTRIBUTES sa;
-  SECURITY_DESCRIPTOR sd;
-  ACL dacl;
-
-  sa.nLength = sizeof(sa);
-  sa.lpSecurityDescriptor = &sd;
-  sa.bInheritHandle = FALSE;
-
-  if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
-      NS_WARN_IF(
-          !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
-      NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
-    return Err(NS_ERROR_FAILURE);
-  }
-
-  nsAutoStringN<sizeof("MozSharedMem_") + 16 * 4> name;
-  if (!IsWin8Point1OrLater()) {
-    name.AssignLiteral("MozSharedMem_");
-    for (size_t i = 0; i < 4; ++i) {
-      Maybe<uint64_t> randomNum = RandomUint64();
-      if (NS_WARN_IF(randomNum.isNothing())) {
-        return Err(NS_ERROR_UNEXPECTED);
-      }
-      name.AppendPrintf("%016llx", *randomNum);
-    }
-  }
-
-  HANDLE handle =
-      CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0,
-                        DWORD(aSize), name.IsEmpty() ? nullptr : name.get());
-
-  if (!handle) {
-    return Err(NS_ERROR_FAILURE);
-  }
-
-  mFile.emplace(handle);
-  return mMem.initWithHandle(mFile.ref(), aSize, PR_PROT_READWRITE);
-}
-
-Result<Ok, nsresult> MemMapSnapshot::Freeze(AutoMemMap& aMem) {
-  auto orig = mFile.ref().ClonePlatformHandle();
-  mFile.reset();
-
-  HANDLE handle;
-  if (!::DuplicateHandle(
-          GetCurrentProcess(), orig.release(), GetCurrentProcess(), &handle,
-          GENERIC_READ | FILE_MAP_READ, false, DUPLICATE_CLOSE_SOURCE)) {
-    return Err(NS_ERROR_FAILURE);
-  }
-
-  return aMem.initWithHandle(FileDescriptor(handle), mMem.size());
-}
-
-#elif defined(XP_UNIX)
-
-Result<Ok, nsresult> MemMapSnapshot::Create(size_t aSize) {
-  FilePath path;
-  ScopedCloseFile fd(file_util::CreateAndOpenTemporaryShmemFile(&path));
-  if (!fd) {
-    return Err(NS_ERROR_FAILURE);
-  }
-
-  if (HANDLE_EINTR(ftruncate(fileno(fd), aSize)) != 0) {
-    return Err(NS_ERROR_FAILURE);
-  }
-
-  MOZ_TRY(mMem.init(FILEToFileDescriptor(fd), PR_PROT_READWRITE));
-
-  mPath.Assign(path.value().data(), path.value().length());
-  return Ok();
-}
-
-Result<Ok, nsresult> MemMapSnapshot::Freeze(AutoMemMap& aMem) {
-  // Delete the shm file after we're done here, whether we succeed or not. The
-  // open file descriptor will keep it alive until all remaining references
-  // are closed, at which point it will be automatically freed.
-  auto cleanup = MakeScopeExit([&]() { PR_Delete(mPath.get()); });
-
-  // Make the shm file readonly. This doesn't make a difference in practice,
-  // since we open and share a read-only file descriptor, and then delete the
-  // file. But it doesn't hurt, either.
-  chmod(mPath.get(), 0400);
-
-  nsCOMPtr<nsIFile> file;
-  MOZ_TRY(NS_NewNativeLocalFile(mPath, /* followLinks = */ false,
-                                getter_AddRefs(file)));
-
-  return aMem.init(file);
-}
-
-#else
-#  error "Unsupported build configuration"
-#endif
-
 }  // namespace ipc
 }  // namespace mozilla
--- a/dom/ipc/MemMapSnapshot.h
+++ b/dom/ipc/MemMapSnapshot.h
@@ -2,26 +2,27 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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 dom_ipc_MemMapSnapshot_h
 #define dom_ipc_MemMapSnapshot_h
 
-#include "mozilla/AutoMemMap.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/RangedPtr.h"
 #include "mozilla/Result.h"
-#ifdef XP_WIN
-#  include "mozilla/ipc/FileDescriptor.h"
-#endif
+#include "base/shared_memory.h"
 
 namespace mozilla {
+namespace loader {
+class AutoMemMap;
+}
+
 namespace ipc {
 
 /**
  * A helper class for creating a read-only snapshot of memory-mapped data.
  *
  * The Init() method initializes a read-write memory mapped region of the given
  * size, which can be initialized with arbitrary data. The Finalize() method
  * remaps that region as read-only (and backs it with a read-only file
@@ -30,33 +31,23 @@ namespace ipc {
  * The file descriptor for the resulting AutoMemMap can be shared among
  * processes, to safely access a shared, read-only copy of the data snapshot.
  */
 class MOZ_RAII MemMapSnapshot {
  public:
   Result<Ok, nsresult> Init(size_t aSize);
   Result<Ok, nsresult> Finalize(loader::AutoMemMap& aMap);
 
-  template <typename T = void>
+  template <typename T>
   RangedPtr<T> Get() {
     MOZ_ASSERT(mInitialized);
-    return mMem.get<T>();
+    return {static_cast<T*>(mMem.memory()), mMem.max_size() / sizeof(T)};
   }
 
  private:
-  Result<Ok, nsresult> Create(size_t aSize);
-  Result<Ok, nsresult> Freeze(loader::AutoMemMap& aMem);
-
-  loader::AutoMemMap mMem;
-
+  base::SharedMemory mMem;
   bool mInitialized = false;
-
-#ifdef XP_WIN
-  Maybe<FileDescriptor> mFile;
-#else
-  nsCString mPath;
-#endif
 };
 
 }  // namespace ipc
 }  // namespace mozilla
 
 #endif  // dom_ipc_MemMapSnapshot_h