Bug 1001691 - Use thread pool for WebCrypto operations r=bz

This commit is contained in:
Tim Taubert 2015-09-11 23:41:58 +02:00
Родитель c3ced0a78e
Коммит 8f64c093bf
2 изменённых файлов: 113 добавлений и 29 удалений

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

@ -8,6 +8,7 @@
#include "cryptohi.h"
#include "secerr.h"
#include "ScopedNSSTypes.h"
#include "nsNSSComponent.h"
#include "jsapi.h"
#include "mozilla/Telemetry.h"
@ -17,6 +18,7 @@
#include "mozilla/dom/TypedArray.h"
#include "mozilla/dom/WebCryptoCommon.h"
#include "mozilla/dom/WebCryptoTask.h"
#include "mozilla/dom/WebCryptoThreadPool.h"
namespace mozilla {
namespace dom {
@ -286,9 +288,72 @@ CloneData(JSContext* aCx, CryptoBuffer& aDst, JS::Handle<JSObject*> aSrc)
// Implementation of WebCryptoTask methods
void
WebCryptoTask::FailWithError(nsresult aRv)
WebCryptoTask::DispatchWithPromise(Promise* aResultPromise)
{
MOZ_ASSERT(NS_IsMainThread());
mResultPromise = aResultPromise;
// Fail if an error was set during the constructor
MAYBE_EARLY_FAIL(mEarlyRv)
// Perform pre-NSS operations, and fail if they fail
mEarlyRv = BeforeCrypto();
MAYBE_EARLY_FAIL(mEarlyRv)
// Skip NSS if we're already done, or launch a CryptoTask
if (mEarlyComplete) {
CallCallback(mEarlyRv);
Skip();
return;
}
// Ensure that NSS is initialized, since presumably CalculateResult
// will use NSS functions
if (!EnsureNSSInitializedChromeOrContent()) {
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
MAYBE_EARLY_FAIL(mEarlyRv)
}
// Store calling thread and dispatch to thread pool.
mOriginalThread = NS_GetCurrentThread();
mEarlyRv = WebCryptoThreadPool::Dispatch(this);
MAYBE_EARLY_FAIL(mEarlyRv)
}
NS_IMETHODIMP
WebCryptoTask::Run()
{
// Run heavy crypto operations on the thread pool, off the original thread.
if (!IsOnOriginalThread()) {
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
mRv = NS_ERROR_NOT_AVAILABLE;
} else {
mRv = CalculateResult();
}
// Back to the original thread, i.e. continue below.
mOriginalThread->Dispatch(this, NS_DISPATCH_NORMAL);
return NS_OK;
}
// We're now back on the calling thread.
// Release NSS resources now, before calling CallCallback, so that
// WebCryptoTasks have consistent behavior regardless of whether NSS is shut
// down between CalculateResult being called and CallCallback being called.
virtualDestroyNSSReference();
CallCallback(mRv);
return NS_OK;
}
void
WebCryptoTask::FailWithError(nsresult aRv)
{
MOZ_ASSERT(IsOnOriginalThread());
Telemetry::Accumulate(Telemetry::WEBCRYPTO_RESOLVED, false);
// Blindly convert nsresult to DOMException
@ -302,7 +367,7 @@ WebCryptoTask::FailWithError(nsresult aRv)
nsresult
WebCryptoTask::CalculateResult()
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!IsOnOriginalThread());
if (isAlreadyShutDown()) {
return NS_ERROR_DOM_UNKNOWN_ERR;
@ -314,7 +379,7 @@ WebCryptoTask::CalculateResult()
void
WebCryptoTask::CallCallback(nsresult rv)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(IsOnOriginalThread());
if (NS_FAILED(rv)) {
FailWithError(rv);
return;

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

@ -7,8 +7,7 @@
#ifndef mozilla_dom_WebCryptoTask_h
#define mozilla_dom_WebCryptoTask_h
#include "CryptoTask.h"
#include "nsNSSShutDown.h"
#include "nsIGlobalObject.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/DOMException.h"
@ -58,30 +57,15 @@ if (NS_FAILED(rv)) { \
return; \
}
class WebCryptoTask : public CryptoTask
class WebCryptoTask : public nsCancelableRunnable,
public nsNSSShutDownObject
{
public:
virtual void DispatchWithPromise(Promise* aResultPromise)
virtual void DispatchWithPromise(Promise* aResultPromise);
void Skip()
{
MOZ_ASSERT(NS_IsMainThread());
mResultPromise = aResultPromise;
// Fail if an error was set during the constructor
MAYBE_EARLY_FAIL(mEarlyRv)
// Perform pre-NSS operations, and fail if they fail
mEarlyRv = BeforeCrypto();
MAYBE_EARLY_FAIL(mEarlyRv)
// Skip NSS if we're already done, or launch a CryptoTask
if (mEarlyComplete) {
CallCallback(mEarlyRv);
Skip();
return;
}
mEarlyRv = Dispatch("SubtleCrypto");
MAYBE_EARLY_FAIL(mEarlyRv)
virtualDestroyNSSReference();
}
protected:
@ -184,8 +168,25 @@ protected:
WebCryptoTask()
: mEarlyRv(NS_OK)
, mEarlyComplete(false)
, mOriginalThread(nullptr)
, mReleasedNSSResources(false)
, mRv(NS_ERROR_NOT_INITIALIZED)
{}
virtual ~WebCryptoTask()
{
MOZ_ASSERT(mReleasedNSSResources);
nsNSSShutDownPreventionLock lock;
if (!isAlreadyShutDown()) {
shutdown(calledFromObject);
}
}
bool IsOnOriginalThread() {
return !mOriginalThread || NS_GetCurrentThread() == mOriginalThread;
}
// For things that need to happen on the main thread
// either before or after CalculateResult
virtual nsresult BeforeCrypto() { return NS_OK; }
@ -198,11 +199,29 @@ protected:
// Subclasses should override this method if they keep references to
// any NSS objects, e.g., SECKEYPrivateKey or PK11SymKey.
virtual void ReleaseNSSResources() override {}
virtual void ReleaseNSSResources() {}
virtual nsresult CalculateResult() override final;
virtual nsresult CalculateResult() final;
virtual void CallCallback(nsresult rv) override final;
virtual void CallCallback(nsresult rv) final;
private:
NS_IMETHOD Run() override final;
virtual void
virtualDestroyNSSReference() override final
{
MOZ_ASSERT(IsOnOriginalThread());
if (!mReleasedNSSResources) {
mReleasedNSSResources = true;
ReleaseNSSResources();
}
}
nsCOMPtr<nsIThread> mOriginalThread;
bool mReleasedNSSResources;
nsresult mRv;
};
// XXX This class is declared here (unlike others) to enable reuse by WebRTC.