Bug 1144487 - Implement AbstractThread. r=mattwoodrow

This commit is contained in:
Bobby Holley 2015-03-13 19:41:12 -07:00
Родитель bf4f85a325
Коммит c64dbd1ed9
5 изменённых файлов: 122 добавлений и 68 удалений

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

@ -0,0 +1,44 @@
/* -*- 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 "AbstractThread.h"
#include "MediaTaskQueue.h"
#include "nsThreadUtils.h"
namespace mozilla {
template<>
nsresult
AbstractThreadImpl<MediaTaskQueue>::Dispatch(already_AddRefed<nsIRunnable> aRunnable)
{
RefPtr<nsIRunnable> r(aRunnable);
return mTarget->ForceDispatch(r);
}
template<>
nsresult
AbstractThreadImpl<nsIThread>::Dispatch(already_AddRefed<nsIRunnable> aRunnable)
{
nsCOMPtr<nsIRunnable> r = aRunnable;
return mTarget->Dispatch(r, NS_DISPATCH_NORMAL);
}
template<>
bool
AbstractThreadImpl<MediaTaskQueue>::IsCurrentThreadIn()
{
return mTarget->IsCurrentThreadIn();
}
template<>
bool
AbstractThreadImpl<nsIThread>::IsCurrentThreadIn()
{
return NS_GetCurrentThread() == mTarget;
}
} // namespace mozilla

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

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#if !defined(AbstractThread_h_)
#define AbstractThread_h_
#include "nscore.h"
#include "nsIRunnable.h"
#include "nsISupportsImpl.h"
#include "nsIThread.h"
#include "nsRefPtr.h"
namespace mozilla {
/*
* We often want to run tasks on a target that guarantees that events will never
* run in parallel. There are various target types that achieve this - namely
* nsIThread and MediaTaskQueue. Note that nsIThreadPool (which implements
* nsIEventTarget) does not have this property, so we do not want to use
* nsIEventTarget for this purpose. This class encapsulates the specifics of
* the structures we might use here and provides a consistent interface.
*
* Use AbstractThread::Create() to instantiate an AbstractThread. Note that
* if you use different types than the ones currently supported (MediaTaskQueue
* and nsIThread), you'll need to implement the relevant guts in
* AbstractThread.cpp to avoid linkage errors.
*/
class AbstractThread
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbstractThread);
virtual nsresult Dispatch(already_AddRefed<nsIRunnable> aRunnable) = 0;
virtual bool IsCurrentThreadIn() = 0;
template<typename TargetType> static AbstractThread* Create(TargetType* aTarget);
protected:
virtual ~AbstractThread() {}
};
template<typename TargetType>
class AbstractThreadImpl : public AbstractThread
{
public:
explicit AbstractThreadImpl(TargetType* aTarget) : mTarget(aTarget) {}
virtual nsresult Dispatch(already_AddRefed<nsIRunnable> aRunnable);
virtual bool IsCurrentThreadIn();
private:
nsRefPtr<TargetType> mTarget;
};
template<typename TargetType>
AbstractThread*
AbstractThread::Create(TargetType* aTarget)
{
return new AbstractThreadImpl<TargetType>(aTarget);
};
} // namespace mozilla
#endif

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

