зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1144487 - Implement AbstractThread. r=mattwoodrow
This commit is contained in:
Родитель
bf4f85a325
Коммит
c64dbd1ed9
|
@ -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',
|
||||
|
|
Загрузка…
Ссылка в новой задаче