Bug 1239873 - Use AsyncShutdown API to shut down MediaStreamGraph thread. r=jesup

--HG--
extra : rebase_source : e79a1b0fdf3d37315707673ab94fc7cfb8e06981
This commit is contained in:
Jan-Ivar Bruaroey 2016-01-22 13:49:54 -05:00
Родитель a2a02af8bf
Коммит 286f642e6a
2 изменённых файлов: 88 добавлений и 34 удалений

Просмотреть файл

@ -23,6 +23,7 @@
#include "AudioNodeStream.h"
#include "AudioNodeExternalInputStream.h"
#include "mozilla/dom/AudioContextBinding.h"
#include "mozilla/media/MediaUtils.h"
#include <algorithm>
#include "DOMMediaStream.h"
#include "GeckoProfiler.h"
@ -1405,17 +1406,20 @@ MediaStreamGraphImpl::ApplyStreamUpdate(StreamUpdate* aUpdate)
}
void
MediaStreamGraphImpl::ForceShutDown()
MediaStreamGraphImpl::ForceShutDown(ShutdownTicket* aShutdownTicket)
{
NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
STREAM_LOG(LogLevel::Debug, ("MediaStreamGraph %p ForceShutdown", this));
{
MonitorAutoLock lock(mMonitor);
mForceShutDown = true;
mForceShutdownTicket = aShutdownTicket;
EnsureNextIterationLocked();
}
}
/* static */ StaticRefPtr<nsIAsyncShutdownBlocker> gMediaStreamGraphShutdownBlocker;
namespace {
class MediaStreamGraphShutDownRunnable : public nsRunnable {
@ -1444,6 +1448,13 @@ public:
mGraph->mDriver->Shutdown(); // This will wait until it's shutdown since
// we'll start tearing down the graph after this
// We may be one of several graphs. Drop ticket to eventually unblock shutdown.
mGraph->mForceShutdownTicket = nullptr;
// We can't block past the final LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION
// stage, since completion of that stage requires all streams to be freed,
// which requires shutdown to proceed.
// mGraph's thread is not running so it's OK to do whatever here
if (mGraph->IsEmpty()) {
// mGraph is no longer needed, so delete it.
@ -1510,14 +1521,6 @@ public:
}
};
class MediaStreamGraphShutdownObserver final : public nsIObserver
{
~MediaStreamGraphShutdownObserver() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
} // namespace
void
@ -2800,26 +2803,6 @@ MediaStreamGraphImpl::Destroy()
mSelfRef = nullptr;
}
NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
static bool gShutdownObserverRegistered = false;
NS_IMETHODIMP
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
for (auto iter = gGraphs.Iter(); !iter.Done(); iter.Next()) {
MediaStreamGraphImpl* graph = iter.UserData();
graph->ForceShutDown();
}
nsContentUtils::UnregisterShutdownObserver(this);
gShutdownObserverRegistered = false;
}
return NS_OK;
}
MediaStreamGraph*
MediaStreamGraph::GetInstance(MediaStreamGraph::GraphDriverType aGraphDriverRequested,
dom::AudioChannel aChannel)
@ -2830,9 +2813,38 @@ MediaStreamGraph::GetInstance(MediaStreamGraph::GraphDriverType aGraphDriverRequ
MediaStreamGraphImpl* graph = nullptr;
if (!gGraphs.Get(channel, &graph)) {
if (!gShutdownObserverRegistered) {
gShutdownObserverRegistered = true;
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
if (!gMediaStreamGraphShutdownBlocker) {
class Blocker : public media::ShutdownBlocker
{
public:
Blocker()
: media::ShutdownBlocker(NS_LITERAL_STRING(
"MediaStreamGraph shutdown: blocking on msg thread")) {}
NS_IMETHOD
BlockShutdown(nsIAsyncShutdownClient* aProfileBeforeChange) override
{
// Distribute the global async shutdown blocker in a ticket. If there
// are zero graphs then shutdown is unblocked when we go out of scope.
RefPtr<MediaStreamGraphImpl::ShutdownTicket> ticket =
new MediaStreamGraphImpl::ShutdownTicket(gMediaStreamGraphShutdownBlocker.get());
gMediaStreamGraphShutdownBlocker = nullptr;
for (auto iter = gGraphs.Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->ForceShutDown(ticket);
}
return NS_OK;
}
};
gMediaStreamGraphShutdownBlocker = new Blocker();
nsCOMPtr<nsIAsyncShutdownClient> barrier = MediaStreamGraphImpl::GetShutdownBarrier();
nsresult rv = barrier->
AddBlocker(gMediaStreamGraphShutdownBlocker,
NS_LITERAL_STRING(__FILE__), __LINE__,
NS_LITERAL_STRING("MediaStreamGraph shutdown"));
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
}
CubebUtils::InitPreferredSampleRate();
@ -2880,7 +2892,7 @@ MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph)
// Start the graph, but don't produce anything
graph->StartNonRealtimeProcessing(0);
}
graph->ForceShutDown();
graph->ForceShutDown(nullptr);
}
NS_IMPL_ISUPPORTS(MediaStreamGraphImpl, nsIMemoryReporter)

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsIMemoryReporter.h"
#include "nsIThread.h"
#include "nsIRunnable.h"
#include "nsIAsyncShutdown.h"
#include "Latency.h"
#include "mozilla/WeakPtr.h"
#include "GraphDriver.h"
@ -139,13 +140,48 @@ public:
* during RunInStableState; the messages will run on the graph thread.
*/
void AppendMessage(ControlMessage* aMessage);
// Shutdown helpers.
static already_AddRefed<nsIAsyncShutdownClient>
GetShutdownBarrier()
{
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
MOZ_RELEASE_ASSERT(svc);
nsCOMPtr<nsIAsyncShutdownClient> barrier;
nsresult rv = svc->GetProfileBeforeChange(getter_AddRefs(barrier));
if (!barrier) {
// We are probably in a content process.
rv = svc->GetContentChildShutdown(getter_AddRefs(barrier));
}
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
MOZ_RELEASE_ASSERT(barrier);
return barrier.forget();
}
class ShutdownTicket final
{
public:
explicit ShutdownTicket(nsIAsyncShutdownBlocker* aBlocker) : mBlocker(aBlocker) {}
NS_INLINE_DECL_REFCOUNTING(ShutdownTicket)
private:
~ShutdownTicket()
{
nsCOMPtr<nsIAsyncShutdownClient> barrier = GetShutdownBarrier();
barrier->RemoveBlocker(mBlocker);
}
nsCOMPtr<nsIAsyncShutdownBlocker> mBlocker;
};
/**
* Make this MediaStreamGraph enter forced-shutdown state. This state
* will be noticed by the media graph thread, which will shut down all streams
* and other state controlled by the media graph thread.
* This is called during application shutdown.
*/
void ForceShutDown();
void ForceShutDown(ShutdownTicket* aShutdownTicket);
/**
* Shutdown() this MediaStreamGraph's threads and return when they've shut down.
*/
@ -692,6 +728,12 @@ public:
* True when we need to do a forced shutdown during application shutdown.
*/
bool mForceShutDown;
/**
* Drop this reference during shutdown to unblock shutdown.
**/
RefPtr<ShutdownTicket> mForceShutdownTicket;
/**
* True when we have posted an event to the main thread to run
* RunInStableState() and the event hasn't run yet.