diff --git a/storage/src/TelemetryVFS.cpp b/storage/src/TelemetryVFS.cpp index 423788c90526..bcb4fd9fd025 100644 --- a/storage/src/TelemetryVFS.cpp +++ b/storage/src/TelemetryVFS.cpp @@ -107,7 +107,10 @@ public: Telemetry::AccumulateTimeDelta(static_cast(id + mainThread), start, end); } -#ifdef MOZ_ENABLE_PROFILER_SPS + // 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) if (IOInterposer::IsObservedOperation(op)) { const char* main_ref = "sqlite-mainthread"; const char* other_ref = "sqlite-otherthread"; @@ -118,7 +121,7 @@ public: // Report observation IOInterposer::Report(ob); } -#endif /* MOZ_ENABLE_PROFILER_SPS */ +#endif /* defined(MOZ_ENABLE_PROFILER_SPS) && !defined(XP_WIN) */ } private: diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index c446ad57973c..a90a42aeff70 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -386,7 +386,7 @@ void TelemetryIOInterposeObserver::AddPath(const nsAString& aPath, void TelemetryIOInterposeObserver::Observe(Observation& aOb) { // We only report main-thread I/O - if (!NS_IsMainThread()) { + if (!IsMainThread()) { return; } @@ -2968,10 +2968,6 @@ InitIOReporting(nsIFile* aXreDir) return; } - // Initialize IO interposing - IOInterposer::Init(); - InitPoisonIOInterposer(); - sTelemetryIOObserver = new TelemetryIOInterposeObserver(aXreDir); IOInterposer::Register(IOInterposeObserver::OpAll, sTelemetryIOObserver); } diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index 347146296a9a..a13a9ef3bfc1 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -24,7 +24,6 @@ if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']: EXPORTS += ['EventTracer.h'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - EXPORTS += ['nsWindowsDllInterceptor.h'] UNIFIED_SOURCES += [ 'nsNativeAppSupportWin.cpp', ] diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 66bd32d757cc..b81ff321da63 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -14,6 +14,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Attributes.h" +#include "mozilla/IOInterposer.h" #include "mozilla/Likely.h" #include "mozilla/Poison.h" #include "mozilla/Preferences.h" @@ -4025,6 +4026,8 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) GeckoProfilerInitRAII profilerGuard(&aLocal); PROFILER_LABEL("Startup", "XRE_Main"); + mozilla::IOInterposerInit ioInterposerGuard; + nsresult rv = NS_OK; gArgc = argc; @@ -4228,6 +4231,8 @@ XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData) GeckoProfilerInitRAII profilerGuard(&aLocal); PROFILER_LABEL("Startup", "XRE_Main"); + mozilla::IOInterposerInit ioInterposerGuard; + nsresult rv = NS_OK; xreMainPtr = new XREMain(); diff --git a/tools/profiler/ProfilerIOInterposeObserver.cpp b/tools/profiler/ProfilerIOInterposeObserver.cpp index 73788fc2a3ea..757189c7f159 100644 --- a/tools/profiler/ProfilerIOInterposeObserver.cpp +++ b/tools/profiler/ProfilerIOInterposeObserver.cpp @@ -10,6 +10,10 @@ using namespace mozilla; void ProfilerIOInterposeObserver::Observe(Observation& aObservation) { + if (!IsMainThread()) { + return; + } + const char* str = nullptr; switch (aObservation.ObservedOperation()) { diff --git a/tools/profiler/moz.build b/tools/profiler/moz.build index ff009ecb2ebb..4710841e7be9 100644 --- a/tools/profiler/moz.build +++ b/tools/profiler/moz.build @@ -24,10 +24,8 @@ if CONFIG['MOZ_ENABLE_PROFILER_SPS']: ] UNIFIED_SOURCES += [ 'BreakpadSampler.cpp', - 'IOInterposer.cpp', 'JSCustomObjectBuilder.cpp', 'JSObjectBuilder.cpp', - 'NSPRInterposer.cpp', 'nsProfiler.cpp', 'nsProfilerFactory.cpp', 'platform.cpp', @@ -90,8 +88,4 @@ EXPORTS += [ 'GeckoProfiler.h', ] -EXPORTS.mozilla += [ - 'IOInterposer.h', -] - XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini'] diff --git a/tools/profiler/platform.cpp b/tools/profiler/platform.cpp index cb339ac63d2f..8a4f29e85631 100644 --- a/tools/profiler/platform.cpp +++ b/tools/profiler/platform.cpp @@ -7,8 +7,6 @@ #include #include -#include "IOInterposer.h" -#include "NSPRInterposer.h" #include "ProfilerIOInterposeObserver.h" #include "platform.h" #include "PlatformMacros.h" @@ -481,11 +479,6 @@ void mozilla_sampler_init(void* stackTop) // 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 @@ -533,16 +526,6 @@ void mozilla_sampler_shutdown() 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 @@ -741,6 +724,7 @@ void mozilla_sampler_stop() mozilla::IOInterposer::Unregister(mozilla::IOInterposeObserver::OpAll, sInterposeObserver); + sInterposeObserver = nullptr; sIsProfiling = false; diff --git a/widget/windows/winrt/MetroApp.cpp b/widget/windows/winrt/MetroApp.cpp index f41f2f9b1d0a..8b2c0442c7e1 100644 --- a/widget/windows/winrt/MetroApp.cpp +++ b/widget/windows/winrt/MetroApp.cpp @@ -5,6 +5,7 @@ #include "MetroApp.h" #include "MetroWidget.h" +#include "mozilla/IOInterposer.h" #include "mozilla/widget/AudioSession.h" #include "nsIRunnable.h" #include "MetroUtils.h" @@ -76,10 +77,11 @@ MetroApp::Run() LogThread(); // Name this thread for debugging and register it with the profiler - // as the main gecko thread. + // and IOInterposer 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>( diff --git a/tools/profiler/IOInterposer.cpp b/xpcom/build/IOInterposer.cpp similarity index 89% rename from tools/profiler/IOInterposer.cpp rename to xpcom/build/IOInterposer.cpp index 9f6ed9cd2e56..b825987a1048 100644 --- a/tools/profiler/IOInterposer.cpp +++ b/xpcom/build/IOInterposer.cpp @@ -9,6 +9,12 @@ #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; @@ -70,6 +76,7 @@ public: // List of observers registered static StaticAutoPtr sObserverLists; +static ThreadLocal sIsMainThread; /** Find if a vector contains a specific element */ template @@ -135,6 +142,30 @@ IOInterposeObserver::Operation IOInterposer::sObservedOperations = } 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() @@ -226,8 +257,6 @@ IOInterposeObserver::Operation IOInterposer::sObservedOperations = /* 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) { @@ -272,8 +301,6 @@ IOInterposeObserver::Operation IOInterposer::sObservedOperations = /* static */ void IOInterposer::Unregister(IOInterposeObserver::Operation aOp, IOInterposeObserver* aObserver) { - // IOInterposer::Init most be called before this method. - MOZ_ASSERT(sObserverLists); if (!sObserverLists) { return; } @@ -324,3 +351,18 @@ IOInterposeObserver::Operation IOInterposer::sObservedOperations = } } } + +/* 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 +} + diff --git a/tools/profiler/IOInterposer.h b/xpcom/build/IOInterposer.h similarity index 91% rename from tools/profiler/IOInterposer.h rename to xpcom/build/IOInterposer.h index 10ac05c6a009..e80ddc9a810a 100644 --- a/tools/profiler/IOInterposer.h +++ b/xpcom/build/IOInterposer.h @@ -136,6 +136,14 @@ public: 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 @@ -238,10 +246,19 @@ public: * 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 */ @@ -260,10 +277,23 @@ public: 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 diff --git a/tools/profiler/NSPRInterposer.cpp b/xpcom/build/NSPRInterposer.cpp similarity index 100% rename from tools/profiler/NSPRInterposer.cpp rename to xpcom/build/NSPRInterposer.cpp diff --git a/tools/profiler/NSPRInterposer.h b/xpcom/build/NSPRInterposer.h similarity index 100% rename from tools/profiler/NSPRInterposer.h rename to xpcom/build/NSPRInterposer.h diff --git a/xpcom/build/moz.build b/xpcom/build/moz.build index 3887e908eac7..d8738f79270c 100644 --- a/xpcom/build/moz.build +++ b/xpcom/build/moz.build @@ -15,6 +15,7 @@ EXPORTS += [ EXPORTS.mozilla += [ 'FileLocation.h', + 'IOInterposer.h', 'LateWriteChecks.h', 'Omnijar.h', 'PoisonIOInterposer.h', @@ -24,6 +25,7 @@ EXPORTS.mozilla += [ ] if CONFIG['OS_ARCH'] == 'WINNT': + EXPORTS += ['nsWindowsDllInterceptor.h'] EXPORTS.mozilla += ['perfprobe.h'] SOURCES += ['perfprobe.cpp'] if CONFIG['MOZ_ENABLE_PROFILER_SPS']: @@ -55,6 +57,15 @@ UNIFIED_SOURCES += [ '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 += [ diff --git a/toolkit/xre/nsWindowsDllInterceptor.h b/xpcom/build/nsWindowsDllInterceptor.h similarity index 100% rename from toolkit/xre/nsWindowsDllInterceptor.h rename to xpcom/build/nsWindowsDllInterceptor.h diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 2e7aecbd67dc..9b257f1ab837 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -110,8 +110,6 @@ extern nsresult nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **) #include "nsChromeRegistry.h" #include "nsChromeProtocolHandler.h" -#include "mozilla/IOInterposer.h" -#include "mozilla/PoisonIOInterposer.h" #include "mozilla/LateWriteChecks.h" #include "mozilla/scache/StartupCache.h" @@ -969,11 +967,6 @@ ShutdownXPCOM(nsIServiceManager* servMgr) 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 */