зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1256428 P1 Add ServiceWorkerJob2 base class. r=jdm
This commit is contained in:
Родитель
0ff5ceefd5
Коммит
9aff747125
|
@ -0,0 +1,218 @@
|
|||
/* -*- 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 "ServiceWorkerJob.h"
|
||||
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Workers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
ServiceWorkerJob2::Type
|
||||
ServiceWorkerJob2::GetType() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
ServiceWorkerJob2::State
|
||||
ServiceWorkerJob2::GetState() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceWorkerJob2::Canceled() const
|
||||
{
|
||||
return mCanceled;
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceWorkerJob2::IsEquivalentTo(ServiceWorkerJob2* aJob) const
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aJob);
|
||||
return mType == aJob->mType &&
|
||||
mScope.Equals(aJob->mScope) &&
|
||||
mScriptSpec.Equals(aJob->mScriptSpec) &&
|
||||
mPrincipal->Equals(aJob->mPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::AppendResultCallback(Callback* aCallback)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mState != State::Finished);
|
||||
MOZ_ASSERT(aCallback);
|
||||
MOZ_ASSERT(mFinalCallback != aCallback);
|
||||
MOZ_ASSERT(!mResultCallbackList.Contains(aCallback));
|
||||
// TODO: handle the case where InvokeResultCallback() has already been called
|
||||
mResultCallbackList.AppendElement(aCallback);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::StealResultCallbacksFrom(ServiceWorkerJob2* aJob)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aJob);
|
||||
MOZ_ASSERT(aJob->mState == State::Initial);
|
||||
|
||||
// Take the callbacks from the other job immediately to avoid the
|
||||
// any possibility of them existing on both jobs at once.
|
||||
nsTArray<RefPtr<Callback>> callbackList;
|
||||
callbackList.SwapElements(aJob->mResultCallbackList);
|
||||
|
||||
for (RefPtr<Callback>& callback : callbackList) {
|
||||
// Use AppendResultCallback() so that assertion checking is performed on
|
||||
// each callback.
|
||||
AppendResultCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::Start(Callback* aFinalCallback)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(!mCanceled);
|
||||
|
||||
MOZ_ASSERT(aFinalCallback);
|
||||
MOZ_ASSERT(!mFinalCallback);
|
||||
MOZ_ASSERT(!mResultCallbackList.Contains(aFinalCallback));
|
||||
mFinalCallback = aFinalCallback;
|
||||
|
||||
MOZ_ASSERT(mState == State::Initial);
|
||||
mState = State::Started;
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewRunnableMethod(this, &ServiceWorkerJob2::AsyncExecute);
|
||||
|
||||
// We may have to wait for the PBackground actor to be initialized
|
||||
// before proceeding. We should always be able to get a ServiceWorkerManager,
|
||||
// however, since Start() should not be called during shutdown.
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
if (!swm->HasBackgroundActor()) {
|
||||
swm->AppendPendingOperation(runnable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise start asynchronously. We should never run a job synchronously.
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
NS_DispatchToMainThread(runnable.forget())));
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::Cancel()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(!mCanceled);
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
ServiceWorkerJob2::ServiceWorkerJob2(Type aType,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsACString& aScope,
|
||||
const nsACString& aScriptSpec)
|
||||
: mType(aType)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mScope(aScope)
|
||||
, mScriptSpec(aScriptSpec)
|
||||
, mState(State::Initial)
|
||||
, mCanceled(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mPrincipal);
|
||||
MOZ_ASSERT(!mScope.IsEmpty());
|
||||
// Some job types may have an empty script spec
|
||||
}
|
||||
|
||||
ServiceWorkerJob2::~ServiceWorkerJob2()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
// Jobs must finish or never be started. Destroying an actively running
|
||||
// job is an error.
|
||||
MOZ_ASSERT(mState != State::Started);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::InvokeResultCallbacks(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mState == State::Started);
|
||||
|
||||
nsTArray<RefPtr<Callback>> callbackList;
|
||||
callbackList.SwapElements(mResultCallbackList);
|
||||
|
||||
for (RefPtr<Callback>& callback : callbackList) {
|
||||
// The callback might consume an exception on the ErrorResult, so we need
|
||||
// to clone in order to maintain the error for the next callback.
|
||||
ErrorResult rv;
|
||||
aRv.CloneTo(rv);
|
||||
|
||||
callback->JobFinished(this, rv);
|
||||
|
||||
// The callback might not consume the error.
|
||||
rv.SuppressException();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::InvokeResultCallbacks(nsresult aRv)
|
||||
{
|
||||
ErrorResult converted(aRv);
|
||||
InvokeResultCallbacks(converted);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::Finish(ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mState == State::Started);
|
||||
|
||||
// Ensure that we only surface SecurityErr, TypeErr or InvalidStateErr to script.
|
||||
if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) &&
|
||||
!aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR) &&
|
||||
!aRv.ErrorCodeIs(NS_ERROR_DOM_INVALID_STATE_ERR)) {
|
||||
|
||||
// Remove the old error code so we can replace it with a TypeError.
|
||||
aRv.SuppressException();
|
||||
|
||||
NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
|
||||
NS_ConvertUTF8toUTF16 scope(mScope);
|
||||
|
||||
// Throw the type error with a generic error message.
|
||||
aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope);
|
||||
}
|
||||
|
||||
// The final callback may drop the last ref to this object.
|
||||
RefPtr<ServiceWorkerJob2> kungFuDeathGrip = this;
|
||||
|
||||
InvokeResultCallbacks(aRv);
|
||||
|
||||
mState = State::Finished;
|
||||
|
||||
mFinalCallback->JobFinished(this, aRv);
|
||||
mFinalCallback = nullptr;
|
||||
|
||||
// The callback might not consume the error.
|
||||
aRv.SuppressException();
|
||||
|
||||
// Async release this object to ensure that our caller methods complete
|
||||
// as well.
|
||||
NS_ReleaseOnMainThread(kungFuDeathGrip.forget(), true /* always proxy */);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerJob2::Finish(nsresult aRv)
|
||||
{
|
||||
ErrorResult converted(aRv);
|
||||
Finish(converted);
|
||||
}
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,149 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_serviceworkerjob_h
|
||||
#define mozilla_dom_workers_serviceworkerjob_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class ServiceWorkerJob2
|
||||
{
|
||||
public:
|
||||
// Implement this interface to receive notification when a job completes.
|
||||
class Callback
|
||||
{
|
||||
public:
|
||||
// Called once when the job completes. If the job is started, then this
|
||||
// will be called. If a job is never executed due to browser shutdown,
|
||||
// then this method will never be called. This method is always called
|
||||
// on the main thread asynchronously after Start() completes.
|
||||
virtual void JobFinished(ServiceWorkerJob2* aJob, ErrorResult& aStatus) = 0;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
AddRef(void) = 0;
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType)
|
||||
Release(void) = 0;
|
||||
};
|
||||
|
||||
enum class Type
|
||||
{
|
||||
Register,
|
||||
Update,
|
||||
Unregister
|
||||
};
|
||||
|
||||
enum class State
|
||||
{
|
||||
Initial,
|
||||
Started,
|
||||
Finished
|
||||
};
|
||||
|
||||
Type
|
||||
GetType() const;
|
||||
|
||||
State
|
||||
GetState() const;
|
||||
|
||||
// Determine if the job has been canceled. This does not change the
|
||||
// current State, but indicates that the job should progress to Finished
|
||||
// as soon as possible.
|
||||
bool
|
||||
Canceled() const;
|
||||
|
||||
bool
|
||||
IsEquivalentTo(ServiceWorkerJob2* aJob) const;
|
||||
|
||||
// Add a callback that will be invoked when the job's result is available.
|
||||
// Some job types will invoke this before the job is actually finished.
|
||||
// If an early callback does not occur, then it will be called automatically
|
||||
// when Finish() is called. These callbacks will be invoked while the job
|
||||
// state is Started.
|
||||
void
|
||||
AppendResultCallback(Callback* aCallback);
|
||||
|
||||
// This takes ownership of any result callbacks associated with the given job
|
||||
// and then appends them to this job's callback list.
|
||||
void
|
||||
StealResultCallbacksFrom(ServiceWorkerJob2* aJob);
|
||||
|
||||
// Start the job. All work will be performed asynchronously on
|
||||
// the main thread. The Finish() method must be called exactly
|
||||
// once after this point. A final callback must be provided. It
|
||||
// will be invoked after all other callbacks have been processed.
|
||||
void
|
||||
Start(Callback* aFinalCallback);
|
||||
|
||||
// Set an internal flag indicating that a started job should finish as
|
||||
// soon as possible.
|
||||
void
|
||||
Cancel();
|
||||
|
||||
protected:
|
||||
ServiceWorkerJob2(Type aType,
|
||||
nsIPrincipal* aPrincipal,
|
||||
const nsACString& aScope,
|
||||
const nsACString& aScriptSpec);
|
||||
|
||||
virtual ~ServiceWorkerJob2();
|
||||
|
||||
// Invoke the result callbacks immediately. The job must be in the
|
||||
// Started state. The callbacks are cleared after being invoked,
|
||||
// so subsequent method calls have no effect.
|
||||
void
|
||||
InvokeResultCallbacks(ErrorResult& aRv);
|
||||
|
||||
// Convenience method that converts to ErrorResult and calls real method.
|
||||
void
|
||||
InvokeResultCallbacks(nsresult aRv);
|
||||
|
||||
// Indicate that the job has completed. The must be called exactly
|
||||
// once after Start() has initiated job execution. It may not be
|
||||
// called until Start() has returned.
|
||||
void
|
||||
Finish(ErrorResult& aRv);
|
||||
|
||||
// Convenience method that converts to ErrorResult and calls real method.
|
||||
void
|
||||
Finish(nsresult aRv);
|
||||
|
||||
// Specific job types should define AsyncExecute to begin their work.
|
||||
// All errors and successes must result in Finish() being called.
|
||||
virtual void
|
||||
AsyncExecute() = 0;
|
||||
|
||||
const Type mType;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
const nsCString mScope;
|
||||
const nsCString mScriptSpec;
|
||||
|
||||
private:
|
||||
RefPtr<Callback> mFinalCallback;
|
||||
nsTArray<RefPtr<Callback>> mResultCallbackList;
|
||||
State mState;
|
||||
bool mCanceled;
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(ServiceWorkerJob2)
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_workers_serviceworkerjob_h
|
|
@ -330,6 +330,7 @@ class ServiceWorkerManager final
|
|||
friend class ServiceWorkerJobQueue;
|
||||
friend class ServiceWorkerInstallJob;
|
||||
friend class ServiceWorkerRegisterJob;
|
||||
friend class ServiceWorkerJob2;
|
||||
friend class ServiceWorkerJobBase;
|
||||
friend class ServiceWorkerScriptJobBase;
|
||||
friend class ServiceWorkerRegistrationInfo;
|
||||
|
|
|
@ -66,6 +66,7 @@ UNIFIED_SOURCES += [
|
|||
'ServiceWorkerClients.cpp',
|
||||
'ServiceWorkerContainer.cpp',
|
||||
'ServiceWorkerEvents.cpp',
|
||||
'ServiceWorkerJob.cpp',
|
||||
'ServiceWorkerManager.cpp',
|
||||
'ServiceWorkerManagerChild.cpp',
|
||||
'ServiceWorkerManagerParent.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче