Bug 917491: Guarantee cleanup of AsyncLatencyLogger on xpcom-shutdown r=bsmedberg
authorRandell Jesup <rjesup@jesup.org>
Tue, 24 Sep 2013 22:10:24 -0400
changeset 148612 2ebbcdeeab08a40ef1475ac18a8dea44790bcd6c
parent 148611 eef35ea0291bbb0852af83aa52e88457c25887db
child 148613 072594314b133232aad433abf8744ab379efb496
push id25349
push userryanvm@gmail.com
push dateWed, 25 Sep 2013 18:52:12 +0000
treeherdermozilla-central@39f30376058c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs917491
milestone27.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 917491: Guarantee cleanup of AsyncLatencyLogger on xpcom-shutdown r=bsmedberg
content/media/AudioStream.cpp
content/media/AudioStream.h
content/media/Latency.cpp
content/media/Latency.h
content/media/MediaStreamGraph.cpp
content/media/MediaStreamGraphImpl.h
layout/build/nsLayoutStatics.cpp
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -900,18 +900,18 @@ BufferedAudioStream::DataCallback(void* 
   }
 
   WriteDumpFile(mDumpFile, this, aFrames, aBuffer);
   if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
     uint32_t latency = UINT32_MAX;
     if (cubeb_stream_get_latency(mCubebStream, &latency)) {
       NS_WARNING("Could not get latency from cubeb.");
     }
-    LogLatency(AsyncLatencyLogger::AudioStream, 0, (mBuffer.Length() * 1000) / mOutRate);
-    LogLatency(AsyncLatencyLogger::Cubeb, 0, (latency * 1000) / mOutRate);
+    mLatencyLog->Log(AsyncLatencyLogger::AudioStream, 0, (mBuffer.Length() * 1000) / mOutRate);
+    mLatencyLog->Log(AsyncLatencyLogger::Cubeb, 0, (latency * 1000) / mOutRate);
   }
 
   mAudioClock.UpdateWritePosition(servicedFrames);
   return servicedFrames;
 }
 
 void
 BufferedAudioStream::StateCallback(cubeb_state aState)
--- a/content/media/AudioStream.h
+++ b/content/media/AudioStream.h
@@ -4,16 +4,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/. */
 #if !defined(AudioStream_h_)
 #define AudioStream_h_
 
 #include "AudioSampleFormat.h"
 #include "AudioChannelCommon.h"
 #include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "Latency.h"
 
 namespace soundtouch {
 class SoundTouch;
 }
 
 namespace mozilla {
 
 class AudioStream;
@@ -180,13 +182,14 @@ protected:
   int mInRate;
   // Output rate in Hz (characteristic of the playback rate)
   int mOutRate;
   int mChannels;
   // Number of frames written to the buffers.
   int64_t mWritten;
   AudioClock mAudioClock;
   nsAutoPtr<soundtouch::SoundTouch> mTimeStretcher;
+  nsRefPtr<AsyncLatencyLogger> mLatencyLog;
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/Latency.cpp
+++ b/content/media/Latency.cpp
@@ -8,17 +8,19 @@
 #define FORCE_PR_LOG
 
 #include "Latency.h"
 #include "nsThreadUtils.h"
 #include <prlog.h>
 #include <cmath>
 #include <algorithm>
 
+#include <mozilla/Services.h>
 #include <mozilla/StaticPtr.h>
+#include "nsContentUtils.h"
 
 using namespace mozilla;
 
 const char* LatencyLogIndex2Strings[] = {
   "Audio MediaStreamTrack",
   "Video MediaStreamTrack",
   "Cubeb",
   "AudioStream",
@@ -54,67 +56,94 @@ public:
   }
 
 protected:
   AsyncLatencyLogger::LatencyLogIndex mIndex;
   uint64_t mID;
   int64_t mValue;
 };
 
