зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1239873 - Use AsyncShutdown API to shut down MediaStreamGraph thread. r=jesup
--HG-- extra : rebase_source : e79a1b0fdf3d37315707673ab94fc7cfb8e06981
This commit is contained in:
Родитель
a2a02af8bf
Коммит
286f642e6a
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче