Bug 1151656 - Implement the ability to get the currently running task queue. r=mattwoodrow
authorBobby Holley <bobbyholley@gmail.com>
Tue, 07 Apr 2015 11:26:35 -0700
changeset 268144 94128d385667f1379575855bd342c0256bdb5ce3
parent 268143 defb154dbaa8901f81672d0b1f08e08edd87b2c4
child 268145 1c6ee34874d872b25e625f651ef24156de70e1e9
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1151656
milestone40.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 1151656 - Implement the ability to get the currently running task queue. r=mattwoodrow I think this will generally be useful for asserting things. If we're concerned about the TLS overhead we could make it debug-only, but my sense is that it's negligible.
dom/media/AbstractThread.cpp
dom/media/MediaDecoder.cpp
dom/media/MediaTaskQueue.cpp
dom/media/MediaTaskQueue.h
--- a/dom/media/AbstractThread.cpp
+++ b/dom/media/AbstractThread.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "AbstractThread.h"
 
+#include "MediaTaskQueue.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 
 namespace mozilla {
 
 StaticRefPtr<AbstractThread> sMainThread;
@@ -22,17 +23,19 @@ AbstractThreadImpl<nsIThread>::Dispatch(
   nsCOMPtr<nsIRunnable> r = aRunnable;
   return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
 }
 
 template<>
 bool
 AbstractThreadImpl<nsIThread>::IsCurrentThreadIn()
 {
-  return NS_GetCurrentThread() == mTarget;
+  bool in = NS_GetCurrentThread() == mTarget;
+  MOZ_ASSERT_IF(in, MediaTaskQueue::GetCurrentQueue() == nullptr);
+  return in;
 }
 
 AbstractThread*
 AbstractThread::MainThread()
 {
   MOZ_ASSERT(sMainThread);
   return sMainThread;
 }
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -116,16 +116,18 @@ public:
 };
 
 StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
 
 void
 MediaDecoder::InitStatics()
 {
   AbstractThread::InitStatics();
+
+  MediaTaskQueue::InitStatics();
 }
 
 NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
 
 NS_IMPL_ISUPPORTS(MediaDecoder, nsIObserver)
 
 void MediaDecoder::NotifyOwnerActivityChanged()
 {
--- a/dom/media/MediaTaskQueue.cpp
+++ b/dom/media/MediaTaskQueue.cpp
@@ -5,16 +5,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MediaTaskQueue.h"
 #include "nsThreadUtils.h"
 #include "SharedThreadPool.h"
 
 namespace mozilla {
 
+ThreadLocal<MediaTaskQueue*> MediaTaskQueue::sCurrentQueueTLS;
+
+/* static */ void
+MediaTaskQueue::InitStatics()
+{
+  if (!sCurrentQueueTLS.init()) {
+    MOZ_CRASH();
+  }
+}
+
 MediaTaskQueue::MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool)
   : mPool(aPool)
   , mQueueMonitor("MediaTaskQueue::Queue")
   , mIsRunning(false)
   , mIsShutdown(false)
   , mIsFlushing(false)
 {
   MOZ_COUNT_CTOR(MediaTaskQueue);
@@ -191,17 +201,19 @@ MediaTaskQueue::IsEmpty()
   MonitorAutoLock mon(mQueueMonitor);
   return mTasks.empty();
 }
 
 bool
 MediaTaskQueue::IsCurrentThreadIn()
 {
   MonitorAutoLock mon(mQueueMonitor);
-  return NS_GetCurrentThread() == mRunningThread;
+  bool in = NS_GetCurrentThread() == mRunningThread;
+  MOZ_ASSERT_IF(in, GetCurrentQueue() == this);
+  return in;
 }
 
 nsresult
 MediaTaskQueue::Runner::Run()
 {
   RefPtr<nsIRunnable> event;
   {
     MonitorAutoLock mon(mQueue->mQueueMonitor);
@@ -218,17 +230,20 @@ MediaTaskQueue::Runner::Run()
   }
   MOZ_ASSERT(event);
 
   // Note that dropping the queue monitor before running the task, and
   // taking the monitor again after the task has run ensures we have memory
   // fences enforced. This means that if the object we're calling wasn't
   // designed to be threadsafe, it will be, provided we're only calling it
   // in this task queue.
-  event->Run();
+  {
+    AutoTaskGuard g(mQueue);
+    event->Run();
+  }
 
   // Drop the reference to event. The event will hold a reference to the
   // object it's calling, and we don't want to keep it alive, it may be
   // making assumptions what holds references to it. This is especially
   // the case if the object is waiting for us to shutdown, so that it
   // can shutdown (like in the MediaDecoderStateMachine's SHUTDOWN case).
   event = nullptr;
 
--- a/dom/media/MediaTaskQueue.h
+++ b/dom/media/MediaTaskQueue.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MediaTaskQueue_h_
 #define MediaTaskQueue_h_
 
 #include <queue>
 #include "mozilla/RefPtr.h"
 #include "mozilla/Monitor.h"
+#include "mozilla/ThreadLocal.h"
 #include "SharedThreadPool.h"
 #include "nsThreadUtils.h"
 #include "MediaPromise.h"
 
 class nsIRunnable;
 
 namespace mozilla {
 
@@ -23,17 +24,24 @@ class SharedThreadPool;
 typedef MediaPromise<bool, bool, false> ShutdownPromise;
 
 // Abstracts executing runnables in order in a thread pool. The runnables
 // dispatched to the MediaTaskQueue will be executed in the order in which
 // they're received, and are guaranteed to not be executed concurrently.
 // They may be executed on different threads, and a memory barrier is used
 // to make this threadsafe for objects that aren't already threadsafe.
 class MediaTaskQueue : public AbstractThread {
+  static ThreadLocal<MediaTaskQueue*> sCurrentQueueTLS;
 public:
+  static void InitStatics();
+
+  // Returns the task queue that the caller is currently running in, or null
+  // if the caller is not running in a MediaTaskQueue.
+  static MediaTaskQueue* GetCurrentQueue() { return sCurrentQueueTLS.get(); }
+
   explicit MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool);
 
   nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable);
 
   // For AbstractThread.
   nsresult Dispatch(already_AddRefed<nsIRunnable> aRunnable) override
   {
     RefPtr<nsIRunnable> r(aRunnable);
@@ -98,16 +106,34 @@ protected:
   // Queue of tasks to run.
   std::queue<TaskQueueEntry> mTasks;
 
   // The thread currently running the task queue. We store a reference
   // to this so that IsCurrentThreadIn() can tell if the current thread
   // is the thread currently running in the task queue.
   RefPtr<nsIThread> mRunningThread;
 
+  // RAII class that gets instantiated for each dispatched task.
+  class AutoTaskGuard
+  {
+  public:
+    explicit AutoTaskGuard(MediaTaskQueue* aQueue)
+    {
+      // NB: We don't hold the lock to aQueue here. Don't do anything that
+      // might require it.
+      MOZ_ASSERT(sCurrentQueueTLS.get() == nullptr);
+      sCurrentQueueTLS.set(aQueue);
+    }
+
+    ~AutoTaskGuard()
+    {
+      sCurrentQueueTLS.set(nullptr);
+    }
+  };
+
   // True if we've dispatched an event to the pool to execute events from
   // the queue.
   bool mIsRunning;
 
   // True if we've started our shutdown process.
   bool mIsShutdown;
   MediaPromiseHolder<ShutdownPromise> mShutdownPromise;