-// This is the only function that clients should use.
 void LogLatency(AsyncLatencyLogger::LatencyLogIndex aIndex, uint64_t aID, int64_t aValue)
 {
   AsyncLatencyLogger::Get()->Log(aIndex, aID, aValue);
 }
 
+/* static */
 void AsyncLatencyLogger::InitializeStatics()
 {
   NS_ASSERTION(NS_IsMainThread(), "Main thread only");
   GetLatencyLog();
   gAsyncLogger = new AsyncLatencyLogger();
 }
 
-void AsyncLatencyLogger::Shutdown()
+/* static */
+void AsyncLatencyLogger::ShutdownLogger()
 {
   gAsyncLogger = nullptr;
 }
 
 /* static */
 AsyncLatencyLogger* AsyncLatencyLogger::Get(bool aStartTimer)
 {
+  // Users don't generally null-check the result since we should live longer than they
+  MOZ_ASSERT(gAsyncLogger);
+
   if (aStartTimer) {
     gAsyncLogger->Init();
   }
   return gAsyncLogger;
 }
 
+NS_IMPL_ISUPPORTS1(AsyncLatencyLogger, nsIObserver)
+
 AsyncLatencyLogger::AsyncLatencyLogger()
   : mThread(nullptr),
     mMutex("AsyncLatencyLogger")
-{ }
+{
+  NS_ASSERTION(NS_IsMainThread(), "Main thread only");
+  nsContentUtils::RegisterShutdownObserver(this);
+}
 
 AsyncLatencyLogger::~AsyncLatencyLogger()
 {
+  AsyncLatencyLogger::Shutdown();
+}
+
+void AsyncLatencyLogger::Shutdown()
+{
+  nsContentUtils::UnregisterShutdownObserver(this);
+
   MutexAutoLock lock(mMutex);
   if (mThread) {
     mThread->Shutdown();
   }
-  mStart = TimeStamp();
+  mStart = TimeStamp(); // make sure we don't try to restart it for any reason
 }
 
 void AsyncLatencyLogger::Init()
 {
   MutexAutoLock lock(mMutex);
   if (mStart.IsNull()) {
-    mStart = TimeStamp::Now();
     nsresult rv = NS_NewNamedThread("Latency Logger", getter_AddRefs(mThread));
     NS_ENSURE_SUCCESS_VOID(rv);
+    mStart = TimeStamp::Now();
   }
 }
 
+nsresult
+AsyncLatencyLogger::Observe(nsISupports* aSubject, const char* aTopic,
+                            const PRUnichar* aData)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
+    Shutdown();
+  }
+  return NS_OK;
+}
+
 // aID is a sub-identifier (in particular a specific MediaStramTrack)
 void AsyncLatencyLogger::WriteLog(LatencyLogIndex aIndex, uint64_t aID, int64_t aValue)
 {
   PR_LOG(GetLatencyLog(), PR_LOG_DEBUG,
          ("%s,%llu,%lld.,%lld.",
           LatencyLogIndex2Strings[aIndex], aID, GetTimeStamp(), aValue));
 }
 
@@ -128,9 +157,8 @@ void AsyncLatencyLogger::Log(LatencyLogI
 {
   if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
     nsCOMPtr<nsIRunnable> event = new LogEvent(aIndex, aID, aValue);
     if (mThread) {
       mThread->Dispatch(event, NS_DISPATCH_NORMAL);
     }
   }
 }
-
--- a/content/media/Latency.h
+++ b/content/media/Latency.h
@@ -8,46 +8,54 @@
 #define MOZILLA_LATENCY_H
 
 #include "mozilla/TimeStamp.h"
 #include "prlog.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "mozilla/Monitor.h"
 #include "nsISupportsImpl.h"
+#include "nsObserverService.h"
 
 class AsyncLatencyLogger;
 class LogEvent;
 
 PRLogModuleInfo* GetLatencyLog();
 
 // This class is a singleton. It is refcounted.
