Bug 1477561 - Improve handling of shared memory preference data when spawning recording processes, r=mccr8.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 24 Jul 2018 15:46:38 +0000
changeset 428255 5dc6db6742369a6b0eb017167c21d33cacb1e31b
parent 428254 171dfd07ecb4df81fdf1624ea0a67b28084d92d2
child 428256 cb0cf4cad7ce14d67831aa6a27868a40a4c8fede
push id34327
push userarchaeopteryx@coole-files.de
push dateWed, 25 Jul 2018 14:18:02 +0000
treeherdermozilla-central@fa78cd1a6880 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1477561
milestone63.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 1477561 - Improve handling of shared memory preference data when spawning recording processes, r=mccr8.
dom/ipc/ContentProcess.cpp
toolkit/recordreplay/ipc/Channel.h
toolkit/recordreplay/ipc/ChildIPC.cpp
toolkit/recordreplay/ipc/ChildIPC.h
toolkit/recordreplay/ipc/ChildProcess.cpp
toolkit/recordreplay/ipc/ParentIPC.cpp
toolkit/recordreplay/ipc/ParentIPC.h
--- a/dom/ipc/ContentProcess.cpp
+++ b/dom/ipc/ContentProcess.cpp
@@ -257,42 +257,32 @@ ContentProcess::Init(int aArgc, char* aA
       prefsLen.isNothing() ||
       prefMapHandle.isNothing() ||
       prefMapSize.isNothing() ||
       schedulerPrefs.isNothing() ||
       parentBuildID.isNothing()) {
     return false;
   }
 
-  if (recordreplay::IsRecordingOrReplaying()) {
-    // Set up early prefs from shmem contents passed to us by the middleman.
-    Preferences::DeserializePreferences(recordreplay::child::PrefsShmemContents(*prefsLen),
-                                        *prefsLen);
-  } else {
-    // Init the shared-memory base preference mapping first, so that only changed
-    // preferences wind up in heap memory.
-    Preferences::InitSnapshot(prefMapHandle.ref(), *prefMapSize);
+  // Init the shared-memory base preference mapping first, so that only changed
+  // preferences wind up in heap memory.
+  Preferences::InitSnapshot(prefMapHandle.ref(), *prefMapSize);
 
-    // Set up early prefs from the shared memory.
-    base::SharedMemory shm;
-    if (!shm.SetHandle(*prefsHandle, /* read_only */ true)) {
-      NS_ERROR("failed to open shared memory in the child");
-      return false;
-    }
-    if (!shm.Map(*prefsLen)) {
-      NS_ERROR("failed to map shared memory in the child");
-      return false;
-    }
-    Preferences::DeserializePreferences(static_cast<char*>(shm.memory()),
-                                        *prefsLen);
-    if (recordreplay::IsMiddleman()) {
-      recordreplay::parent::NotePrefsShmemContents(static_cast<char*>(shm.memory()),
-                                                   *prefsLen);
-    }
+  // Set up early prefs from the shared memory.
+  base::SharedMemory shm;
+  if (!shm.SetHandle(*prefsHandle, /* read_only */ true)) {
+    NS_ERROR("failed to open shared memory in the child");
+    return false;
   }
+  if (!shm.Map(*prefsLen)) {
+    NS_ERROR("failed to map shared memory in the child");
+    return false;
+  }
+  Preferences::DeserializePreferences(static_cast<char*>(shm.memory()),
+                                      *prefsLen);
 
   Scheduler::SetPrefs(*schedulerPrefs);
 
   if (recordreplay::IsMiddleman()) {
     recordreplay::parent::InitializeMiddleman(aArgc, aArgv, ParentPid());
   }
 
   mContent.Init(IOThreadChild::message_loop(),
--- a/toolkit/recordreplay/ipc/Channel.h
+++ b/toolkit/recordreplay/ipc/Channel.h
@@ -166,43 +166,35 @@ protected:
     void* ptr = malloc(size);
     return new(ptr) T(size, std::forward<Args>(aArgs)...);
   }
 };
 
 struct IntroductionMessage : public Message
 {
   base::ProcessId mParentPid;
-  uint32_t mPrefsLen;
   uint32_t mArgc;
 
-  IntroductionMessage(uint32_t aSize, base::ProcessId aParentPid, uint32_t aPrefsLen, uint32_t aArgc)
+  IntroductionMessage(uint32_t aSize, base::ProcessId aParentPid, uint32_t aArgc)
     : Message(MessageType::Introduction, aSize)
     , mParentPid(aParentPid)
-    , mPrefsLen(aPrefsLen)
     , mArgc(aArgc)
   {}
 
-  char* PrefsData() { return Data<IntroductionMessage, char>(); }
-  char* ArgvString() { return Data<IntroductionMessage, char>() + mPrefsLen; }
+  char* ArgvString() { return Data<IntroductionMessage, char>(); }
+  const char* ArgvString() const { return Data<IntroductionMessage, char>(); }
 
-  const char* PrefsData() const { return Data<IntroductionMessage, char>(); }
-  const char* ArgvString() const { return Data<IntroductionMessage, char>() + mPrefsLen; }
-
-  static IntroductionMessage* New(base::ProcessId aParentPid, char* aPrefs, size_t aPrefsLen,
-                                  int aArgc, char* aArgv[]) {
+  static IntroductionMessage* New(base::ProcessId aParentPid, int aArgc, char* aArgv[]) {
     size_t argsLen = 0;
     for (int i = 0; i < aArgc; i++) {
       argsLen += strlen(aArgv[i]) + 1;
     }
 
     IntroductionMessage* res =
-      NewWithData<IntroductionMessage, char>(aPrefsLen + argsLen, aParentPid, aPrefsLen, aArgc);
-
-    memcpy(res->PrefsData(), aPrefs, aPrefsLen);
+      NewWithData<IntroductionMessage, char>(argsLen, aParentPid, aArgc);
 
     size_t offset = 0;
     for (int i = 0; i < aArgc; i++) {
       memcpy(&res->ArgvString()[offset], aArgv[i], strlen(aArgv[i]) + 1);
       offset += strlen(aArgv[i]) + 1;
     }
     MOZ_RELEASE_ASSERT(offset == argsLen);
 
--- a/toolkit/recordreplay/ipc/ChildIPC.cpp
+++ b/toolkit/recordreplay/ipc/ChildIPC.cpp
@@ -45,19 +45,16 @@ Monitor* gMonitor;
 
 // The singleton channel for communicating with the middleman.
 Channel* gChannel;
 
 static base::ProcessId gMiddlemanPid;
 static base::ProcessId gParentPid;
 static StaticInfallibleVector<char*> gParentArgv;
 
-static char* gShmemPrefs;
-static size_t gShmemPrefsLen;
-
 // File descriptors used by a pipe to create checkpoints when instructed by the
 // parent process.
 static FileHandle gCheckpointWriteFd;
 static FileHandle gCheckpointReadFd;
 
 // Copy of the introduction message we got from the middleman. This is saved on
 // receipt and then processed during InitRecordingOrReplayingProcess.
 static IntroductionMessage* gIntroductionMessage;
@@ -141,23 +138,16 @@ ChannelMessageHandler(Message* aMsg)
   }
   default:
     MOZ_CRASH();
   }
 
   free(aMsg);
 }
 
-char*
-PrefsShmemContents(size_t aPrefsLen)
-{
-  MOZ_RELEASE_ASSERT(aPrefsLen == gShmemPrefsLen);
-  return gShmemPrefs;
-}
-
 // Main routine for a thread whose sole purpose is to listen to requests from
 // the middleman process to create a new checkpoint. This is separate from the
 // channel thread because this thread is recorded and the latter is not
 // recorded. By communicating between the two threads with a pipe, this
 // thread's behavior will be replicated exactly when replaying and new
 // checkpoints will be created at the same point as during recording.
 static void
 ListenForCheckpointThreadMain(void*)
@@ -243,30 +233,25 @@ InitRecordingOrReplayingProcess(int* aAr
 
   pt.reset();
 
   // We are ready to receive initialization messages from the middleman, pause
   // so they can be sent.
   HitCheckpoint(CheckpointId::Invalid, /* aRecordingEndpoint = */ false);
 
   // Process the introduction message to fill in arguments.
-  MOZ_RELEASE_ASSERT(!gShmemPrefs);
   MOZ_RELEASE_ASSERT(gParentArgv.empty());
 
   gParentPid = gIntroductionMessage->mParentPid;
 
   // Record/replay the introduction message itself so we get consistent args
-  // and prefs between recording and replaying.
+  // between recording and replaying.
   {
     IntroductionMessage* msg = IntroductionMessage::RecordReplay(*gIntroductionMessage);
 
-    gShmemPrefs = new char[msg->mPrefsLen];
-    memcpy(gShmemPrefs, msg->PrefsData(), msg->mPrefsLen);
-    gShmemPrefsLen = msg->mPrefsLen;
-
     const char* pos = msg->ArgvString();
     for (size_t i = 0; i < msg->mArgc; i++) {
       gParentArgv.append(strdup(pos));
       pos += strlen(pos) + 1;
     }
 
     free(msg);
   }
--- a/toolkit/recordreplay/ipc/ChildIPC.h
+++ b/toolkit/recordreplay/ipc/ChildIPC.h
@@ -36,19 +36,16 @@ namespace child {
 ///////////////////////////////////////////////////////////////////////////////
 // Public API
 ///////////////////////////////////////////////////////////////////////////////
 
 // Initialize replaying IPC state. This is called once during process startup,
 // and is a no-op if the process is not recording/replaying.
 void InitRecordingOrReplayingProcess(int* aArgc, char*** aArgv);
 
-// Get the contents of the prefs shmem as conveyed to the middleman process.
-char* PrefsShmemContents(size_t aPrefsLen);
-
 base::ProcessId MiddlemanProcessId();
 base::ProcessId ParentProcessId();
 
 void SetVsyncObserver(VsyncObserver* aObserver);
 void NotifyVsyncObserver();
 
 void NotifyPaint();
 void NotifyPaintStart();
--- a/toolkit/recordreplay/ipc/ChildProcess.cpp
+++ b/toolkit/recordreplay/ipc/ChildProcess.cpp
@@ -459,16 +459,20 @@ ChildProcessInfo::LaunchSubprocess()
 
   if (IsRecording()) {
     std::vector<std::string> extraArgs;
     GetArgumentsForChildProcess(base::GetCurrentProcId(), channelId,
                                 gRecordingFilename, /* aRecording = */ true, extraArgs);
 
     MOZ_RELEASE_ASSERT(!gRecordingProcess);
     gRecordingProcess = new ipc::GeckoChildProcessHost(GeckoProcessType_Content);
+
+    gRecordingProcess->AddFdToRemap(kPrefsFileDescriptor, kPrefsFileDescriptor);
+    gRecordingProcess->AddFdToRemap(kPrefMapFileDescriptor, kPrefMapFileDescriptor);
+
     if (!gRecordingProcess->LaunchAndWaitForProcessHandle(extraArgs)) {
       MOZ_CRASH("ChildProcessInfo::LaunchSubprocess");
     }
   } else {
     dom::ContentChild::GetSingleton()->SendCreateReplayingProcess(channelId);
   }
 
   mLastMessageTime = TimeStamp::Now();
--- a/toolkit/recordreplay/ipc/ParentIPC.cpp
+++ b/toolkit/recordreplay/ipc/ParentIPC.cpp
@@ -824,38 +824,24 @@ ActiveChildIsPausedOrRewinding()
 static MessageLoop* gMainThreadMessageLoop;
 
 MessageLoop*
 MainThreadMessageLoop()
 {
   return gMainThreadMessageLoop;
 }
 
-// Contents of the prefs shmem block that is sent to the child on startup.
-static char* gShmemPrefs;
-static size_t gShmemPrefsLen;
-
-void
-NotePrefsShmemContents(char* aPrefs, size_t aPrefsLen)
-{
-  MOZ_RELEASE_ASSERT(!gShmemPrefs);
-  gShmemPrefs = new char[aPrefsLen];
-  memcpy(gShmemPrefs, aPrefs, aPrefsLen);
-  gShmemPrefsLen = aPrefsLen;
-}
-
 void
 InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
-  MOZ_RELEASE_ASSERT(gShmemPrefs);
 
   // Construct the message that will be sent to each child when starting up.
   IntroductionMessage* msg =
-    IntroductionMessage::New(aParentPid, gShmemPrefs, gShmemPrefsLen, aArgc, aArgv);
+    IntroductionMessage::New(aParentPid, aArgc, aArgv);
   ChildProcessInfo::SetIntroductionMessage(msg);
 
   MOZ_RELEASE_ASSERT(gProcessKind == ProcessKind::MiddlemanRecording ||
                      gProcessKind == ProcessKind::MiddlemanReplaying);
 
   InitializeGraphicsMemory();
 
   gMonitor = new Monitor();
--- a/toolkit/recordreplay/ipc/ParentIPC.h
+++ b/toolkit/recordreplay/ipc/ParentIPC.h
@@ -40,19 +40,16 @@ const char* SaveAllRecordingsDirectory()
 void SaveRecording(const ipc::FileDescriptor& aFile);
 
 // Get the message channel used to communicate with the UI process.
 ipc::MessageChannel* ChannelToUIProcess();
 
 // Initialize state in a middleman process.
 void InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid);
 
-// Note the contents of the prefs shmem for use by the child process.
-void NotePrefsShmemContents(char* aPrefs, size_t aPrefsLen);
-
 // Open a socket which a recording/replaying child can use to connect to its
 // middleman process.
 void OpenChannel(base::ProcessId aMiddlemanPid, uint32_t aChannelId,
                  ipc::FileDescriptor* aConnection);
 
 // Get the command line arguments to use when spawning a recording or replaying
 // child process.
 void GetArgumentsForChildProcess(base::ProcessId aMiddlemanPid, uint32_t aChannelId,