Bug 1129877 - Separate the creator and consumer APIs for MediaPromise. v2 r=mattwoodrow

This causes the buggy code that caused the crash to fail to compile.
This commit is contained in:
Bobby Holley 2015-02-09 18:47:49 -08:00
Родитель 411d2a22af
Коммит 4b06c284a3
1 изменённых файлов: 57 добавлений и 35 удалений

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

@ -62,6 +62,10 @@ public:
typedef RejectValueT RejectValueType;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPromise)
protected:
// MediaPromise is the public type, and never constructed directly. Construct
// a MediaPromise::Private, defined below.
explicit MediaPromise(const char* aCreationSite)
: mCreationSite(aCreationSite)
, mMutex("MediaPromise Mutex")
@ -70,20 +74,30 @@ public:
PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this);
}
public:
// MediaPromise::Private allows us to separate the public interface (upon which
// consumers of the promise may invoke methods like Then()) from the private
// interface (upon which the creator of the promise may invoke Resolve() or
// Reject()). APIs should create and store a MediaPromise::Private (usually
// via a MediaPromiseHolder), and return a MediaPromise to consumers.
//
// NB: We can include the definition of this class inline once B2G ICS is gone.
class Private;
static nsRefPtr<MediaPromise>
CreateAndResolve(ResolveValueType aResolveValue, const char* aResolveSite)
{
nsRefPtr<MediaPromise> p = new MediaPromise(aResolveSite);
nsRefPtr<typename MediaPromise::Private> p = new MediaPromise::Private(aResolveSite);
p->Resolve(aResolveValue, aResolveSite);
return p;
return Move(p);
}
static nsRefPtr<MediaPromise>
CreateAndReject(RejectValueType aRejectValue, const char* aRejectSite)
{
nsRefPtr<MediaPromise> p = new MediaPromise(aRejectSite);
nsRefPtr<typename MediaPromise::Private> p = new MediaPromise::Private(aRejectSite);
p->Reject(aRejectValue, aRejectSite);
return p;
return Move(p);
}
class Consumer
@ -328,12 +342,12 @@ public:
return;
}
void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite)
void ChainTo(already_AddRefed<Private> aChainedPromise, const char* aCallSite)
{
MutexAutoLock lock(mMutex);
MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveConsumer);
mHaveConsumer = true;
nsRefPtr<MediaPromise> chainedPromise = aChainedPromise;
nsRefPtr<Private> chainedPromise = aChainedPromise;
PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]",
aCallSite, this, chainedPromise.get(), (int) IsPending());
if (!IsPending()) {
@ -343,24 +357,6 @@ public:
}
}
void Resolve(ResolveValueType aResolveValue, const char* aResolveSite)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
mResolveValue.emplace(aResolveValue);
DispatchAll();
}
void Reject(RejectValueType aRejectValue, const char* aRejectSite)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
mRejectValue.emplace(aRejectValue);
DispatchAll();
}
protected:
bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
void DispatchAll()
@ -377,7 +373,7 @@ protected:
mChainedPromises.Clear();
}
void ForwardTo(MediaPromise* aOther)
void ForwardTo(Private* aOther)
{
MOZ_ASSERT(!IsPending());
if (mResolveValue.isSome()) {
@ -400,10 +396,36 @@ protected:
Maybe<ResolveValueType> mResolveValue;
Maybe<RejectValueType> mRejectValue;
nsTArray<nsRefPtr<ThenValueBase>> mThenValues;
nsTArray<nsRefPtr<MediaPromise>> mChainedPromises;
nsTArray<nsRefPtr<Private>> mChainedPromises;
bool mHaveConsumer;
};
template<typename ResolveValueT, typename RejectValueT, bool IsExclusive>
class MediaPromise<ResolveValueT, RejectValueT, IsExclusive>::Private
: public MediaPromise<ResolveValueT, RejectValueT, IsExclusive>
{
public:
explicit Private(const char* aCreationSite) : MediaPromise(aCreationSite) {}
void Resolve(ResolveValueT aResolveValue, const char* aResolveSite)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite);
mResolveValue.emplace(aResolveValue);
DispatchAll();
}
void Reject(RejectValueT aRejectValue, const char* aRejectSite)
{
MutexAutoLock lock(mMutex);
MOZ_ASSERT(IsPending());
PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite);
mRejectValue.emplace(aRejectValue);
DispatchAll();
}
};
/*
* Class to encapsulate a promise for a particular role. Use this as the member
* variable for a class whose method returns a promise.
@ -422,9 +444,9 @@ public:
mMonitor->AssertCurrentThreadOwns();
}
if (!mPromise) {
mPromise = new PromiseType(aMethodName);
mPromise = new (typename PromiseType::Private)(aMethodName);
}
nsRefPtr<PromiseType> p = mPromise;
nsRefPtr<PromiseType> p = mPromise.get();
return p.forget();
}
@ -439,13 +461,13 @@ public:
return !mPromise;
}
already_AddRefed<PromiseType> Steal()
already_AddRefed<typename PromiseType::Private> Steal()
{
if (mMonitor) {
mMonitor->AssertCurrentThreadOwns();
}
nsRefPtr<PromiseType> p = mPromise;
nsRefPtr<typename PromiseType::Private> p = mPromise;
mPromise = nullptr;
return p.forget();
}
@ -490,7 +512,7 @@ public:
private:
Monitor* mMonitor;
nsRefPtr<PromiseType> mPromise;
nsRefPtr<typename PromiseType::Private> mPromise;
};
/*
@ -590,7 +612,7 @@ template<typename PromiseType>
class ProxyRunnable : public nsRunnable
{
public:
ProxyRunnable(PromiseType* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
ProxyRunnable(typename PromiseType::Private* aProxyPromise, MethodCallBase<PromiseType>* aMethodCall)
: mProxyPromise(aProxyPromise), mMethodCall(aMethodCall) {}
NS_IMETHODIMP Run()
@ -602,7 +624,7 @@ public:
}
private:
nsRefPtr<PromiseType> mProxyPromise;
nsRefPtr<typename PromiseType::Private> mProxyPromise;
nsAutoPtr<MethodCallBase<PromiseType>> mMethodCall;
};
@ -610,11 +632,11 @@ template<typename PromiseType, typename TargetType>
static nsRefPtr<PromiseType>
ProxyInternal(TargetType* aTarget, MethodCallBase<PromiseType>* aMethodCall, const char* aCallerName)
{
nsRefPtr<PromiseType> p = new PromiseType(aCallerName);
nsRefPtr<typename PromiseType::Private> p = new (typename PromiseType::Private)(aCallerName);
nsRefPtr<ProxyRunnable<PromiseType>> r = new ProxyRunnable<PromiseType>(p, aMethodCall);
nsresult rv = detail::DispatchMediaPromiseRunnable(aTarget, r);
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
return p;
return Move(p);
}
} // namespace detail