@ -1,41 +0,0 @@
/* -*- 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 "MediaPromise.h"
#include "MediaTaskQueue.h"
#include "nsThreadUtils.h"
namespace mozilla {
namespace detail {
nsresult
DispatchMediaPromiseRunnable(MediaTaskQueue* aTaskQueue, nsIRunnable* aRunnable)
{
return aTaskQueue->ForceDispatch(aRunnable);
}
nsresult
DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnable)
{
return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
}
void
AssertOnThread(MediaTaskQueue* aQueue)
{
MOZ_ASSERT(aQueue->IsCurrentThreadIn());
}
void AssertOnThread(nsIEventTarget* aTarget)
{
nsCOMPtr<nsIThread> targetThread = do_QueryInterface(aTarget);
MOZ_ASSERT(targetThread, "Don't know how to deal with threadpools etc here");
MOZ_ASSERT(NS_GetCurrentThread() == targetThread);
}
}
} // namespace mozilla

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

@ -9,6 +9,8 @@
#include "prlog.h"
#include "AbstractThread.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
@ -23,7 +25,6 @@
#define __func__ __FUNCTION__
#endif
class nsIEventTarget;
namespace mozilla {
extern PRLogModuleInfo* gMediaPromiseLog;
@ -32,19 +33,6 @@ extern PRLogModuleInfo* gMediaPromiseLog;
MOZ_ASSERT(gMediaPromiseLog); \
PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
class MediaTaskQueue;
namespace detail {
nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable);
nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable);
#ifdef DEBUG
void AssertOnThread(MediaTaskQueue* aQueue);
void AssertOnThread(nsIEventTarget* aTarget);
#endif
} // namespace detail
/*
* A promise manages an asynchronous request that may or may not be able to be
* fulfilled immediately. When an API returns a promise, the consumer may attach
@ -218,12 +206,11 @@ protected:
((*aThisVal).*aMethod)();
}
template<typename TargetType, typename ThisType,
typename ResolveMethodType, typename RejectMethodType>
template<typename ThisType, typename ResolveMethodType, typename RejectMethodType>
class ThenValue : public ThenValueBase
{
public:
ThenValue(TargetType* aResponseTarget, ThisType* aThisVal,
ThenValue(AbstractThread* aResponseTarget, ThisType* aThisVal,
ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod,
const char* aCallSite)
: ThenValueBase(aCallSite)
@ -243,8 +230,7 @@ protected:
PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]",
resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite,
runnable.get(), aPromise, this);
nsresult rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable);
unused << rv;
nsresult rv = mResponseTarget->Dispatch(runnable.forget());
// NB: mDisconnected is only supposed to be accessed on the dispatch
// thread. However, we require the consumer to have disconnected any
@ -253,12 +239,13 @@ protected:
// failing involves the target thread being unable to manipulate the
// ThenValue (since it's been disconnected), so it's safe to read here.
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv) || Consumer::mDisconnected);
unused << rv;
}
#ifdef DEBUG
void AssertOnDispatchThread()
{
detail::AssertOnThread(mResponseTarget);
MOZ_ASSERT(mResponseTarget->IsCurrentThreadIn());
}
#else
void AssertOnDispatchThread() {}
@ -312,7 +299,7 @@ protected:
}
private:
nsRefPtr<TargetType> mResponseTarget; // May be released on any thread.
nsRefPtr<AbstractThread> mResponseTarget; // May be released on any thread.
nsRefPtr<ThisType> mThisVal; // Only accessed and refcounted on dispatch thread.
ResolveMethodType mResolveMethod;
RejectMethodType mRejectMethod;
@ -327,10 +314,9 @@ public:
MutexAutoLock lock(mMutex);
MOZ_DIAGNOSTIC_ASSERT(!IsExclusive || !mHaveConsumer);
mHaveConsumer = true;
nsRefPtr<ThenValueBase> thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType,
RejectMethodType>(aResponseTarget, aThisVal,
aResolveMethod, aRejectMethod,
aCallSite);
nsRefPtr<AbstractThread> responseTarget = AbstractThread::Create(aResponseTarget);
nsRefPtr<ThenValueBase> thenValue = new ThenValue<ThisType, ResolveMethodType, RejectMethodType>(
responseTarget, aThisVal, aResolveMethod, aRejectMethod, aCallSite);
PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]",
aCallSite, this, thenValue.get(), aThisVal, (int) IsPending());
if (!IsPending()) {
@ -664,9 +650,10 @@ template<typename PromiseType, typename TargetType>
static nsRefPtr<PromiseType>
ProxyInternal(TargetType* aTarget, MethodCallBase<PromiseType>* aMethodCall, const char* aCallerName)
{
nsRefPtr<AbstractThread> target = AbstractThread::Create(aTarget);
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);
nsresult rv = target->Dispatch(r.forget());
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
unused << rv;
return Move(p);

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

@ -81,6 +81,7 @@ XPIDL_MODULE = 'dom_media'
EXPORTS += [
'AbstractMediaDecoder.h',
'AbstractThread.h',
'AudioBufferUtils.h',
'AudioChannelFormat.h',
'AudioCompactor.h',
@ -161,6 +162,7 @@ EXPORTS.mozilla.dom += [
]
UNIFIED_SOURCES += [
'AbstractThread.cpp',
'AudioChannelFormat.cpp',
'AudioCompactor.cpp',
'AudioSegment.cpp',
@ -183,7 +185,6 @@ UNIFIED_SOURCES += [
'MediaDecoderStateMachine.cpp',
'MediaDevices.cpp',
'MediaManager.cpp',
'MediaPromise.cpp',
'MediaRecorder.cpp',
'MediaResource.cpp',
'MediaShutdownManager.cpp',