Bug 1085168 - Move timeout on async GMP shutdown to (catch all) non xpcom-shutdown case. r=jesup

This commit is contained in:
Chris Pearce 2014-10-22 09:45:18 +13:00
Родитель a4c280a3c0
Коммит fa856685bf
4 изменённых файлов: 73 добавлений и 68 удалений

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

@ -174,6 +174,49 @@ GMPParent::LoadProcess()
return NS_OK;
}
void
AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
{
NS_WARNING("Timed out waiting for GMP async shutdown!");
GMPParent* parent = reinterpret_cast<GMPParent*>(aClosure);
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
if (service) {
service->AsyncShutdownComplete(parent);
}
}
nsresult
GMPParent::EnsureAsyncShutdownTimeoutSet()
{
if (mAsyncShutdownTimeout) {
return NS_OK;
}
nsresult rv;
mAsyncShutdownTimeout = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Set timer to abort waiting for plugin to shutdown if it takes
// too long.
rv = mAsyncShutdownTimeout->SetTarget(mGMPThread);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
int32_t timeout = GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT;
nsRefPtr<GeckoMediaPluginService> service =
GeckoMediaPluginService::GetGeckoMediaPluginService();
if (service) {
timeout = service->AsyncShutdownTimeoutMs();
}
return mAsyncShutdownTimeout->InitWithFuncCallback(
&AbortWaitingForGMPAsyncShutdown, this, timeout,
nsITimer::TYPE_ONE_SHOT);
}
void
GMPParent::CloseIfUnused()
{
@ -199,7 +242,8 @@ GMPParent::CloseIfUnused()
LOGD(("%s::%s: %p sending async shutdown notification", __CLASS__,
__FUNCTION__, this));
mAsyncShutdownInProgress = true;
if (!SendBeginAsyncShutdown()) {
if (!SendBeginAsyncShutdown() ||
NS_FAILED(EnsureAsyncShutdownTimeoutSet())) {
AbortAsyncShutdown();
}
}
@ -219,6 +263,11 @@ GMPParent::AbortAsyncShutdown()
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
if (mAsyncShutdownTimeout) {
mAsyncShutdownTimeout->Cancel();
mAsyncShutdownTimeout = nullptr;
}
if (!mAsyncShutdownRequired || !mAsyncShutdownInProgress) {
return;
}
@ -289,6 +338,8 @@ GMPParent::Shutdown()
LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
MOZ_ASSERT(!mAsyncShutdownTimeout, "Should have canceled shutdown timeout");
if (mAbnormalShutdownInProgress) {
return;
}

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

@ -170,6 +170,8 @@ private:
virtual bool RecvAsyncShutdownComplete() MOZ_OVERRIDE;
virtual bool RecvAsyncShutdownRequired() MOZ_OVERRIDE;
nsresult EnsureAsyncShutdownTimeoutSet();
GMPState mState;
nsCOMPtr<nsIFile> mDirectory; // plugin directory on disk
nsString mName; // base name of plugin on disk, UTF-16 because used for paths
@ -188,6 +190,7 @@ private:
nsTArray<nsRefPtr<GMPTimerParent>> mTimers;
nsTArray<nsRefPtr<GMPStorageParent>> mStorage;
nsCOMPtr<nsIThread> mGMPThread;
nsCOMPtr<nsITimer> mAsyncShutdownTimeout; // GMP Thread only.
// NodeId the plugin is assigned to, or empty if the the plugin is not
// assigned to a NodeId.
nsAutoCString mNodeId;

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

@ -136,8 +136,8 @@ GeckoMediaPluginService::GetGeckoMediaPluginService()
NS_IMPL_ISUPPORTS(GeckoMediaPluginService, mozIGeckoMediaPluginService, nsIObserver)
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
static int32_t sMaxAsyncShutdownWaitMs = 0;
static bool sHaveSetTimeoutPrefCache = false;
GeckoMediaPluginService::GeckoMediaPluginService()
: mMutex("GeckoMediaPluginService::mMutex")
@ -147,9 +147,8 @@ GeckoMediaPluginService::GeckoMediaPluginService()
, mWaitingForPluginsAsyncShutdown(false)
{
MOZ_ASSERT(NS_IsMainThread());
static bool setTimeoutPrefCache = false;
if (!setTimeoutPrefCache) {
setTimeoutPrefCache = true;
if (!sHaveSetTimeoutPrefCache) {
sHaveSetTimeoutPrefCache = true;
Preferences::AddIntVarCache(&sMaxAsyncShutdownWaitMs,
"media.gmp.async-shutdown-timeout",
GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT);
@ -162,6 +161,13 @@ GeckoMediaPluginService::~GeckoMediaPluginService()
MOZ_ASSERT(mAsyncShutdownPlugins.IsEmpty());
}
int32_t
GeckoMediaPluginService::AsyncShutdownTimeoutMs()
{
MOZ_ASSERT(sHaveSetTimeoutPrefCache);
return sMaxAsyncShutdownWaitMs;
}
nsresult
GeckoMediaPluginService::Init()
{
@ -205,16 +211,6 @@ GeckoMediaPluginService::Init()
return GetThread(getter_AddRefs(thread));
}
void
AbortWaitingForGMPAsyncShutdown(nsITimer* aTimer, void* aClosure)
{
NS_WARNING("Timed out waiting for GMP async shutdown!");
nsRefPtr<GeckoMediaPluginService> service = sSingletonService.get();
if (service) {
service->AbortAsyncShutdown();
}
}
NS_IMETHODIMP
GeckoMediaPluginService::Observe(nsISupports* aSubject,
const char* aTopic,
@ -533,9 +529,11 @@ GeckoMediaPluginService::AsyncShutdownComplete(GMPParent* aParent)
mAsyncShutdownPlugins.RemoveElement(aParent);
if (mAsyncShutdownPlugins.IsEmpty() && mShuttingDownOnGMPThread) {
// The main thread is waiting for async shutdown of plugins,
// The main thread may be waiting for async shutdown of plugins,
// which has completed. Break the main thread out of its waiting loop.
AbortAsyncShutdown();
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethod(
this, &GeckoMediaPluginService::SetAsyncShutdownComplete));
NS_DispatchToMainThread(task);
}
}
@ -546,47 +544,6 @@ GeckoMediaPluginService::SetAsyncShutdownComplete()
mWaitingForPluginsAsyncShutdown = false;
}
void
GeckoMediaPluginService::AbortAsyncShutdown()
{
MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
for (size_t i = 0; i < mAsyncShutdownPlugins.Length(); i++) {
mAsyncShutdownPlugins[i]->AbortAsyncShutdown();
}
mAsyncShutdownPlugins.Clear();
if (mAsyncShutdownTimeout) {
mAsyncShutdownTimeout->Cancel();
mAsyncShutdownTimeout = nullptr;
}
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethod(
this, &GeckoMediaPluginService::SetAsyncShutdownComplete));
NS_DispatchToMainThread(task);
}
nsresult
GeckoMediaPluginService::SetAsyncShutdownTimeout()
{
MOZ_ASSERT(!mAsyncShutdownTimeout);
nsresult rv;
mAsyncShutdownTimeout = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create timer for async GMP shutdown");
return NS_OK;
}
// Set timer to abort waiting for plugins to shutdown if they take
// too long.
rv = mAsyncShutdownTimeout->SetTarget(mGMPThread);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return mAsyncShutdownTimeout->InitWithFuncCallback(
&AbortWaitingForGMPAsyncShutdown, nullptr, sMaxAsyncShutdownWaitMs,
nsITimer::TYPE_ONE_SHOT);
}
void
GeckoMediaPluginService::UnloadPlugins()
{
@ -607,16 +564,7 @@ GeckoMediaPluginService::UnloadPlugins()
mPlugins.Clear();
}
if (!mAsyncShutdownPlugins.IsEmpty()) {
// We have plugins that require async shutdown. Set a timer to abort
// waiting if they take too long to shutdown.
if (NS_FAILED(SetAsyncShutdownTimeout())) {
mAsyncShutdownPlugins.Clear();
}
}
if (mAsyncShutdownPlugins.IsEmpty()) {
mAsyncShutdownPlugins.Clear();
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethod(
this, &GeckoMediaPluginService::SetAsyncShutdownComplete));
NS_DispatchToMainThread(task);

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

@ -28,6 +28,8 @@ namespace gmp {
class GMPParent;
#define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
class GeckoMediaPluginService MOZ_FINAL : public mozIGeckoMediaPluginService
, public nsIObserver
{
@ -45,6 +47,8 @@ public:
void AsyncShutdownComplete(GMPParent* aParent);
void AbortAsyncShutdown();
int32_t AsyncShutdownTimeoutMs();
private:
~GeckoMediaPluginService();
@ -122,7 +126,6 @@ private:
MainThreadOnly<bool> mWaitingForPluginsAsyncShutdown;
nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins; // GMP Thread only.
nsCOMPtr<nsITimer> mAsyncShutdownTimeout; // GMP Thread only.
#ifndef MOZ_WIDGET_GONK
nsCOMPtr<nsIFile> mStorageBaseDir;