-class AsyncLatencyLogger
+class AsyncLatencyLogger : public nsIObserver
 {
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncLatencyLogger);
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
 public:
+
   enum LatencyLogIndex {
     AudioMediaStreamTrack,
     VideoMediaStreamTrack,
     Cubeb,
     AudioStream,
     NetEQ,
     _MAX_INDEX
   };
   void Log(LatencyLogIndex index, uint64_t aID, int64_t value);
   void WriteLog(LatencyLogIndex index, uint64_t aID, int64_t value);
 
   static AsyncLatencyLogger* Get(bool aStartTimer = false);
   static void InitializeStatics();
-  static void Shutdown();
+  // After this is called, the global log object may go away
+  static void ShutdownLogger();
 private:
   AsyncLatencyLogger();
-  ~AsyncLatencyLogger();
+  virtual ~AsyncLatencyLogger();
   int64_t GetTimeStamp();
   void Init();
+  // Shut down the thread associated with this, and make sure it doesn't
+  // start up again.
+  void Shutdown();
   // The thread on which the IO happens
   nsCOMPtr<nsIThread> mThread;
   // This can be initialized on multiple threads, but is protected by a
   // monitor. After the initialization phase, it is accessed on the log
   // thread only.
   mozilla::TimeStamp mStart;
   // This monitor protects mStart and mMediaLatencyLog for the
   // initialization sequence. It is initialized at layout startup, and
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2320,16 +2320,17 @@ MediaStreamGraphImpl::MediaStreamGraphIm
   , mForceShutDown(false)
   , mPostedRunInStableStateEvent(false)
   , mNonRealtimeIsRunning(false)
   , mDetectedNotRunning(false)
   , mPostedRunInStableState(false)
   , mRealtime(aRealtime)
   , mNonRealtimeProcessing(false)
   , mStreamOrderDirty(false)
+  , mLatencyLog(AsyncLatencyLogger::Get())
 {
 #ifdef PR_LOGGING
   if (!gMediaStreamGraphLog) {
     gMediaStreamGraphLog = PR_NewLogModule("MediaStreamGraph");
   }
 #endif
 
   mCurrentTimeStamp = mInitialTimeStamp = mLastMainThreadUpdate = TimeStamp::Now();
--- a/content/media/MediaStreamGraphImpl.h
+++ b/content/media/MediaStreamGraphImpl.h
@@ -7,16 +7,17 @@
 #define MOZILLA_MEDIASTREAMGRAPHIMPL_H_
 
 #include "MediaStreamGraph.h"
 
 #include "mozilla/Monitor.h"
 #include "mozilla/TimeStamp.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
+#include "Latency.h"
 
 namespace mozilla {
 
 template <typename T>
 class LinkedList;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaStreamGraphLog;
@@ -561,13 +562,17 @@ public:
    * value is only accessed on the main thread.
    */
   bool mNonRealtimeProcessing;
   /**
    * True when a change has happened which requires us to recompute the stream
    * blocking order.
    */
   bool mStreamOrderDirty;
+  /**
+   * Hold a ref to the Latency logger
+   */
+  nsRefPtr<AsyncLatencyLogger> mLatencyLog;
 };
 
 }
 
 #endif /* MEDIASTREAMGRAPHIMPL_H_ */
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -355,17 +355,17 @@ nsLayoutStatics::Shutdown()
   MediaPluginHost::Shutdown();
 #endif
 
 #ifdef MOZ_GSTREAMER
   GStreamerFormatHelper::Shutdown();
 #endif
 
   AudioStream::ShutdownLibrary();
-  AsyncLatencyLogger::Shutdown();
+  AsyncLatencyLogger::ShutdownLogger();
   WebAudioUtils::Shutdown();
 
 #ifdef MOZ_WMF
   WMFDecoder::UnloadDLLs();
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   nsVolumeService::Shutdown();