Backed out changeset 2bdd2d042847 (bug 972577) for non-unified bustage on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Fri, 14 Mar 2014 15:27:21 -0700
changeset 190907 401e4ec82734b6dc22748c897a6ac2d9015161b0
parent 190906 46d18be48bc4210e60eb4f64224768650cb66382
child 190908 c8641d02a06d1b7edf25e044447d772820b9870c
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs972577
milestone30.0a1
backs out2bdd2d04284726d02c0c641560261770c58d9cfb
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
Backed out changeset 2bdd2d042847 (bug 972577) for non-unified bustage on a CLOSED TREE
storage/src/TelemetryVFS.cpp
toolkit/components/telemetry/Telemetry.cpp
toolkit/xre/moz.build
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsWindowsDllInterceptor.h
tools/profiler/IOInterposer.cpp
tools/profiler/IOInterposer.h
tools/profiler/NSPRInterposer.cpp
tools/profiler/NSPRInterposer.h
tools/profiler/ProfilerIOInterposeObserver.cpp
tools/profiler/moz.build
tools/profiler/platform.cpp
widget/windows/winrt/MetroApp.cpp
xpcom/build/IOInterposer.cpp
xpcom/build/IOInterposer.h
xpcom/build/NSPRInterposer.cpp
xpcom/build/NSPRInterposer.h
xpcom/build/moz.build
xpcom/build/nsWindowsDllInterceptor.h
xpcom/build/nsXPComInit.cpp
--- a/storage/src/TelemetryVFS.cpp
+++ b/storage/src/TelemetryVFS.cpp
@@ -102,31 +102,28 @@ public:
   ~IOThreadAutoTimer()
   {
     TimeStamp end(TimeStamp::Now());
     uint32_t mainThread = NS_IsMainThread() ? 1 : 0;
     if (id != Telemetry::HistogramCount) {
       Telemetry::AccumulateTimeDelta(static_cast<Telemetry::ID>(id + mainThread),
                                      start, end);
     }
-    // We don't report SQLite I/O on Windows because we have a comprehensive
-    // mechanism for intercepting I/O on that platform that captures a superset
-    // of the data captured here.
-#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN)
+#ifdef MOZ_ENABLE_PROFILER_SPS
     if (IOInterposer::IsObservedOperation(op)) {
       const char* main_ref  = "sqlite-mainthread";
       const char* other_ref = "sqlite-otherthread";
 
       // Create observation
       IOInterposeObserver::Observation ob(op, start, end,
                                           (mainThread ? main_ref : other_ref));
       // Report observation
       IOInterposer::Report(ob);
     }
-#endif /* defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) */
+#endif /* MOZ_ENABLE_PROFILER_SPS */
   }
 
 private:
   const TimeStamp start;
   const Telemetry::ID id;
   IOInterposeObserver::Operation op;
 };
 
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -381,17 +381,17 @@ void TelemetryIOInterposeObserver::AddPa
                                            const nsAString& aSubstName)
 {
   mSafeDirs.AppendElement(SafeDir(aPath, aSubstName));
 }
  
 void TelemetryIOInterposeObserver::Observe(Observation& aOb)
 {
   // We only report main-thread I/O
-  if (!IsMainThread()) {
+  if (!NS_IsMainThread()) {
     return;
   }
 
   // Get the filename
   const char16_t* filename = aOb.Filename();
  
   // Discard observations without filename
   if (!filename) {
@@ -2963,16 +2963,20 @@ WriteFailedProfileLock(nsIFile* aProfile
 void
 InitIOReporting(nsIFile* aXreDir)
 {
   // Never initialize twice
   if (sTelemetryIOObserver) {
     return;
   }
 
+  // Initialize IO interposing
+  IOInterposer::Init();
+  InitPoisonIOInterposer();
+ 
   sTelemetryIOObserver = new TelemetryIOInterposeObserver(aXreDir);
   IOInterposer::Register(IOInterposeObserver::OpAll, sTelemetryIOObserver);
 }
 
 void
 SetProfileDir(nsIFile* aProfD)
 {
   if (!sTelemetryIOObserver || !aProfD) {
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -19,16 +19,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
     ]
 
 XPIDL_MODULE = 'xulapp'
 
 if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
     EXPORTS += ['EventTracer.h']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    EXPORTS += ['nsWindowsDllInterceptor.h']
     UNIFIED_SOURCES += [
         'nsNativeAppSupportWin.cpp',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     EXPORTS += ['MacQuirks.h']
     UNIFIED_SOURCES += [
         'nsCommandLineServiceMac.cpp',
     ]
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -9,17 +9,16 @@
 #include "nsQAppInstance.h"
 #endif // MOZ_WIDGET_QT
 
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
-#include "mozilla/IOInterposer.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Poison.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsAppRunner.h"
 #include "mozilla/AppData.h"
 #include "nsUpdateDriver.h"
@@ -4021,18 +4020,16 @@ XREMain::XRE_mainRun()
  */
 int
 XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
 {
   char aLocal;
   GeckoProfilerInitRAII profilerGuard(&aLocal);
   PROFILER_LABEL("Startup", "XRE_Main");
 
-  mozilla::IOInterposerInit ioInterposerGuard;
-
   nsresult rv = NS_OK;
 
   gArgc = argc;
   gArgv = argv;
 
   NS_ENSURE_TRUE(aAppData, 2);
 
   mAppData = new ScopedAppData(aAppData);
@@ -4226,18 +4223,16 @@ public:
 
 int
 XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
 {
   char aLocal;
   GeckoProfilerInitRAII profilerGuard(&aLocal);
   PROFILER_LABEL("Startup", "XRE_Main");
 
-  mozilla::IOInterposerInit ioInterposerGuard;
-
   nsresult rv = NS_OK;
 
   xreMainPtr = new XREMain();
   if (!xreMainPtr) {
     return 1;
   }
 
   // Inits Winrt and COM underneath it.
rename from xpcom/build/nsWindowsDllInterceptor.h
rename to toolkit/xre/nsWindowsDllInterceptor.h
rename from xpcom/build/IOInterposer.cpp
rename to tools/profiler/IOInterposer.cpp
--- a/xpcom/build/IOInterposer.cpp
+++ b/tools/profiler/IOInterposer.cpp
@@ -4,22 +4,16 @@
 
 #include <algorithm>
 #include <vector>
 
 #include "IOInterposer.h"
 
 #include "mozilla/Mutex.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/ThreadLocal.h"
-#if !defined(XP_WIN)
-#include "NSPRInterposer.h"
-#endif // !defined(XP_WIN)
-#include "nsXULAppAPI.h"
-#include "PoisonIOInterposer.h"
 
 using namespace mozilla;
 
 namespace {
 
 /** Lists of Observers */
 struct ObserverLists {
   ObserverLists()
@@ -71,17 +65,16 @@ public:
   ~AutoPRLock()
   {
     PR_Unlock(mLock);
   }
 };
 
 // List of observers registered
 static StaticAutoPtr<ObserverLists> sObserverLists;
-static ThreadLocal<bool> sIsMainThread;
 
 /** Find if a vector contains a specific element */
 template<class T>
 bool VectorContains(const std::vector<T>& vector, const T& element)
 {
   return std::find(vector.begin(), vector.end(), element) != vector.end();
 }
 
@@ -137,40 +130,16 @@ IOInterposeObserver::Operation IOInterpo
 /* static */ void IOInterposer::Init()
 {
   // Don't initialize twice...
   if (sObserverLists) {
     return;
   }
   sObserverLists = new ObserverLists();
   sObservedOperations = IOInterposeObserver::OpNone;
-  if (sIsMainThread.init()) {
-#if defined(XP_WIN)
-    bool isMainThread = XRE_GetWindowsEnvironment() !=
-                          WindowsEnvironmentType_Metro;
-#else
-    bool isMainThread = true;
-#endif
-    sIsMainThread.set(isMainThread);
-  }
-  // Now we initialize the various interposers depending on platform
-#if defined(XP_WIN) || defined(XP_MACOSX)
-  InitPoisonIOInterposer();
-#endif
-  // We don't hook NSPR on Windows because PoisonIOInterposer captures a
-  // superset of the former's events.
-#if !defined(XP_WIN)
-  InitNSPRIOInterposing();
-#endif
-}
-
-/* static */ bool
-IOInterposeObserver::IsMainThread()
-{
-  return sIsMainThread.initialized() && sIsMainThread.get();
 }
 
 /* static */ void IOInterposer::Clear()
 {
   // Clear() shouldn't be called if Init() wasn't called,
   MOZ_ASSERT(sObserverLists);
   if (sObserverLists) {
     // We require everybody unregister before clearing. If somebody didn't then
@@ -252,16 +221,18 @@ IOInterposeObserver::IsMainThread()
   for (uint32_t i = 0; i < nObservers; ++i) {
     (*observers)[i]->Observe(aObservation);
   }
 }
 
 /* static */ void IOInterposer::Register(IOInterposeObserver::Operation aOp,
                                          IOInterposeObserver* aObserver)
 {
+  // IOInterposer::Init most be called before this method
+  MOZ_ASSERT(sObserverLists);
   // We should never register nullptr as observer
   MOZ_ASSERT(aObserver);
   if (!sObserverLists || !aObserver) {
     return;
   }
 
   AutoPRLock listLock(sObserverLists->mObserverListsLock);
 
@@ -296,16 +267,18 @@ IOInterposeObserver::IsMainThread()
   // observer is observing.
   sObservedOperations = (IOInterposeObserver::Operation)
                         (sObservedOperations | aOp);
 }
 
 /* static */ void IOInterposer::Unregister(IOInterposeObserver::Operation aOp,
                                            IOInterposeObserver* aObserver)
 {
+  // IOInterposer::Init most be called before this method.
+  MOZ_ASSERT(sObserverLists);
   if (!sObserverLists) {
     return;
   }
 
   AutoPRLock listLock(sObserverLists->mObserverListsLock);
 
   if (aOp & IOInterposeObserver::OpCreateOrOpen) {
     VectorRemove(sObserverLists->mCreateObservers, aObserver);
@@ -346,23 +319,8 @@ IOInterposeObserver::IsMainThread()
   if (aOp & IOInterposeObserver::OpClose) {
     VectorRemove(sObserverLists->mCloseObservers, aObserver);
     if (sObserverLists->mCloseObservers.empty()) {
       sObservedOperations = (IOInterposeObserver::Operation)
                        (sObservedOperations & ~IOInterposeObserver::OpClose);
     }
   }
 }
-
-/* static */ void
-IOInterposer::RegisterCurrentThread(bool aIsMainThread)
-{
-  // Right now this is a no-op unless we're running on Metro.
-  // More cross-platform stuff will be added in the near future, stay tuned!
-#if defined(XP_WIN)
-  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro ||
-      !sIsMainThread.initialized()) {
-    return;
-  }
-  sIsMainThread.set(aIsMainThread);
-#endif
-}
-
rename from xpcom/build/IOInterposer.h
rename to tools/profiler/IOInterposer.h
--- a/xpcom/build/IOInterposer.h
+++ b/tools/profiler/IOInterposer.h
@@ -131,24 +131,16 @@ public:
    *
    * Remark: Observations may occur on any thread.
    */
   virtual void Observe(Observation& aObservation) = 0;
 
   virtual ~IOInterposeObserver()
   {
   }
-
-protected:
-  /**
-   * We don't use NS_IsMainThread() because we need to be able to determine the
-   * main thread outside of XPCOM Initialization. IOInterposer observers should
-   * call this function instead.
-   */
-  static bool IsMainThread();
 };
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 
 /**
  * Class offering the public static IOInterposer API.
  *
  * This class is responsible for ensuring that events are routed to the
@@ -241,29 +233,20 @@ public:
                        IOInterposeObserver* aObserver);
 
   /**
    * Unregister an IOInterposeObserver for a given operation
    * Remark: It is always safe to unregister for all operations, even if yoú
    * didn't register for them all.
    * I.e. IOInterposer::Unregister(IOInterposeObserver::OpAll, aObserver)
    *
-   * Remark: Init() must be called before observers are unregistered.
+   * Remark: Init() must be called before observers are unregistered
    */
   static void Unregister(IOInterposeObserver::Operation aOp,
                          IOInterposeObserver* aObserver);
-
-  /**
-   * Registers the current thread with the IOInterposer.
-   *
-   * @param aIsMainThread true if IOInterposer should treat the current thread
-   *                      as the main thread.
-   */
-  static void
-  RegisterCurrentThread(bool aIsMainThread = false);
 };
 
 #else /* MOZ_ENABLE_PROFILER_SPS */
 
 class IOInterposer MOZ_FINAL
 {
   IOInterposer();
 public:
@@ -272,28 +255,15 @@ public:
   static inline void Report(IOInterposeObserver::Observation& aOb)        {}
   static inline void Register(IOInterposeObserver::Operation aOp,
                               IOInterposeObserver* aObserver)             {}
   static inline void Unregister(IOInterposeObserver::Operation aOp,
                                 IOInterposeObserver* aObserver)           {}
   static inline bool IsObservedOperation(IOInterposeObserver::Operation aOp) {
     return false;
   }
-  static inline void RegisterCurrentThread(bool)                          {}
 };
 
 #endif /* MOZ_ENABLE_PROFILER_SPS */
 
-class IOInterposerInit
-{
-public:
-  IOInterposerInit()
-  {
-    IOInterposer::Init();
-  }
-
-  // No destructor needed at the moment -- this stuff stays active for the
-  // life of the process. This may change in the future.
-};
-
 } // namespace mozilla
 
 #endif // mozilla_IOInterposer_h
rename from xpcom/build/NSPRInterposer.cpp
rename to tools/profiler/NSPRInterposer.cpp
rename from xpcom/build/NSPRInterposer.h
rename to tools/profiler/NSPRInterposer.h
--- a/tools/profiler/ProfilerIOInterposeObserver.cpp
+++ b/tools/profiler/ProfilerIOInterposeObserver.cpp
@@ -5,20 +5,16 @@
 #include "GeckoProfiler.h"
 #include "ProfilerIOInterposeObserver.h"
 #include "ProfilerMarkers.h"
 
 using namespace mozilla;
 
 void ProfilerIOInterposeObserver::Observe(Observation& aObservation)
 {
-  if (!IsMainThread()) {
-    return;
-  }
-
   const char* str = nullptr;
 
   switch (aObservation.ObservedOperation()) {
     case IOInterposeObserver::OpCreateOrOpen:
       str = "create/open";
       break;
     case IOInterposeObserver::OpRead:
       str = "read";
--- a/tools/profiler/moz.build
+++ b/tools/profiler/moz.build
@@ -19,18 +19,20 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
         'PseudoStack.h',
         'shared-libraries.h',
     ]
     EXTRA_JS_MODULES = [
         'Profiler.jsm',
     ]
     UNIFIED_SOURCES += [
         'BreakpadSampler.cpp',
+        'IOInterposer.cpp',
         'JSCustomObjectBuilder.cpp',
         'JSObjectBuilder.cpp',
+        'NSPRInterposer.cpp',
         'nsProfiler.cpp',
         'nsProfilerFactory.cpp',
         'platform.cpp',
         'ProfileEntry.cpp',
         'ProfilerBacktrace.cpp',
         'ProfilerIOInterposeObserver.cpp',
         'ProfilerMarkers.cpp',
         'SaveProfileTask.cpp',
@@ -83,9 +85,13 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
         DEFINES['ARCH_ARMV6'] = True
 
     FINAL_LIBRARY = 'xul'
 
 EXPORTS += [
     'GeckoProfiler.h',
 ]
 
+EXPORTS.mozilla += [
+    'IOInterposer.h',
+]
+
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -2,16 +2,18 @@
  * 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 <ostream>
 #include <fstream>
 #include <sstream>
 #include <errno.h>
 
+#include "IOInterposer.h"
+#include "NSPRInterposer.h"
 #include "ProfilerIOInterposeObserver.h"
 #include "platform.h"
 #include "PlatformMacros.h"
 #include "prenv.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ThreadLocal.h"
 #include "PseudoStack.h"
 #include "TableTicker.h"
@@ -474,16 +476,21 @@ void mozilla_sampler_init(void* stackTop
   // Read mode settings from MOZ_PROFILER_MODE and interval
   // settings from MOZ_PROFILER_INTERVAL and stack-scan threshhold
   // from MOZ_PROFILER_STACK_SCAN.
   read_profiler_env_vars();
 
   // platform specific initialization
   OS::Startup();
 
+  // Initialize I/O interposing
+  mozilla::IOInterposer::Init();
+  // Initialize NSPR I/O Interposing
+  mozilla::InitNSPRIOInterposing();
+
   // We can't open pref so we use an environment variable
   // to know if we should trigger the profiler on startup
   // NOTE: Default
   const char *val = PR_GetEnv("MOZ_PROFILER_STARTUP");
   if (!val || !*val) {
     return;
   }
 
@@ -521,16 +528,26 @@ void mozilla_sampler_shutdown()
         t->ToStreamAsJSON(stream);
         stream.close();
       }
     }
   }
 
   profiler_stop();
 
+  // Unregister IO interpose observer
+  mozilla::IOInterposer::Unregister(mozilla::IOInterposeObserver::OpAll,
+                                    sInterposeObserver);
+  // mozilla_sampler_shutdown is only called at shutdown, and late-write checks
+  // might need the IO interposer, so we don't clear it. Don't worry it's
+  // designed not to report leaks.
+  // mozilla::IOInterposer::Clear();
+  mozilla::ClearNSPRIOInterposing();
+  sInterposeObserver = nullptr;
+
   Sampler::Shutdown();
 
   // We can't delete the Stack because we can be between a
   // sampler call_enter/call_exit point.
   // TODO Need to find a safe time to delete Stack
 }
 
 void mozilla_sampler_save()
@@ -719,17 +736,16 @@ void mozilla_sampler_stop()
   }
 
   if (unwinderThreader) {
     uwt__deinit();
   }
 
   mozilla::IOInterposer::Unregister(mozilla::IOInterposeObserver::OpAll,
                                     sInterposeObserver);
-  sInterposeObserver = nullptr;
 
   sIsProfiling = false;
 
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os)
     os->NotifyObservers(nullptr, "profiler-stopped", nullptr);
 }
 
--- a/widget/windows/winrt/MetroApp.cpp
+++ b/widget/windows/winrt/MetroApp.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 "MetroApp.h"
 #include "MetroWidget.h"
-#include "mozilla/IOInterposer.h"
 #include "mozilla/widget/AudioSession.h"
 #include "nsIRunnable.h"
 #include "MetroUtils.h"
 #include "MetroAppShell.h"
 #include "nsICommandLineRunner.h"
 #include "FrameworkView.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "GeckoProfiler.h"
@@ -72,21 +71,20 @@ MetroApp::CreateView(ABI::Windows::Appli
 // MetroApp impl.
 
 void
 MetroApp::Run()
 {
   LogThread();
 
   // Name this thread for debugging and register it with the profiler
-  // and IOInterposer as the main gecko thread.
+  // as the main gecko thread.
   char aLocal;
   PR_SetCurrentThreadName(gGeckoThreadName);
   profiler_register_thread(gGeckoThreadName, &aLocal);
-  IOInterposer::RegisterCurrentThread(true);
 
   HRESULT hr;
   hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>(
     this, &MetroApp::OnSuspending).Get(), &mSuspendEvent);
   AssertHRESULT(hr);
 
   hr = sCoreApp->add_Resuming(Callback<__FIEventHandler_1_IInspectable_t>(
     this, &MetroApp::OnResuming).Get(), &mResumeEvent);
--- a/xpcom/build/moz.build
+++ b/xpcom/build/moz.build
@@ -10,27 +10,25 @@ EXPORTS += [
     'nsXPCOMCIDInternal.h',
     'nsXREAppData.h',
     'nsXULAppAPI.h',
     'xrecore.h',
 ]
 
 EXPORTS.mozilla += [
     'FileLocation.h',
-    'IOInterposer.h',
     'LateWriteChecks.h',
     'Omnijar.h',
     'PoisonIOInterposer.h',
     'ServiceList.h',
     'Services.h',
     'XPCOM.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
-    EXPORTS += ['nsWindowsDllInterceptor.h']
     EXPORTS.mozilla += ['perfprobe.h']
     SOURCES += ['perfprobe.cpp']
     if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
         SOURCES += [
             'PoisonIOInterposerBase.cpp',
             'PoisonIOInterposerWin.cpp',
         ]
     else:
@@ -52,25 +50,16 @@ UNIFIED_SOURCES += xpcom_glue_src_cppsrc
 UNIFIED_SOURCES += [
     'FrozenFunctions.cpp',
     'LateWriteChecks.cpp',
     'nsXPComInit.cpp',
     'nsXPCOMStrings.cpp',
     'Services.cpp',
 ]
 
-if CONFIG['MOZ_ENABLE_PROFILER_SPS']:
-    SOURCES += [
-        'IOInterposer.cpp',
-    ]
-    if CONFIG['OS_ARCH'] != 'WINNT':
-      SOURCES += [
-          'NSPRInterposer.cpp',
-      ]
-
 # FileLocation.cpp and Omnijar.cpp cannot be built in unified mode because they
 # use plarena.h.
 SOURCES += [
     'FileLocation.cpp',
     'Omnijar.cpp',
 ]
 
 MSVC_ENABLE_PGO = True
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -105,16 +105,18 @@ extern nsresult nsStringInputStreamConst
 #include "mozilla/Services.h"
 #include "mozilla/Omnijar.h"
 #include "mozilla/HangMonitor.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/BackgroundHangMonitor.h"
 
 #include "nsChromeRegistry.h"
 #include "nsChromeProtocolHandler.h"
+#include "mozilla/IOInterposer.h"
+#include "mozilla/PoisonIOInterposer.h"
 #include "mozilla/LateWriteChecks.h"
 
 #include "mozilla/scache/StartupCache.h"
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop.h"
 
@@ -962,16 +964,21 @@ ShutdownXPCOM(nsIServiceManager* servMgr
         moduleLoaders = nullptr;
     }
 
     nsCycleCollector_shutdown();
 
     PROFILER_MARKER("Shutdown xpcom");
     // If we are doing any shutdown checks, poison writes.
     if (gShutdownChecks != SCM_NOTHING) {
+        // Calling InitIOInterposer or InitPoisonIOInterposer twice doesn't
+        // cause any problems, they'll safely abort the initialization on their
+        // own initiative.
+        mozilla::IOInterposer::Init();
+        mozilla::InitPoisonIOInterposer();
 #ifdef XP_MACOSX
         mozilla::OnlyReportDirtyWrites();
 #endif /* XP_MACOSX */
         mozilla::BeginLateWriteChecks();
     }
 
     // Shutdown nsLocalFile string conversion
     NS_ShutdownLocalFile();