Bug 1286766 - make MediaPrefs::MDSMSuspendBackgroundVideoDelay() safe to read off main thread using Preferences::AddAtomicUintVarCache(). r?gerald draft
authorJW Wang <jwwang@mozilla.com>
Thu, 14 Jul 2016 15:50:23 +0800
changeset 390462 41dc10adcfc8a981e129849072e539266b70e475
parent 389550 5a91e5b49be3c1ba401b057e90c92d7488e3647d
child 390524 ff4b209e9814c9570772a3a897369f63dfc2fb22
push id23673
push userjwwang@mozilla.com
push dateThu, 21 Jul 2016 05:27:20 +0000
reviewersgerald
bugs1286766
milestone50.0a1
Bug 1286766 - make MediaPrefs::MDSMSuspendBackgroundVideoDelay() safe to read off main thread using Preferences::AddAtomicUintVarCache(). r?gerald MozReview-Commit-ID: FAplUTE07l0
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaPrefs.cpp
dom/media/MediaPrefs.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -201,25 +201,21 @@ static void InitVideoQueuePrefs() {
       "media.video-queue.hw-accel-size", HW_VIDEO_QUEUE_SIZE);
     sVideoQueueSendToCompositorSize = Preferences::GetUint(
       "media.video-queue.send-to-compositor-size", VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE);
   }
 }
 
 // Delay, in milliseconds, that tabs needs to be in background before video
 // decoding is suspended.
-static TimeDuration sSuspendBackgroundVideoDelay;
-
-static void
-InitSuspendBackgroundPref()
+static TimeDuration
+SuspendBackgroundVideoDelay()
 {
-  MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
-
-  sSuspendBackgroundVideoDelay = TimeDuration::FromMilliseconds(
-      MediaPrefs::MDSMSuspendBackgroundVideoDelay());
+  return TimeDuration::FromMilliseconds(
+    MediaPrefs::MDSMSuspendBackgroundVideoDelay());
 }
 
 #define INIT_WATCHABLE(name, val) \
   name(val, "MediaDecoderStateMachine::" #name)
 #define INIT_MIRROR(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Mirror)")
 #define INIT_CANONICAL(name, val) \
   name(mTaskQueue, val, "MediaDecoderStateMachine::" #name " (Canonical)")
@@ -290,17 +286,16 @@ MediaDecoderStateMachine::MediaDecoderSt
   INIT_CANONICAL(mCurrentPosition, 0),
   INIT_CANONICAL(mPlaybackOffset, 0),
   INIT_CANONICAL(mIsAudioDataAudible, false)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   InitVideoQueuePrefs();
-  InitSuspendBackgroundPref();
 
   mBufferingWait = IsRealTime() ? 0 : 15;
   mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
 
 #ifdef XP_WIN
   // Ensure high precision timers are enabled on Windows, otherwise the state
   // machine isn't woken up at reliable intervals to set the next frame,
   // and we drop frames while painting. Note that multiple calls to this
@@ -1349,17 +1344,17 @@ void MediaDecoderStateMachine::Visibilit
 
   // If not playing then there's nothing to do.
   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
     return;
   }
 
   // Start timer to trigger suspended decoding state when going invisible.
   if (!mIsVisible) {
-    TimeStamp target = TimeStamp::Now() + sSuspendBackgroundVideoDelay;
+    TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
 
     RefPtr<MediaDecoderStateMachine> self = this;
     mVideoDecodeSuspendTimer.Ensure(target,
                                     [=]() { self->OnSuspendTimerResolved(); },
                                     [=]() { self->OnSuspendTimerRejected(); });
     return;
   }
 
--- a/dom/media/MediaPrefs.cpp
+++ b/dom/media/MediaPrefs.cpp
@@ -64,9 +64,16 @@ void MediaPrefs::PrefAddVarCache(uint32_
 
 void MediaPrefs::PrefAddVarCache(float* aVariable,
                                  const char* aPref,
                                  float aDefault)
 {
   Preferences::AddFloatVarCache(aVariable, aPref, aDefault);
 }
 
+void MediaPrefs::PrefAddVarCache(AtomicUint32* aVariable,
+                                 const char* aPref,
+                                 uint32_t aDefault)
+{
+  Preferences::AddAtomicUintVarCache(aVariable, aPref, aDefault);
+}
+
 } // namespace mozilla
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -5,16 +5,18 @@
 
 #ifndef MEDIA_PREFS_H
 #define MEDIA_PREFS_H
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
+#include "mozilla/Atomics.h"
+
 // First time MediaPrefs::GetSingleton() needs to be called on the main thread,
 // before any of the methods accessing the values are used, but after
 // the Preferences system has been initialized.
 
 // The static methods to access the preference value are safe to call
 // from any thread after that first call.
 
 // To register a preference, you need to add a line in this file using
@@ -28,34 +30,48 @@
 // "media.resampling.enabled".  If the value is not set, the default would be
 // false.
 
 #define DECL_MEDIA_PREF(Pref, Name, Type, Default)                            \
 public:                                                                       \
 static const Type& Name() { MOZ_ASSERT(SingletonExists()); return GetSingleton().mPref##Name.mValue; } \
 private:                                                                      \
 static const char* Get##Name##PrefName() { return Pref; }                     \
-static Type Get##Name##PrefDefault() { return Default; }                      \
+static StripAtomic<Type> Get##Name##PrefDefault() { return Default; }         \
 PrefTemplate<Type, Get##Name##PrefDefault, Get##Name##PrefName> mPref##Name
 
 // Custom Definitions.
 #define GMP_DEFAULT_ASYNC_SHUTDOWN_TIMEOUT 3000
 #define SUSPEND_BACKGROUND_VIDEO_DELAY_MS 10000
 #define TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE "media.webspeech.test.fake_recognition_service"
 
 namespace mozilla {
 
 template<class T> class StaticAutoPtr;
 
 class MediaPrefs final
 {
+  typedef Atomic<uint32_t, Relaxed> AtomicUint32;
+
+  template <typename T>
+  struct StripAtomicImpl {
+    typedef T Type;
+  };
+
+  template <typename T, MemoryOrdering Order>
+  struct StripAtomicImpl<Atomic<T, Order>> {
+    typedef T Type;
+  };
+
+  template <typename T>
+  using StripAtomic = typename StripAtomicImpl<T>::Type;
 
 private:
   // Since we cannot use const char*, use a function that returns it.
-  template <class T, T Default(), const char* Pref()>
+  template <class T, StripAtomic<T> Default(), const char* Pref()>
   class PrefTemplate
   {
   public:
     PrefTemplate()
     : mValue(Default())
     {
       Register(Pref());
     }
@@ -109,17 +125,17 @@ private:
   DECL_MEDIA_PREF("media.decoder.fuzzing.video-output-minimum-interval-ms", PDMFuzzingInterval, uint32_t, 0);
   DECL_MEDIA_PREF("media.decoder.fuzzing.dont-delay-inputexhausted", PDMFuzzingDelayInputExhausted, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.enabled",                PDMGMPEnabled, bool, true);
   DECL_MEDIA_PREF("media.gmp.decoder.aac",                    GMPAACPreferred, uint32_t, 0);
   DECL_MEDIA_PREF("media.gmp.decoder.h264",                   GMPH264Preferred, uint32_t, 0);
 
   // MediaDecoderStateMachine
   DECL_MEDIA_PREF("media.suspend-bkgnd-video.enabled",        MDSMSuspendBackgroundVideoEnabled, bool, false);
-  DECL_MEDIA_PREF("media.suspend-bkgnd-video.delay-ms",       MDSMSuspendBackgroundVideoDelay, uint32_t, SUSPEND_BACKGROUND_VIDEO_DELAY_MS);
+  DECL_MEDIA_PREF("media.suspend-bkgnd-video.delay-ms",       MDSMSuspendBackgroundVideoDelay, AtomicUint32, SUSPEND_BACKGROUND_VIDEO_DELAY_MS);
 
   // WebSpeech
   DECL_MEDIA_PREF("media.webspeech.synth.force_global_queue", WebSpeechForceGlobal, bool, false);
   DECL_MEDIA_PREF("media.webspeech.test.enable",              WebSpeechTestEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.test.fake_fsm_events",     WebSpeechFakeFSMEvents, bool, false);
   DECL_MEDIA_PREF(TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE,   WebSpeechFakeRecognitionService, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.enable",       WebSpeechRecognitionEnabled, bool, false);
   DECL_MEDIA_PREF("media.webspeech.recognition.force_enable", WebSpeechRecognitionForceEnabled, bool, false);
@@ -151,16 +167,17 @@ private:
     return -1;
   }
 
   // Creating these to avoid having to include Preferences.h in the .h
   static void PrefAddVarCache(bool*, const char*, bool);
   static void PrefAddVarCache(int32_t*, const char*, int32_t);
   static void PrefAddVarCache(uint32_t*, const char*, uint32_t);
   static void PrefAddVarCache(float*, const char*, float);
+  static void PrefAddVarCache(AtomicUint32*, const char*, uint32_t);
 
   static void AssertMainThread();
 
   MediaPrefs();
   MediaPrefs(const MediaPrefs&) = delete;
   MediaPrefs& operator=(const MediaPrefs&) = delete;
 };