gecko-dev/dom/promise/PromiseWorkerProxy.h

239 строки
8.3 KiB
C
Исходник Обычный вид История

/* -*- 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_PromiseWorkerProxy_h
#define mozilla_dom_PromiseWorkerProxy_h
// Required for Promise::PromiseTaskSync.
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/dom/workers/bindings/WorkerFeature.h"
#include "nsProxyRelease.h"
#include "WorkerRunnable.h"
namespace mozilla {
namespace dom {
class Promise;
namespace workers {
class WorkerPrivate;
} // namespace workers
// A proxy to (eventually) mirror a resolved/rejected Promise's result from the
// main thread to a Promise on the worker thread.
//
// How to use:
//
// 1. Create a Promise on the worker thread and return it to the content
// script:
//
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
// RefPtr<Promise> promise = Promise::Create(workerPrivate->GlobalScope(), aRv);
// if (aRv.Failed()) {
// return nullptr;
// }
//
// 2. Create a PromiseWorkerProxy wrapping the Promise. If this fails, the
// worker is shutting down and you should fail the original call. This is
// only likely to happen in (Gecko-specific) worker onclose handlers.
//
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
// RefPtr<PromiseWorkerProxy> proxy =
// PromiseWorkerProxy::Create(workerPrivate, promise);
// if (!proxy) {
// // You may also reject the Promise with an AbortError or similar.
// return nullptr;
// }
//
// 3. Dispatch a runnable to the main thread, with a reference to the proxy to
// perform the main thread operation. PromiseWorkerProxy is thread-safe
// refcounted.
//
// 4. Return the worker thread promise to the JS caller:
//
// return promise.forget();
//
// 5. In your main thread runnable Run(), obtain a Promise on
// the main thread and call its AppendNativeHandler(PromiseNativeHandler*)
// to bind the PromiseWorkerProxy created at #2.
//
// 4. Then the Promise results returned by ResolvedCallback/RejectedCallback
// will be dispatched as a WorkerRunnable to the worker thread to
// resolve/reject the Promise created at #1.
//
// PromiseWorkerProxy can also be used in situations where there is no main
// thread Promise, or where special handling is required on the worker thread
// for promise resolution. Create a PromiseWorkerProxy as in steps 1 to 3
// above. When the main thread is ready to resolve the worker thread promise:
//
// 1. Acquire the mutex before attempting to access the worker private.
//
// AssertIsOnMainThread();
// MutexAutoLock lock(proxy->Lock());
// if (proxy->CleanedUp()) {
// // Worker has already shut down, can't access worker private.
// return;
// }
//
// 2. Dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the
// worker.
//
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
// RefPtr<FinishTaskWorkerRunnable> runnable =
// new FinishTaskWorkerRunnable(proxy->GetWorkerPrivate(), proxy, result);
// if (!r->Dispatch()) {
// // Worker is alive but not Running any more, so the Promise can't
// // be resolved, give up. The proxy will get Release()d at some
// // point.
//
// // Usually do nothing, but you may want to log the fact.
// }
//
// 3. In the WorkerRunnable's WorkerRun() use WorkerPromise() to access the
// Promise and resolve/reject it. Then call CleanUp().
//
// bool
// WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
// {
// aWorkerPrivate->AssertIsOnWorkerThread();
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
// RefPtr<Promise> promise = mProxy->WorkerPromise();
// promise->MaybeResolve(mResult);
// mProxy->CleanUp();
// }
//
// Note: If a PromiseWorkerProxy is not cleaned up by a WorkerRunnable - this
// can happen if the main thread Promise is never fulfilled - it will
// stay alive till the worker reaches a Canceling state, even if all external
// references to it are dropped.
class PromiseWorkerProxy : public PromiseNativeHandler
, public workers::WorkerFeature
, public StructuredCloneHolderBase
{
friend class PromiseWorkerProxyRunnable;
NS_DECL_THREADSAFE_ISUPPORTS
public:
typedef JSObject* (*ReadCallbackOp)(JSContext* aCx,
JSStructuredCloneReader* aReader,
const PromiseWorkerProxy* aProxy,
uint32_t aTag,
uint32_t aData);
typedef bool (*WriteCallbackOp)(JSContext* aCx,
JSStructuredCloneWriter* aWorker,
PromiseWorkerProxy* aProxy,
JS::HandleObject aObj);
struct PromiseWorkerProxyStructuredCloneCallbacks
{
ReadCallbackOp Read;
WriteCallbackOp Write;
};
static already_AddRefed<PromiseWorkerProxy>
Create(workers::WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const PromiseWorkerProxyStructuredCloneCallbacks* aCallbacks = nullptr);
// Main thread callers must hold Lock() and check CleanUp() before calling this.
// Worker thread callers, this will assert that the proxy has not been cleaned
// up.
workers::WorkerPrivate* GetWorkerPrivate() const;
// This should only be used within WorkerRunnable::WorkerRun() running on the
// worker thread! Do not call this after calling CleanUp().
Promise* WorkerPromise() const;
void StoreISupports(nsISupports* aSupports);
// Worker thread only. Calling this invalidates several assumptions, so be
// sure this is the last thing you do.
// 1. WorkerPrivate() will no longer return a valid worker.
// 2. WorkerPromise() will crash!
void CleanUp();
Mutex& Lock()
{
return mCleanUpLock;
}
bool CleanedUp() const
{
mCleanUpLock.AssertCurrentThreadOwns();
return mCleanedUp;
}
// StructuredCloneHolderBase
JSObject* CustomReadHandler(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aTag,
uint32_t aIndex) override;
bool CustomWriteHandler(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
JS::Handle<JSObject*> aObj) override;
protected:
virtual void ResolvedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue) override;
virtual void RejectedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue) override;
virtual bool Notify(JSContext* aCx, workers::Status aStatus) override;
private:
PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
Promise* aWorkerPromise,
const PromiseWorkerProxyStructuredCloneCallbacks* aCallbacks = nullptr);
virtual ~PromiseWorkerProxy();
bool AddRefObject();
// If not called from Create(), be sure to hold Lock().
void CleanProperties();
// Function pointer for calling Promise::{ResolveInternal,RejectInternal}.
typedef void (Promise::*RunCallbackFunc)(JSContext*,
JS::Handle<JS::Value>);
void RunCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
RunCallbackFunc aFunc);
// Any thread with appropriate checks.
workers::WorkerPrivate* mWorkerPrivate;
// Worker thread only.
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<Promise> mWorkerPromise;
// Modified on the worker thread.
// It is ok to *read* this without a lock on the worker.
// Main thread must always acquire a lock.
bool mCleanedUp; // To specify if the cleanUp() has been done.
const PromiseWorkerProxyStructuredCloneCallbacks* mCallbacks;
// Aimed to keep objects alive when doing the structured-clone read/write,
// which can be added by calling StoreISupports() on the main thread.
nsTArray<nsMainThreadPtrHandle<nsISupports>> mSupportsArray;
// Ensure the worker and the main thread won't race to access |mCleanedUp|.
Mutex mCleanUpLock;
#ifdef DEBUG
// Maybe get rid of this entirely and rely on mCleanedUp
bool mFeatureAdded;
#endif
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PromiseWorkerProxy_h