import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1161590 - Ignore blocklist preference in nightly and aurora. r=jrmuizelaar (47ec8bee6)
- Bug 1162299 - Distinguish between all features and unrecognized feature. r=kats (e9705844f)
- Add compositor, layers, and rendering info to nsIGfxInfo. (bug 1179051 part 5, r=mattwoodrow) (b4e6da05f)
- Bug 1186002. Avoid testing for recreate on broken drivers. r=dvander (10506f4f2)
- Bug 1156407 - part 1 - use static_assert instead of PR_STATIC_ASSERT; r=mccr8 (ff53e05ba)
- Bug 1156407 - part 2 - make CALLBACK_TYPE enum a private implementation detail of nsTimerImpl; r=mccr8 (de0cc6527)
- Bug 1156407 - part 3 - get rid of NS_NewTimer; r=mccr8 (c598b96e0)
- Bug 1095433: fix the race condition in the Task Tracer that crashes processes forked from Nuwa. r=tlee (cffe07827)
- Bug 1113562 - Expected delay time of tasks should not be the latency of those kind. r=sinker (f422ae04e)
- Bug 1155059: Patch 1&2 - Convert Dispatch() and friends to already_AddRefed<> r=froydnj (2ca9850af)
- Bug 1155059: Patch 4 - invoke NS_ASSERTION if DispatchToMainThread fails to get MainThread ptr r=froydnj (651903c22)
- Bug 1155059: Patch 3&7 - fix leaks in Promise, ConsoleService and JS Finalize r=froydnj (b57cb08d9)
- Bug 1155059: Patch 5 - clean up ServiceWorkers and avoid leaks r=nikhil (666245af8)
- Bug 1155059: Patch 6 - fix problems with gfxFontInfoLoader shutdown sequence r=jdaggett (332e8bd76)
- Bug 1155059: Patch 8 - Don't leak runnables when MediaCache/FileBlockCache get shut down after XPCOM is in final shutdown r=cpearce (18f36fa25)
- Bug 1155059: Patch 9 - Modify DataChannel.cpp to use updated API r=froydnj (c5415703c)
- Bug 1176446 - TextureClientD3D11 should take into account the layer backend when allocating a surface. r=bas (3c1b59296)
- Bug 1176363 - Part 1: Stop using DrawTargets off the main thread. r=mattwoodrow (624e8107a)
- Bug 1176363 - Part 2: Allow mapping of SourceSurfaceRawData from multiple threads. r=bas (38c8363cf)
- Fix d3d11 texture sharing checks being preserved across device resets. (bug 1183910 part 6, r=mattwoodrow) (658121c50)
- Clear the blur cache after device resets. (bug 1188032, r=bas) (c362b2ec6)
This commit is contained in:
2021-06-17 09:58:49 +08:00
parent ed0b673484
commit 14c77e53f5
74 changed files with 1487 additions and 586 deletions
+16 -4
View File
@@ -80,6 +80,10 @@ public:
NS_DECL_NSIREQUEST
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIEVENTTARGET
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
explicit WebSocketImpl(WebSocket* aWebSocket)
: mWebSocket(aWebSocket)
@@ -2667,7 +2671,7 @@ class WorkerRunnableDispatcher final : public WorkerRunnable
public:
WorkerRunnableDispatcher(WebSocketImpl* aImpl, WorkerPrivate* aWorkerPrivate,
nsIRunnable* aEvent)
already_AddRefed<nsIRunnable>&& aEvent)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
, mWebSocketImpl(aImpl)
, mEvent(aEvent)
@@ -2712,11 +2716,19 @@ private:
} // anonymous namespace
NS_IMETHODIMP
WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
WebSocketImpl::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event_ref(aEvent);
// If the target is the main-thread we can just dispatch the runnable.
if (mIsMainThread) {
return NS_DispatchToMainThread(aEvent);
return NS_DispatchToMainThread(event_ref.forget());
}
MutexAutoLock lock(mMutex);
@@ -2733,7 +2745,7 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
// runnable.
nsRefPtr<WorkerRunnableDispatcher> event =
new WorkerRunnableDispatcher(this, mWorkerPrivate, aEvent);
new WorkerRunnableDispatcher(this, mWorkerPrivate, event_ref.forget());
if (!event->Dispatch(nullptr)) {
return NS_ERROR_FAILURE;
+10 -3
View File
@@ -74,9 +74,16 @@ void FileBlockCache::Close()
// opening more streams, while the media cache is shutting down and
// releasing memory etc! Also note we close mFD in the destructor so
// as to not disturb any IO that's currently running.
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread);
mThread = nullptr;
NS_DispatchToMainThread(event);
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (mainThread) {
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mThread);
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
} else {
// we're on Mainthread already, *and* the event queues are already
// shut down, so no events should occur - certainly not creations of
// new streams.
mThread->Shutdown();
}
}
}
+8 -2
View File
@@ -1409,8 +1409,14 @@ MediaCache::QueueUpdate()
if (mUpdateQueued)
return;
mUpdateQueued = true;
nsCOMPtr<nsIRunnable> event = new UpdateEvent();
NS_DispatchToMainThread(event);
// XXX MediaCache does updates when decoders are still running at
// shutdown and get freed in the final cycle-collector cleanup. So
// don't leak a runnable in that case.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (mainThread) {
nsCOMPtr<nsIRunnable> event = new UpdateEvent();
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
}
}
void
+10 -10
View File
@@ -808,19 +808,19 @@ void
MediaOperationTask::ReturnCallbackError(nsresult rv, const char* errorLog)
{
MM_LOG(("%s , rv=%d", errorLog, rv));
NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
mOnTracksAvailableCallback.forget()));
NS_DispatchToMainThread(do_AddRef(new ReleaseMediaOperationResource(mStream.forget(),
mOnTracksAvailableCallback.forget())));
nsString log;
log.AssignASCII(errorLog);
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess;
nsRefPtr<MediaMgrError> error = new MediaMgrError(
NS_LITERAL_STRING("InternalError"), log);
NS_DispatchToMainThread(
NS_DispatchToMainThread(do_AddRef(
new ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>(onSuccess,
mOnFailure,
*error,
mWindowID));
mWindowID)));
}
/**
@@ -1207,9 +1207,9 @@ public:
MOZ_ASSERT(!mOnSuccess);
MOZ_ASSERT(!mOnFailure);
NS_DispatchToMainThread(runnable);
NS_DispatchToMainThread(runnable.forget());
// Do after ErrorCallbackRunnable Run()s, as it checks active window list
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener));
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, mListener)));
}
void
@@ -1379,10 +1379,10 @@ public:
peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
}
NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
NS_DispatchToMainThread(do_AddRef(new GetUserMediaStreamRunnable(
mOnSuccess, mOnFailure, mWindowID, mListener, aAudioSource, aVideoSource,
peerIdentity
));
)));
MOZ_ASSERT(!mOnSuccess);
MOZ_ASSERT(!mOnFailure);
@@ -2233,7 +2233,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
mozilla::ipc::BackgroundChild::CloseForCurrentThread();
NS_DispatchToMainThread(mReply);
NS_DispatchToMainThread(mReply.forget());
}
nsRefPtr<nsRunnable> mReply;
};
@@ -2692,7 +2692,7 @@ GetUserMediaCallbackMediaStreamListener::NotifyFinished(MediaStreamGraph* aGraph
{
mFinished = true;
Invalidate(); // we know it's been activated
NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, this));
NS_DispatchToMainThread(do_AddRef(new GetUserMediaListenerRemove(mWindowID, this)));
}
// Called from the MediaStreamGraph thread
+13 -1
View File
@@ -45,7 +45,19 @@ public:
// Forward behaviour to wrapped thread pool implementation.
NS_FORWARD_SAFE_NSITHREADPOOL(mPool);
NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
// See bug 1155059 - MSVC forces us to not declare Dispatch normally in idl
// NS_FORWARD_SAFE_NSIEVENTTARGET(mEventTarget);
nsresult Dispatch(nsIRunnable *event, uint32_t flags) { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(event, flags); }
NS_IMETHOD DispatchFromScript(nsIRunnable *event, uint32_t flags) override {
return Dispatch(event, flags);
}
NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags) override
{ return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(Move(event), flags); }
NS_IMETHOD IsOnCurrentThread(bool *_retval) override { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->IsOnCurrentThread(_retval); }
// Creates necessary statics. Called once at startup.
static void InitStatics();
+12 -5
View File
@@ -1214,10 +1214,17 @@ Promise::MaybeReportRejected()
// Now post an event to do the real reporting async
// Since Promises preserve their wrapper, it is essential to nsRefPtr<> the
// AsyncErrorReporter, otherwise if the call to DispatchToMainThread fails, it
// will leak. See Bug 958684.
nsRefPtr<AsyncErrorReporter> r =
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
NS_DispatchToMainThread(r);
// will leak. See Bug 958684. So... don't use DispatchToMainThread()
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (NS_WARN_IF(!mainThread)) {
// Would prefer NS_ASSERTION, but that causes failure in xpcshell tests
NS_WARNING("!!! Trying to report rejected Promise after MainThread shutdown");
}
if (mainThread) {
nsRefPtr<AsyncErrorReporter> r =
new AsyncErrorReporter(CycleCollectedJSRuntime::Get()->Runtime(), xpcReport);
mainThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
}
#endif // defined(DOM_PROMISE_DEPRECATED_REPORTING)
@@ -1634,7 +1641,7 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
if (!runnable->Dispatch(aCx)) {
nsRefPtr<WorkerControlRunnable> runnable =
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, this);
mWorkerPrivate->DispatchControlRunnable(runnable);
mWorkerPrivate->DispatchControlRunnable(runnable.forget());
}
}
+1 -1
View File
@@ -1724,7 +1724,7 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
nsCOMPtr<nsIRunnable> runnable =
new WorkerThreadPrimaryRunnable(aWorkerPrivate, thread, JS_GetParentRuntime(aCx));
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable))) {
if (NS_FAILED(thread->DispatchPrimaryRunnable(friendKey, runnable.forget()))) {
UnregisterWorker(aCx, aWorkerPrivate);
JS_ReportError(aCx, "Could not dispatch to thread!");
return false;
+6 -1
View File
@@ -325,7 +325,10 @@ public:
return false;
}
NS_SUCCEEDED(NS_DispatchToMainThread(this));
nsCOMPtr<nsIRunnable> that(this);
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(this)))) {
NS_ASSERTION(false, "Failed to dispatch update back to MainThread in ServiceWorker");
}
return true;
}
@@ -815,6 +818,8 @@ ServiceWorkerRegistrationWorkerThread::Update()
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
// XXX: this pattern guarantees we won't know which thread UpdateRunnable
// will die on (here or MainThread)
nsRefPtr<UpdateRunnable> r = new UpdateRunnable(worker, mScope);
r->Dispatch();
}
+42 -24
View File
@@ -1847,7 +1847,14 @@ public:
protected:
NS_IMETHOD
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
return Dispatch(runnable.forget(), aFlags);
}
NS_IMETHOD
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override
{
// This should only happen on the timer thread.
MOZ_ASSERT(!NS_IsMainThread());
@@ -1858,7 +1865,8 @@ protected:
// Run the runnable we're given now (should just call DummyCallback()),
// otherwise the timer thread will leak it... If we run this after
// dispatch running the event can race against resetting the timer.
aRunnable->Run();
nsCOMPtr<nsIRunnable> runnable(aRunnable);
runnable->Run();
// This can fail if we're racing to terminate or cancel, should be handled
// by the terminate or cancel code.
@@ -2851,10 +2859,11 @@ WorkerPrivateParent<Derived>::WrapObject(JSContext* aCx, JS::Handle<JSObject*> a
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
WorkerPrivateParent<Derived>::DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable,
nsIEventTarget* aSyncLoopTarget)
{
// May be called on any thread!
nsRefPtr<WorkerRunnable> runnable(aRunnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@@ -2865,7 +2874,7 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
if (!self->mThread) {
if (ParentStatus() == Pending || self->mStatus == Pending) {
mPreStartRunnables.AppendElement(aRunnable);
mPreStartRunnables.AppendElement(runnable);
return NS_OK;
}
@@ -2883,9 +2892,9 @@ WorkerPrivateParent<Derived>::DispatchPrivate(WorkerRunnable* aRunnable,
nsresult rv;
if (aSyncLoopTarget) {
rv = aSyncLoopTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL);
rv = aSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
} else {
rv = self->mThread->Dispatch(WorkerThreadFriendKey(), aRunnable);
rv = self->mThread->DispatchAnyThread(WorkerThreadFriendKey(), runnable.forget());
}
if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -2935,13 +2944,11 @@ WorkerPrivateParent<Derived>::DisableDebugger()
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchControlRunnable(
WorkerControlRunnable* aWorkerControlRunnable)
already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aWorkerControlRunnable);
nsRefPtr<WorkerControlRunnable> runnable = aWorkerControlRunnable;
nsRefPtr<WorkerControlRunnable> runnable(aWorkerControlRunnable);
MOZ_ASSERT(runnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@@ -2975,13 +2982,13 @@ WorkerPrivateParent<Derived>::DispatchControlRunnable(
template <class Derived>
nsresult
WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
WorkerRunnable *aDebuggerRunnable)
already_AddRefed<WorkerRunnable>&& aDebuggerRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aDebuggerRunnable);
nsRefPtr<WorkerRunnable> runnable(aDebuggerRunnable);
nsRefPtr<WorkerRunnable> runnable = aDebuggerRunnable;
MOZ_ASSERT(runnable);
WorkerPrivate* self = ParentAsWorkerPrivate();
@@ -3005,19 +3012,20 @@ WorkerPrivateParent<Derived>::DispatchDebuggerRunnable(
template <class Derived>
already_AddRefed<WorkerRunnable>
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable)
WorkerPrivateParent<Derived>::MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable)
{
// May be called on any thread!
MOZ_ASSERT(aRunnable);
nsCOMPtr<nsIRunnable> runnable(aRunnable);
MOZ_ASSERT(runnable);
nsRefPtr<WorkerRunnable> workerRunnable =
WorkerRunnable::FromRunnable(aRunnable);
WorkerRunnable::FromRunnable(runnable);
if (workerRunnable) {
return workerRunnable.forget();
}
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
if (!cancelable) {
MOZ_CRASH("All runnables destined for a worker thread must be cancelable!");
}
@@ -5408,7 +5416,7 @@ WorkerPrivate::RunBeforeNextEvent(nsIRunnable* aRunnable)
// to run.
if (mPreemptingRunnableInfos.Length() == 1 && !NS_HasPendingEvents(mThread)) {
nsRefPtr<DummyRunnable> dummyRunnable = new DummyRunnable(this);
if (NS_FAILED(Dispatch(dummyRunnable))) {
if (NS_FAILED(Dispatch(dummyRunnable.forget()))) {
NS_WARNING("RunBeforeNextEvent called after the thread is shutting "
"down!");
mPreemptingRunnableInfos.Clear();
@@ -7102,7 +7110,7 @@ WorkerPrivate::SetThread(WorkerThread* aThread)
if (!mPreStartRunnables.IsEmpty()) {
for (uint32_t index = 0; index < mPreStartRunnables.Length(); index++) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
mThread->Dispatch(friendKey, mPreStartRunnables[index])));
mThread->DispatchAnyThread(friendKey, mPreStartRunnables[index].forget())));
}
mPreStartRunnables.Clear();
}
@@ -7359,9 +7367,19 @@ NS_INTERFACE_MAP_END
template <class Derived>
NS_IMETHODIMP
WorkerPrivateParent<Derived>::
EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
EventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aRunnable);
return Dispatch(event.forget(), aFlags);
}
template <class Derived>
NS_IMETHODIMP
WorkerPrivateParent<Derived>::
EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
{
// May be called on any thread!
nsCOMPtr<nsIRunnable> event(aRunnable);
// Workers only support asynchronous dispatch for now.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@@ -7378,12 +7396,12 @@ EventTarget::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
return NS_ERROR_UNEXPECTED;
}
if (aRunnable) {
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
if (event) {
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(event.forget());
}
nsresult rv =
mWorkerPrivate->DispatchPrivate(workerRunnable, mNestedEventTarget);
mWorkerPrivate->DispatchPrivate(workerRunnable.forget(), mNestedEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+6 -6
View File
@@ -232,7 +232,7 @@ private:
ErrorResult& aRv);
nsresult
DispatchPrivate(WorkerRunnable* aRunnable, nsIEventTarget* aSyncLoopTarget);
DispatchPrivate(already_AddRefed<WorkerRunnable>&& aRunnable, nsIEventTarget* aSyncLoopTarget);
public:
virtual JSObject*
@@ -257,19 +257,19 @@ public:
}
nsresult
Dispatch(WorkerRunnable* aRunnable)
Dispatch(already_AddRefed<WorkerRunnable>&& aRunnable)
{
return DispatchPrivate(aRunnable, nullptr);
return DispatchPrivate(Move(aRunnable), nullptr);
}
nsresult
DispatchControlRunnable(WorkerControlRunnable* aWorkerControlRunnable);
DispatchControlRunnable(already_AddRefed<WorkerControlRunnable>&& aWorkerControlRunnable);
nsresult
DispatchDebuggerRunnable(WorkerRunnable* aDebuggerRunnable);
DispatchDebuggerRunnable(already_AddRefed<WorkerRunnable>&& aDebuggerRunnable);
already_AddRefed<WorkerRunnable>
MaybeWrapAsWorkerRunnable(nsIRunnable* aRunnable);
MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>&& aRunnable);
already_AddRefed<nsIEventTarget>
GetEventTarget();
+17 -10
View File
@@ -136,25 +136,27 @@ WorkerRunnable::Dispatch(JSContext* aCx)
bool
WorkerRunnable::DispatchInternal()
{
nsRefPtr<WorkerRunnable> runnable(this);
if (mBehavior == WorkerThreadModifyBusyCount ||
mBehavior == WorkerThreadUnchangedBusyCount) {
if (IsDebuggerRunnable()) {
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(this));
return NS_SUCCEEDED(mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
} else {
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(this));
return NS_SUCCEEDED(mWorkerPrivate->Dispatch(runnable.forget()));
}
}
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->Dispatch(this));
return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@@ -417,7 +419,8 @@ bool
WorkerSyncRunnable::DispatchInternal()
{
if (mSyncLoopTarget) {
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
nsRefPtr<WorkerSyncRunnable> runnable(this);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
return WorkerRunnable::DispatchInternal();
@@ -477,7 +480,8 @@ StopSyncLoopRunnable::DispatchInternal()
{
MOZ_ASSERT(mSyncLoopTarget);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(this, NS_DISPATCH_NORMAL));
nsRefPtr<StopSyncLoopRunnable> runnable(this);
return NS_SUCCEEDED(mSyncLoopTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@@ -503,18 +507,20 @@ WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
bool
WorkerControlRunnable::DispatchInternal()
{
nsRefPtr<WorkerControlRunnable> runnable(this);
if (mBehavior == WorkerThreadUnchangedBusyCount) {
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(this));
return NS_SUCCEEDED(mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
}
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
return NS_SUCCEEDED(parent->DispatchControlRunnable(this));
return NS_SUCCEEDED(parent->DispatchControlRunnable(runnable.forget()));
}
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
return NS_SUCCEEDED(mainThread->Dispatch(this, NS_DISPATCH_NORMAL));
return NS_SUCCEEDED(mainThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL));
}
void
@@ -545,8 +551,9 @@ WorkerMainThreadRunnable::Dispatch(JSContext* aCx)
AutoSyncLoopHolder syncLoop(mWorkerPrivate);
mSyncLoopTarget = syncLoop.EventTarget();
nsRefPtr<WorkerMainThreadRunnable> runnable(this);
if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL))) {
JS_ReportError(aCx, "Failed to dispatch to main thread!");
return false;
}
+25 -18
View File
@@ -139,11 +139,13 @@ WorkerThread::SetWorker(const WorkerThreadFriendKey& /* aKey */,
nsresult
WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
nsIRunnable* aRunnable)
already_AddRefed<nsIRunnable>&& aRunnable)
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
#ifdef DEBUG
MOZ_ASSERT(PR_GetCurrentThread() != mThread);
MOZ_ASSERT(aRunnable);
MOZ_ASSERT(runnable);
{
MutexAutoLock lock(mLock);
@@ -152,7 +154,7 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
}
#endif
nsresult rv = nsThread::Dispatch(aRunnable, NS_DISPATCH_NORMAL);
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -161,8 +163,8 @@ WorkerThread::DispatchPrimaryRunnable(const WorkerThreadFriendKey& /* aKey */,
}
nsresult
WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
WorkerRunnable* aWorkerRunnable)
WorkerThread::DispatchAnyThread(const WorkerThreadFriendKey& /* aKey */,
already_AddRefed<WorkerRunnable>&& aWorkerRunnable)
{
// May be called on any thread!
@@ -181,8 +183,9 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
}
}
#endif
nsCOMPtr<nsIRunnable> runnable(aWorkerRunnable);
nsresult rv = nsThread::Dispatch(aWorkerRunnable, NS_DISPATCH_NORMAL);
nsresult rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -197,9 +200,17 @@ WorkerThread::Dispatch(const WorkerThreadFriendKey& /* aKey */,
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThread, nsThread)
NS_IMETHODIMP
WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
WorkerThread::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> runnable(aRunnable);
return Dispatch(runnable.forget(), aFlags);
}
NS_IMETHODIMP
WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags)
{
// May be called on any thread!
nsCOMPtr<nsIRunnable> runnable(aRunnable); // in case we exit early
// Workers only support asynchronous dispatch.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@@ -209,8 +220,8 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
const bool onWorkerThread = PR_GetCurrentThread() == mThread;
#ifdef DEBUG
if (aRunnable && !onWorkerThread) {
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
if (runnable && !onWorkerThread) {
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(runnable);
{
MutexAutoLock lock(mLock);
@@ -245,18 +256,14 @@ WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
}
}
nsIRunnable* runnableToDispatch;
nsRefPtr<WorkerRunnable> workerRunnable;
if (aRunnable && onWorkerThread) {
workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
runnableToDispatch = workerRunnable;
nsresult rv;
if (runnable && onWorkerThread) {
nsRefPtr<WorkerRunnable> workerRunnable = workerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
rv = nsThread::Dispatch(workerRunnable.forget(), NS_DISPATCH_NORMAL);
} else {
runnableToDispatch = aRunnable;
rv = nsThread::Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
}
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
if (!onWorkerThread && workerPrivate) {
// We need to wake the worker thread if we're not already on the right
// thread and the dispatch succeeded.
+7 -4
View File
@@ -66,11 +66,11 @@ public:
nsresult
DispatchPrimaryRunnable(const WorkerThreadFriendKey& aKey,
nsIRunnable* aRunnable);
already_AddRefed<nsIRunnable>&& aRunnable);
nsresult
Dispatch(const WorkerThreadFriendKey& aKey,
WorkerRunnable* aWorkerRunnable);
DispatchAnyThread(const WorkerThreadFriendKey& aKey,
already_AddRefed<WorkerRunnable>&& aWorkerRunnable);
uint32_t
RecursionDepth(const WorkerThreadFriendKey& aKey) const;
@@ -84,7 +84,10 @@ private:
// This should only be called by consumers that have an
// nsIEventTarget/nsIThread pointer.
NS_IMETHOD
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) override;
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
NS_IMETHOD
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
};
} // namespace workers
+61 -3
View File
@@ -8,6 +8,7 @@
#include "2D.h"
#include "Tools.h"
#include "mozilla/Atomics.h"
namespace mozilla {
namespace gfx {
@@ -16,8 +17,14 @@ class SourceSurfaceRawData : public DataSourceSurface
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRawData)
SourceSurfaceRawData() {}
~SourceSurfaceRawData() { if(mOwnData) delete [] mRawData; }
SourceSurfaceRawData()
: mMapCount(0)
{}
~SourceSurfaceRawData()
{
if(mOwnData) delete [] mRawData;
MOZ_ASSERT(mMapCount == 0);
}
virtual uint8_t *GetData() { return mRawData; }
virtual int32_t Stride() { return mStride; }
@@ -34,11 +41,38 @@ public:
virtual void GuaranteePersistance();
// Althought Map (and Moz2D in general) isn't normally threadsafe,
// we want to allow it for SourceSurfaceRawData since it should
// always be fine (for reading at least).
//
// This is the same as the base class implementation except using
// mMapCount instead of mIsMapped since that breaks for multithread.
//
// Once mfbt supports Monitors we should implement proper read/write
// locking to prevent write races.
virtual bool Map(MapType, MappedSurface *aMappedSurface) override
{
aMappedSurface->mData = GetData();
aMappedSurface->mStride = Stride();
bool success = !!aMappedSurface->mData;
if (success) {
mMapCount++;
}
return success;
}
virtual void Unmap() override
{
mMapCount--;
MOZ_ASSERT(mMapCount >= 0);
}
private:
uint8_t *mRawData;
int32_t mStride;
SurfaceFormat mFormat;
IntSize mSize;
Atomic<int32_t> mMapCount;
bool mOwnData;
};
@@ -46,7 +80,13 @@ class SourceSurfaceAlignedRawData : public DataSourceSurface
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceAlignedRawData)
SourceSurfaceAlignedRawData() {}
SourceSurfaceAlignedRawData()
: mMapCount(0)
{}
~SourceSurfaceAlignedRawData()
{
MOZ_ASSERT(mMapCount == 0);
}
virtual uint8_t *GetData() { return mArray; }
virtual int32_t Stride() { return mStride; }
@@ -63,11 +103,29 @@ public:
int32_t aStride,
bool aZero);
virtual bool Map(MapType, MappedSurface *aMappedSurface) override
{
aMappedSurface->mData = GetData();
aMappedSurface->mStride = Stride();
bool success = !!aMappedSurface->mData;
if (success) {
mMapCount++;
}
return success;
}
virtual void Unmap() override
{
mMapCount--;
MOZ_ASSERT(mMapCount >= 0);
}
private:
AlignedArray<uint8_t> mArray;
int32_t mStride;
SurfaceFormat mFormat;
IntSize mSize;
Atomic<int32_t> mMapCount;
};
} // namespace gfx
+7 -10
View File
@@ -578,20 +578,17 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
if (!textureClient) {
return nullptr;
}
MOZ_ASSERT(textureClient->CanExposeDrawTarget());
if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
return nullptr;
}
TextureClientAutoUnlock autoUnolck(textureClient);
{
// We must not keep a reference to the DrawTarget after it has been unlocked.
DrawTarget* dt = textureClient->BorrowDrawTarget();
if (!dt) {
return nullptr;
}
dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
}
TextureClientAutoUnlock autoUnlock(textureClient);
RefPtr<DataSourceSurface> dataSurf = surface->GetDataSurface();
textureClient->UpdateFromSurface(dataSurf);
textureClient->SyncWithObject(forwarder->GetSyncObject());
mTextureClients.Put(forwarder->GetSerial(), textureClient);
return textureClient;
+19
View File
@@ -56,6 +56,25 @@ TextureClientDIB::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientDIB::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && IsAllocated());
nsRefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface();
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(imgSurf->Data() + imgSurf->Stride() * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
}
TextureClientMemoryDIB::TextureClientMemoryDIB(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
+2
View File
@@ -34,6 +34,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool HasInternalBuffer() const override { return true; }
protected:
+15
View File
@@ -150,3 +150,18 @@ TextureClientX11::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientX11::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(CanExposeDrawTarget());
DrawTarget* dt = BorrowDrawTarget();
if (!dt) {
gfxCriticalError() << "Failed to borrow drawtarget for TextureClientX11::UpdateFromSurface";
return;
}
dt->CopySurface(aSurface, IntRect(IntPoint(), aSurface->GetSize()), IntPoint());
}
+2
View File
@@ -43,6 +43,8 @@ class TextureClientX11 : public TextureClient
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual gfx::SurfaceFormat GetFormat() const override { return mFormat; }
virtual bool HasInternalBuffer() const override { return false; }
+32 -2
View File
@@ -357,7 +357,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
aMoz2DBackend == gfx::BackendType::CAIRO &&
aAllocator->IsSameProcess() &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize) {
aSize.height <= maxTextureSize &&
NS_IsMainThread()) {
if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
texture = new TextureClientD3D9(aAllocator, aFormat, aTextureFlags);
}
@@ -365,7 +366,8 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator,
if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
aAllocator->IsSameProcess() &&
aMoz2DBackend == gfx::BackendType::CAIRO) {
aMoz2DBackend == gfx::BackendType::CAIRO &&
NS_IsMainThread()) {
if (aAllocator->IsSameProcess()) {
texture = new TextureClientMemoryDIB(aAllocator, aFormat, aTextureFlags);
} else {
@@ -813,6 +815,7 @@ gfx::DrawTarget*
BufferTextureClient::BorrowDrawTarget()
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mLocked, "BorrowDrawTarget should be called on locked textures only");
if (!mLocked) {
return nullptr;
@@ -838,6 +841,33 @@ BufferTextureClient::BorrowDrawTarget()
return mDrawTarget;
}
void
BufferTextureClient::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
ImageDataSerializer serializer(GetBuffer(), GetBufferSize());
RefPtr<DataSourceSurface> surface = serializer.GetAsSurface();
if (surface->GetSize() != aSurface->GetSize() || surface->GetFormat() != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
DataSourceSurface::MappedSurface sourceMap;
DataSourceSurface::MappedSurface destMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
surface->Map(DataSourceSurface::WRITE, &destMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(destMap.mData + destMap.mStride * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
surface->Unmap();
}
bool
BufferTextureClient::Lock(OpenMode aMode)
{
+9
View File
@@ -243,6 +243,7 @@ public:
/**
* Returns a DrawTarget to draw into the TextureClient.
* This function should never be called when not on the main thread!
*
* This must never be called on a TextureClient that is not sucessfully locked.
* When called several times within one Lock/Unlock pair, this method should
@@ -268,6 +269,12 @@ public:
*/
virtual gfx::DrawTarget* BorrowDrawTarget() { return nullptr; }
/**
* This function can be used to update the contents of the TextureClient
* off the main thread.
*/
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) { MOZ_CRASH(); }
// TextureClients that can expose a DrawTarget should override this method.
virtual gfx::SurfaceFormat GetFormat() const
{
@@ -586,6 +593,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
+85 -23
View File
@@ -244,7 +244,8 @@ TextureClientD3D11::CreateSimilar(TextureFlags aFlags,
void
TextureClientD3D11::SyncWithObject(SyncObject* aSyncObject)
{
if (!aSyncObject) {
if (!aSyncObject || !NS_IsMainThread()) {
// When off the main thread we sync using a keyed mutex per texture.
return;
}
@@ -278,33 +279,35 @@ TextureClientD3D11::Lock(OpenMode aMode)
return false;
}
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
if (NS_IsMainThread()) {
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
}
}
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return true;
@@ -327,7 +330,7 @@ TextureClientD3D11::Unlock()
mDrawTarget->Flush();
}
if (mReadbackSink && mTexture10) {
if (NS_IsMainThread() && mReadbackSink && mTexture10) {
ID3D10Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D10Device();
D3D10_TEXTURE2D_DESC desc;
@@ -363,6 +366,7 @@ DrawTarget*
TextureClientD3D11::BorrowDrawTarget()
{
MOZ_ASSERT(mIsLocked, "Calling TextureClient::BorrowDrawTarget without locking :(");
MOZ_ASSERT(NS_IsMainThread());
if (!mIsLocked || (!mTexture && !mTexture10)) {
gfxCriticalError() << "Attempted to borrow a DrawTarget without locking the texture.";
@@ -387,6 +391,53 @@ TextureClientD3D11::BorrowDrawTarget()
return mDrawTarget;
}
void
TextureClientD3D11::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
if (mDrawTarget) {
// Ensure unflushed work from our outstanding drawtarget won't override this
// update later.
mDrawTarget->Flush();
}
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format!";
return;
}
if (mTexture) {
RefPtr<ID3D11Device> device;
mTexture->GetDevice(byRef(device));
RefPtr<ID3D11DeviceContext> ctx;
device->GetImmediateContext(byRef(ctx));
D3D11_BOX box;
box.front = 0;
box.back = 1;
box.top = box.left = 0;
box.right = aSurface->GetSize().width;
box.bottom = aSurface->GetSize().height;
ctx->UpdateSubresource(mTexture, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
} else {
RefPtr<ID3D10Device> device;
mTexture10->GetDevice(byRef(device));
D3D10_BOX box;
box.front = 0;
box.back = 1;
box.top = box.left = 0;
box.right = aSurface->GetSize().width;
box.bottom = aSurface->GetSize().height;
device->UpdateSubresource(mTexture10, 0, &box, sourceMap.mData, sourceMap.mStride, 0);
}
aSurface->Unmap();
}
static const GUID sD3D11TextureUsage =
{ 0xd89275b0, 0x6c7d, 0x4038, { 0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e } };
@@ -446,9 +497,15 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
return false;
}
ID3D11Device* d3d11device = gfxWindowsPlatform::GetPlatform()->GetD3D11ContentDevice();
gfxWindowsPlatform* windowsPlatform = gfxWindowsPlatform::GetPlatform();
ID3D11Device* d3d11device = windowsPlatform->GetD3D11DeviceForCurrentThread();
if (gfxPrefs::Direct2DUse1_1() && d3d11device) {
// When we're not on the main thread we're not going to be using Direct2D
// to access the contents of this texture client so we will always use D3D11.
bool haveD3d11Backend = windowsPlatform->GetContentBackend() == BackendType::DIRECT2D1_1 || !NS_IsMainThread();
if (haveD3d11Backend) {
MOZ_ASSERT(d3d11device != nullptr);
CD3D11_TEXTURE2D_DESC newDesc(mFormat == SurfaceFormat::A8 ? DXGI_FORMAT_R8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM,
aSize.width, aSize.height, 1, 1,
@@ -456,6 +513,11 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
if (!NS_IsMainThread()) {
// On the main thread we use the syncobject to handle synchronization.
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
}
hr = d3d11device->CreateTexture2D(&newDesc, nullptr, byRef(mTexture));
if (FAILED(hr)) {
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "[D3D11] 2 CreateTexture2D failure " << aSize << " Code: " << gfx::hexa(hr);
+2
View File
@@ -117,6 +117,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
+42 -29
View File
@@ -498,35 +498,6 @@ TextureClientD3D9::Lock(OpenMode aMode)
mIsLocked = true;
// Make sure that successful write-lock means we will have a DrawTarget to
// write into.
if (aMode & OpenMode::OPEN_WRITE) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
}
if (mNeedsClear) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget = BorrowDrawTarget();
if (!mDrawTarget) {
Unlock();
return false;
}
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return true;
}
@@ -601,9 +572,51 @@ TextureClientD3D9::BorrowDrawTarget()
mLockRect = true;
}
if (mNeedsClear) {
mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height));
mNeedsClear = false;
}
if (mNeedsClearWhite) {
mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
mNeedsClearWhite = false;
}
return mDrawTarget;
}
void
TextureClientD3D9::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(mIsLocked && mD3D9Surface);
// gfxWindowsSurface don't support transparency so we can't use the d3d9
// windows surface optimization.
// Instead we have to use a gfxImageSurface and fallback for font drawing.
D3DLOCKED_RECT rect;
HRESULT hr = mD3D9Surface->LockRect(&rect, nullptr, 0);
if (FAILED(hr) || !rect.pBits) {
gfxCriticalError() << "Failed to lock rect borrowing the target in D3D9 " << hexa(hr);
return;
}
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << mFormat << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy((uint8_t*)rect.pBits + rect.Pitch * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
mD3D9Surface->UnlockRect();
}
bool
TextureClientD3D9::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
+2
View File
@@ -202,6 +202,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
@@ -210,6 +210,40 @@ GrallocTextureClientOGL::BorrowDrawTarget()
return mDrawTarget;
}
void
GrallocTextureClientOGL::UpdateFromSurface(gfx::DataSourceSurface* aSurface)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :(");
if (!IsValid() || !IsAllocated() || !mMappedBuffer) {
return;
}
gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat());
if (mSize != aSurface->GetSize() || mFormat != aSurface->GetFormat()) {
gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat();
return;
}
long pixelStride = mGraphicBuffer->getStride();
long byteStride = pixelStride * BytesPerPixel(format);
DataSourceSurface::MappedSurface sourceMap;
aSurface->Map(DataSourceSurface::READ, &sourceMap);
uint8_t* buffer = GetBuffer();
for (int y = 0; y < aSurface->GetSize().height; y++) {
memcpy(buffer + byteStride * y,
sourceMap.mData + sourceMap.mStride * y,
aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()));
}
aSurface->Unmap();
}
bool
GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags)
+2
View File
@@ -82,6 +82,8 @@ public:
virtual gfx::DrawTarget* BorrowDrawTarget() override;
virtual void UpdateFromSurface(gfx::DataSourceSurface* aSurface) override;
virtual bool AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags aFlags = ALLOC_DEFAULT) override;
+36
View File
@@ -0,0 +1,36 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 "gfxTelemetry.h"
namespace mozilla {
namespace gfx {
const char*
FeatureStatusToString(FeatureStatus aStatus)
{
switch (aStatus) {
case FeatureStatus::Unused:
return "unused";
case FeatureStatus::Unavailable:
return "unavailable";
case FeatureStatus::Blocked:
return "blocked";
case FeatureStatus::Blacklisted:
return "blacklisted";
case FeatureStatus::Failed:
return "failed";
case FeatureStatus::Disabled:
return "disabled";
case FeatureStatus::Available:
return "available";
default:
MOZ_ASSERT_UNREACHABLE("missing status case");
return "unknown";
}
}
} // namespace gfx
} // namespace mozilla
+46
View File
@@ -0,0 +1,46 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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 gfx_src_gfxTelemetry_h__
#define gfx_src_gfxTelemetry_h__
namespace mozilla {
namespace gfx {
// Describes the status of a graphics feature, in terms of whether or not we've
// attempted to initialize the feature, and if so, whether or not it succeeded
// (and if not, why).
enum class FeatureStatus
{
// This feature has not been requested.
Unused,
// This feature is unavailable due to Safe Mode or not being included with
// the operating system.
Unavailable,
// This feature was blocked for reasons outside the blacklist, such as a
// runtime test failing.
Blocked,
// This feature has been blocked by the graphics blacklist.
Blacklisted,
// This feature was attempted but failed to activate.
Failed,
// This feature was explicitly disabled by the user.
Disabled,
// This feature is available for use.
Available
};
const char* FeatureStatusToString(FeatureStatus aStatus);
} // namespace gfx
} // namespace mozilla
#endif // gfx_src_gfxTelemetry_h__
+2
View File
@@ -18,6 +18,7 @@ EXPORTS += [
'FilterSupport.h',
'gfxCore.h',
'gfxCrashReporterUtils.h',
'gfxTelemetry.h',
'nsBoundingMetrics.h',
'nsColor.h',
'nsColorNameList.h',
@@ -56,6 +57,7 @@ UNIFIED_SOURCES += [
'DriverInitCrashDetection.cpp',
'FilterSupport.cpp',
'gfxCrashReporterUtils.cpp',
'gfxTelemetry.cpp',
'nsColor.cpp',
'nsFont.cpp',
'nsFontMetrics.cpp',
+13 -8
View File
@@ -66,7 +66,6 @@ FontInfoLoadCompleteEvent::Run()
loader->FinalizeLoader(mFontInfo);
mFontInfo = nullptr;
return NS_OK;
}
@@ -81,7 +80,6 @@ AsyncFontInfoLoader::Run()
// post a completion event that transfer the data to the fontlist
NS_DispatchToMainThread(mCompleteEvent);
mFontInfo = nullptr;
return NS_OK;
}
@@ -140,23 +138,27 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
InitLoader();
// start async load
mState = stateAsyncLoad;
nsresult rv = NS_NewNamedThread("Font Loader",
getter_AddRefs(mFontLoaderThread),
nullptr);
if (NS_FAILED(rv)) {
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
mState = stateAsyncLoad;
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
mFontLoaderThread->Dispatch(loadEvent, NS_DISPATCH_NORMAL);
mFontLoaderThread->Dispatch(loadEvent.forget(), NS_DISPATCH_NORMAL);
}
void
gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
{
// avoid loading data if loader has already been canceled
// Avoid loading data if loader has already been canceled.
// This should mean that CancelLoader() ran and the Load
// thread has already Shutdown(), and likely before processing
// the Shutdown event it handled the load event and sent back
// our Completion event, thus we end up here.
if (mState != stateAsyncLoad) {
return;
}
@@ -187,8 +189,11 @@ gfxFontInfoLoader::CancelLoader()
mTimer = nullptr;
}
if (mFontLoaderThread) {
mFontLoaderThread->Shutdown();
mFontLoaderThread = nullptr;
// NOTE: Shutdown() runs the event loop, and we can get timer events
// ensure that we can't try to do this twice!
nsCOMPtr<nsIThread> temp;
temp.swap(mFontLoaderThread);
temp->Shutdown();
}
RemoveShutdownObserver();
CleanupLoader();
+25
View File
@@ -417,6 +417,7 @@ gfxPlatform::gfxPlatform()
, mTileHeight(-1)
, mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
, mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
, mCompositorBackend(layers::LayersBackend::LAYERS_NONE)
{
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
@@ -448,6 +449,12 @@ gfxPlatform::GetPlatform()
return gPlatform;
}
bool
gfxPlatform::Initialized()
{
return !!gPlatform;
}
void RecordingPrefChanged(const char *aPrefName, void *aClosure)
{
if (Preferences::GetBool("gfx.2d.recording", false)) {
@@ -2558,3 +2565,21 @@ gfxPlatform::GetCompositorBackends(bool useAcceleration, nsTArray<mozilla::layer
aBackends.AppendElement(LayersBackend::LAYERS_BASIC);
}
}
void
gfxPlatform::NotifyCompositorCreated(LayersBackend aBackend)
{
if (mCompositorBackend == aBackend) {
return;
}
NS_ASSERTION(mCompositorBackend == LayersBackend::LAYERS_NONE, "Compositor backend changed.");
// Set the backend before we notify so it's available immediately.
mCompositorBackend = aBackend;
// Notify that we created a compositor, so telemetry can update.
if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
obsvc->NotifyObservers(nullptr, "compositor:created", nullptr);
}
}
+15
View File
@@ -188,6 +188,12 @@ public:
*/
static gfxPlatform *GetPlatform();
/**
* Returns whether or not graphics has been initialized yet. This is
* intended for Telemetry where we don't necessarily want to initialize
* graphics just to observe its state.
*/
static bool Initialized();
/**
* Shut down Thebes.
@@ -662,6 +668,11 @@ public:
*/
static bool PerfWarnings();
void NotifyCompositorCreated(mozilla::layers::LayersBackend aBackend);
mozilla::layers::LayersBackend GetCompositorBackend() const {
return mCompositorBackend;
}
protected:
gfxPlatform();
virtual ~gfxPlatform();
@@ -782,6 +793,10 @@ private:
mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
mozilla::RefPtr<mozilla::gl::SkiaGLGlue> mSkiaGlue;
// Backend that we are compositing with. NONE, if no compositor has been
// created yet.
mozilla::layers::LayersBackend mCompositorBackend;
};
#endif /* GFX_PLATFORM_H */
+6
View File
@@ -201,6 +201,12 @@ private:
DECL_GFX_PREF(Once, "gfx.android.rgb16.force", AndroidRGB16Force, bool, false);
#if defined(ANDROID)
DECL_GFX_PREF(Once, "gfx.apitrace.enabled", UseApitrace, bool, false);
#endif
#if defined(RELEASE_BUILD)
// "Skip" means this is locked to the default value in beta and release.
DECL_GFX_PREF(Skip, "gfx.blocklist.all", BlocklistAll, int32_t, 0);
#else
DECL_GFX_PREF(Once, "gfx.blocklist.all", BlocklistAll, int32_t, 0);
#endif
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_calls", CanvasAutoAccelerateMinCalls, int32_t, 4);
DECL_GFX_PREF(Live, "gfx.canvas.auto_accelerate.min_frames", CanvasAutoAccelerateMinFrames, int32_t, 30);
+83 -28
View File
@@ -376,6 +376,8 @@ gfxWindowsPlatform::gfxWindowsPlatform()
, mIsWARP(false)
, mHasDeviceReset(false)
, mDoesD3D11TextureSharingWork(false)
, mD3D11Status(FeatureStatus::Unused)
, mD2DStatus(FeatureStatus::Unused)
{
mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
mUseClearTypeAlways = UNINITIALIZED_VALUE;
@@ -435,7 +437,7 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding()
return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding();
}
void
FeatureStatus
gfxWindowsPlatform::InitD2DSupport()
{
#ifdef CAIRO_HAS_D2D_SURFACE
@@ -457,30 +459,41 @@ gfxWindowsPlatform::InitD2DSupport()
// If D2D is blocked or D3D9 is prefered, and D2D is not force-enabled, then
// we don't attempt to use D2D.
if ((d2dBlocked || gfxPrefs::LayersPreferD3D9()) && !gfxPrefs::Direct2DForceEnabled()) {
return;
if (!gfxPrefs::Direct2DForceEnabled()) {
if (d2dBlocked) {
return FeatureStatus::Blacklisted;
}
if (gfxPrefs::LayersPreferD3D9()) {
return FeatureStatus::Disabled;
}
}
// Do not ever try to use D2D if it's explicitly disabled or if we're not
// using DWrite fonts.
if (gfxPrefs::Direct2DDisabled() || mUsingGDIFonts) {
return;
return FeatureStatus::Disabled;
}
ID3D11Device* device = GetD3D11Device();
if (IsVistaOrLater() &&
!InSafeMode() &&
device &&
mDoesD3D11TextureSharingWork)
{
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
if (mD3D10Device && GetD3D11Device()) {
mRenderMode = RENDER_DIRECT2D;
mUseDirectWrite = true;
}
} else {
mD3D10Device = nullptr;
if (!IsVistaOrLater() || !GetD3D11Device()) {
return FeatureStatus::Unavailable;
}
if (!mDoesD3D11TextureSharingWork) {
return FeatureStatus::Failed;
}
if (InSafeMode()) {
return FeatureStatus::Blocked;
}
VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled());
if (!mD3D10Device || !GetD3D11Device()) {
return FeatureStatus::Failed;
}
mRenderMode = RENDER_DIRECT2D;
mUseDirectWrite = true;
return FeatureStatus::Available;
#else
return FeatureStatus::Unavailable;
#endif
}
@@ -543,6 +556,7 @@ gfxWindowsPlatform::UpdateRenderMode()
imgLoader::Singleton()->ClearCache(true);
imgLoader::Singleton()->ClearCache(false);
gfxAlphaBoxBlur::ShutdownBlurCache();
Factory::SetDirect3D11Device(nullptr);
didReset = true;
@@ -551,7 +565,7 @@ gfxWindowsPlatform::UpdateRenderMode()
mRenderMode = RENDER_GDI;
mUseDirectWrite = gfxPrefs::DirectWriteFontRenderingEnabled();
InitD2DSupport();
mD2DStatus = InitD2DSupport();
InitDWriteSupport();
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
@@ -1576,6 +1590,15 @@ gfxWindowsPlatform::GetD3D11ImageBridgeDevice()
return mD3D11ImageBridgeDevice;
}
ID3D11Device*
gfxWindowsPlatform::GetD3D11DeviceForCurrentThread()
{
if (NS_IsMainThread()) {
return GetD3D11ContentDevice();
} else {
return GetD3D11ImageBridgeDevice();
}
}
ReadbackManagerD3D11*
gfxWindowsPlatform::GetReadbackManager()
@@ -1723,6 +1746,12 @@ CheckForAdapterMismatch(ID3D11Device *device)
void CheckIfRenderTargetViewNeedsRecreating(ID3D11Device *device)
{
// CreateTexture2D is known to crash on lower feature levels, see bugs
// 1170211 and 1089413.
if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
return;
}
nsRefPtr<ID3D11DeviceContext> deviceContext;
device->GetImmediateContext(getter_AddRefs(deviceContext));
int backbufferWidth = 32; int backbufferHeight = 32;
@@ -1882,15 +1911,7 @@ bool DoesD3D11TextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT forma
bool DoesD3D11TextureSharingWork(ID3D11Device *device)
{
static bool checked;
static bool result;
if (checked)
return result;
checked = true;
result = DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
return result;
return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
}
bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device)
@@ -2057,15 +2078,17 @@ gfxWindowsPlatform::InitD3D11Devices()
mD3D11DeviceInitialized = true;
mDoesD3D11TextureSharingWork = false;
MOZ_ASSERT(!mD3D11Device);
MOZ_ASSERT(!mD3D11Device);
DriverInitCrashDetection detectCrashes;
if (InSafeMode() || detectCrashes.DisableAcceleration()) {
mD3D11Status = FeatureStatus::Blocked;
return;
}
D3D11Status status = CheckD3D11Support();
if (status == D3D11Status::Blocked) {
mD3D11Status = FeatureStatus::Blacklisted;
return;
}
@@ -2075,6 +2098,7 @@ gfxWindowsPlatform::InitD3D11Devices()
if (!sD3D11CreateDeviceFn) {
// We should just be on Windows Vista or XP in this case.
mD3D11Status = FeatureStatus::Unavailable;
return;
}
@@ -2098,6 +2122,7 @@ gfxWindowsPlatform::InitD3D11Devices()
(status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP))
{
AttemptWARPDeviceCreation(featureLevels);
mD3D11Status = FeatureStatus::Failed;
}
if (!mD3D11Device) {
@@ -2106,6 +2131,7 @@ gfxWindowsPlatform::InitD3D11Devices()
}
mD3D11Device->SetExceptionMode(0);
mD3D11Status = FeatureStatus::Available;
// We create our device for D2D content drawing here. Normally we don't use
// D2D content drawing when using WARP. However when WARP is forced by
@@ -2400,3 +2426,32 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray<LayersBackend>& aB
}
}
}
FeatureStatus
gfxWindowsPlatform::GetD2D1Status()
{
if (GetD2DStatus() != FeatureStatus::Available ||
!Factory::SupportsD2D1())
{
return FeatureStatus::Unavailable;
}
if (!GetD3D11ContentDevice()) {
return FeatureStatus::Failed;
}
if (!gfxPrefs::Direct2DUse1_1()) {
return FeatureStatus::Disabled;
}
return FeatureStatus::Available;
}
unsigned
gfxWindowsPlatform::GetD3D11Version()
{
ID3D11Device* device = GetD3D11Device();
if (!device) {
return 0;
}
return device->GetFeatureLevel();
}
+18 -1
View File
@@ -20,6 +20,7 @@
#include "gfxDWriteFonts.h"
#endif
#include "gfxPlatform.h"
#include "gfxTelemetry.h"
#include "gfxTypes.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.h"
@@ -243,6 +244,7 @@ public:
ID3D10Device1 *GetD3D10Device() { return mD3D10Device; }
ID3D11Device *GetD3D11Device();
ID3D11Device *GetD3D11ContentDevice();
ID3D11Device* GetD3D11DeviceForCurrentThread();
// Device to be used on the ImageBridge thread
ID3D11Device *GetD3D11ImageBridgeDevice();
@@ -261,6 +263,18 @@ public:
}
bool SupportsApzTouchInput() const override;
// Return the diagnostic status of DirectX initialization. If
// initialization has not been attempted, this returns
// FeatureStatus::Unused.
mozilla::gfx::FeatureStatus GetD3D11Status() const {
return mD3D11Status;
}
mozilla::gfx::FeatureStatus GetD2DStatus() const {
return mD2DStatus;
}
unsigned GetD3D11Version();
mozilla::gfx::FeatureStatus GetD2D1Status();
virtual already_AddRefed<mozilla::gfx::VsyncSource> CreateHardwareVsyncSource() override;
static mozilla::Atomic<size_t> sD3D11MemoryUsed;
static mozilla::Atomic<size_t> sD3D9MemoryUsed;
@@ -298,7 +312,7 @@ private:
bool AttemptD3D11ContentDeviceCreation(const nsTArray<D3D_FEATURE_LEVEL>& aFeatureLevels);
// Used by UpdateRenderMode().
void InitD2DSupport();
mozilla::gfx::FeatureStatus InitD2DSupport();
void InitDWriteSupport();
IDXGIAdapter1 *GetDXGIAdapter();
@@ -326,6 +340,9 @@ private:
bool mDoesD3D11TextureSharingWork;
DeviceResetReason mDeviceResetReason;
mozilla::gfx::FeatureStatus mD3D11Status;
mozilla::gfx::FeatureStatus mD2DStatus;
virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size);
};
+3
View File
@@ -32,6 +32,7 @@
#endif
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
#include "TracedTaskCommon.h"
#endif
#include "MessagePump.h"
@@ -287,6 +288,7 @@ void MessageLoop::PostIdleTask(
#ifdef MOZ_TASK_TRACER
task = mozilla::tasktracer::CreateTracedTask(task);
(static_cast<mozilla::tasktracer::TracedTask*>(task))->DispatchTask();
#endif
task->SetBirthPlace(from_here);
@@ -301,6 +303,7 @@ void MessageLoop::PostTask_Helper(
#ifdef MOZ_TASK_TRACER
task = mozilla::tasktracer::CreateTracedTask(task);
(static_cast<mozilla::tasktracer::TracedTask*>(task))->DispatchTask(delay_ms);
#endif
task->SetBirthPlace(from_here);
+3 -3
View File
@@ -6974,11 +6974,11 @@ PresShell::HandleEvent(nsIFrame* aFrame,
// Make touch events, mouse events and hardware key events to be the source
// events of TaskTracer, and originate the rest correlation tasks from here.
SourceEventType type = SourceEventType::Unknown;
if (WidgetTouchEvent* inputEvent = aEvent->AsTouchEvent()) {
if (aEvent->AsTouchEvent()) {
type = SourceEventType::Touch;
} else if (WidgetMouseEvent* inputEvent = aEvent->AsMouseEvent()) {
} else if (aEvent->AsMouseEvent()) {
type = SourceEventType::Mouse;
} else if (WidgetKeyboardEvent* inputEvent = aEvent->AsKeyboardEvent()) {
} else if (aEvent->AsKeyboardEvent()) {
type = SourceEventType::Key;
}
AutoSourceEvent taskTracerEvent(type);
+1 -1
View File
@@ -44,7 +44,7 @@ RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flag
return rv;
}
if (!on) {
return thread->Dispatch(runnable_ref, flags);
return thread->Dispatch(runnable_ref.forget(), flags);
}
}
return runnable_ref->Run();
+11 -3
View File
@@ -114,13 +114,21 @@ nsSocketTransportService::GetThreadSafely()
}
NS_IMETHODIMP
nsSocketTransportService::Dispatch(nsIRunnable *event, uint32_t flags)
nsSocketTransportService::DispatchFromScript(nsIRunnable *event, uint32_t flags)
{
SOCKET_LOG(("STS dispatch [%p]\n", event));
nsCOMPtr<nsIRunnable> event_ref(event);
return Dispatch(event_ref.forget(), flags);
}
NS_IMETHODIMP
nsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event_ref(event);
SOCKET_LOG(("STS dispatch [%p]\n", event_ref.get()));
nsCOMPtr<nsIThread> thread = GetThreadSafely();
nsresult rv;
rv = thread ? thread->Dispatch(event, flags) : NS_ERROR_NOT_INITIALIZED;
rv = thread ? thread->Dispatch(event_ref.forget(), flags) : NS_ERROR_NOT_INITIALIZED;
if (rv == NS_ERROR_UNEXPECTED) {
// Thread is no longer accepting events. We must have just shut it
// down on the main thread. Pretend we never saw it.
+4
View File
@@ -79,6 +79,10 @@ public:
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIRUNNABLE
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsSocketTransportService();
+10 -2
View File
@@ -502,8 +502,16 @@ NS_IMPL_ISUPPORTS(nsStreamTransportService,
nsIObserver)
NS_IMETHODIMP
nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
nsStreamTransportService::DispatchFromScript(nsIRunnable *task, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event(task);
return Dispatch(event.forget(), flags);
}
NS_IMETHODIMP
nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable>&& task, uint32_t flags)
{
nsCOMPtr<nsIRunnable> event(task); // so it gets released on failure paths
nsCOMPtr<nsIThreadPool> pool;
{
mozilla::MutexAutoLock lock(mShutdownLock);
@@ -513,7 +521,7 @@ nsStreamTransportService::Dispatch(nsIRunnable *task, uint32_t flags)
pool = mPool;
}
NS_ENSURE_TRUE(pool, NS_ERROR_NOT_INITIALIZED);
return pool->Dispatch(task, flags);
return pool->Dispatch(event.forget(), flags);
}
NS_IMETHODIMP
+4
View File
@@ -21,6 +21,10 @@ public:
NS_DECL_NSISTREAMTRANSPORTSERVICE
NS_DECL_NSIEVENTTARGET
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsresult Init();
+36 -37
View File
@@ -476,9 +476,9 @@ DataChannelConnection::StartDefer()
{
nsresult rv;
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::START_DEFER,
this, (DataChannel *) nullptr));
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::START_DEFER,
this, (DataChannel *) nullptr)));
return;
}
@@ -615,9 +615,9 @@ DataChannelConnection::CompleteConnect(TransportFlow *flow, TransportLayer::Stat
}
}
// Note: currently this doesn't actually notify the application
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CONNECTION,
this));
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CONNECTION,
this)));
return;
}
@@ -713,7 +713,7 @@ DataChannelConnection::SctpDtlsOutput(void *addr, void *buffer, size_t length,
peer->mSTS->Dispatch(WrapRunnable(
nsRefPtr<DataChannelConnection>(peer),
&DataChannelConnection::SendPacket, data, length, true),
NS_DISPATCH_NORMAL);
NS_DISPATCH_NORMAL);
res = 0; // cheat! Packets can always be dropped later anyways
}
return res;
@@ -774,9 +774,9 @@ DataChannelConnection::Listen(unsigned short port)
// Notify Connection open
// XXX We need to make sure connection sticks around until the message is delivered
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CONNECTION,
this, (DataChannel *) nullptr));
this, (DataChannel *) nullptr)));
return true;
}
@@ -852,9 +852,9 @@ DataChannelConnection::Connect(const char *addr, unsigned short port)
// Notify Connection open
// XXX We need to make sure connection sticks around until the message is delivered
LOG(("%s: sending ON_CONNECTION for %p", __FUNCTION__, this));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CONNECTION,
this, (DataChannel *) nullptr));
this, (DataChannel *) nullptr)));
return true;
}
#endif
@@ -1053,9 +1053,9 @@ DataChannelConnection::SendDeferredMessages()
channel->mState = OPEN;
channel->mReady = true;
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
channel));
channel)));
sent = true;
} else {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
@@ -1065,9 +1065,9 @@ DataChannelConnection::SendDeferredMessages()
mStreams[channel->mStream] = nullptr;
channel->mState = CLOSED;
// Don't need to reset; we didn't open it
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
channel));
channel)));
}
}
}
@@ -1233,9 +1233,9 @@ DataChannelConnection::HandleOpenRequestMessage(const struct rtcweb_datachannel_
LOG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u (state %u)", __FUNCTION__,
channel->mLabel.get(), channel->mProtocol.get(), stream, channel->mState));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CREATED,
this, channel));
this, channel)));
LOG(("%s: deferring sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
@@ -1463,9 +1463,9 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
SetEvenOdd();
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CONNECTION,
this));
this)));
LOG(("DTLS connect() succeeded! Entering connected mode"));
// Open any streams pending...
@@ -1480,18 +1480,18 @@ DataChannelConnection::HandleAssociationChangeEvent(const struct sctp_assoc_chan
case SCTP_COMM_LOST:
LOG(("Association change: SCTP_COMM_LOST"));
// This association is toast, so also close all the channels -- from mainthread!
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_DISCONNECTED,
this));
this)));
break;
case SCTP_RESTART:
LOG(("Association change: SCTP_RESTART"));
break;
case SCTP_SHUTDOWN_COMP:
LOG(("Association change: SCTP_SHUTDOWN_COMP"));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_DISCONNECTED,
this));
this)));
break;
case SCTP_CANT_STR_ASSOC:
LOG(("Association change: SCTP_CANT_STR_ASSOC"));
@@ -1754,9 +1754,9 @@ DataChannelConnection::HandleStreamResetEvent(const struct sctp_stream_reset_eve
// Mark the stream for reset (the reset is sent below)
ResetOutgoingStream(channel->mStream);
}
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
channel));
channel)));
mStreams[channel->mStream] = nullptr;
LOG(("Disconnected DataChannel %p from connection %p",
@@ -1847,9 +1847,9 @@ DataChannelConnection::HandleStreamChangeEvent(const struct sctp_stream_change_e
(strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) {
/* XXX: Signal to the other end. */
channel->mState = CLOSED;
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
channel));
channel)));
// maybe fire onError (bug 843625)
} else {
stream = FindFreeStream();
@@ -2130,9 +2130,9 @@ DataChannelConnection::OpenFinish(already_AddRefed<DataChannel>&& aChannel)
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
// We already returned the channel to the app.
NS_ERROR("Failed to send open request");
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
channel));
channel)));
}
// If we haven't returned the channel yet, it will get destroyed when we exit
// this function.
@@ -2150,9 +2150,9 @@ DataChannelConnection::OpenFinish(already_AddRefed<DataChannel>&& aChannel)
channel->mReady = true;
// FIX? Move into DOMDataChannel? I don't think we can send it yet here
LOG(("%s: sending ON_CHANNEL_OPEN for %p", __FUNCTION__, channel.get()));
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, this,
channel));
channel)));
return channel.forget();
@@ -2161,9 +2161,9 @@ request_error_cleanup:
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
// We already returned the channel to the app.
NS_ERROR("Failed to request more streams");
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_CLOSED, this,
channel));
channel)));
return channel.forget();
}
// we'll be destroying the channel, but it never really got set up
@@ -2330,8 +2330,7 @@ DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream *aBlob)
}
}
nsCOMPtr<nsIRunnable> runnable = new ReadBlobRunnable(this, stream, aBlob);
mInternalIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
mInternalIOThread->Dispatch(do_AddRef(new ReadBlobRunnable(this, stream, aBlob)), NS_DISPATCH_NORMAL);
return 0;
}
@@ -2580,9 +2579,9 @@ DataChannel::AppReady()
mReady = true;
if (mState == WAITING_TO_OPEN) {
mState = OPEN;
NS_DispatchToMainThread(new DataChannelOnMessageAvailable(
NS_DispatchToMainThread(do_AddRef(new DataChannelOnMessageAvailable(
DataChannelOnMessageAvailable::ON_CHANNEL_OPEN, mConnection,
this));
this)));
for (uint32_t i = 0; i < mQueuedMessages.Length(); ++i) {
nsCOMPtr<nsIRunnable> runnable = mQueuedMessages[i];
MOZ_ASSERT(runnable);
@@ -106,7 +106,10 @@ void Finalize(JSFreeOp *fop, JSObject *objSelf)
// Notify observers. Since we are executed during garbage-collection,
// we need to dispatch the notification to the main thread.
(void)NS_DispatchToMainThread(event);
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (mainThread) {
mainThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
}
// We may fail at dispatching to the main thread if we arrive too late
// during shutdown. In that case, there is not much we can do.
}
@@ -101,7 +101,7 @@ Structure::
gfx: {
D2DEnabled: <bool>, // null on failure
DWriteEnabled: <bool>, // null on failure
DWriteVersion: <string>, // null on failure
//DWriteVersion: <string>, // temporarily removed, pending bug 1154500
adapters: [
{
description: <string>, // e.g. "Intel(R) HD Graphics 4600", null on failure
@@ -116,6 +116,28 @@ Structure::
},
...
],
features: {
compositor: <string>, // Layers backend for compositing (eg "d3d11", "none", "opengl")
// Each the following features can have one of the following statuses:
// "unused" - This feature has not been requested.
// "unavailable" - Safe Mode or OS restriction prevents use.
// "blocked" - Blocked due to an internal condition such as safe mode.
// "blacklisted" - Blocked due to a blacklist restriction.
// "disabled" - User explicitly disabled this default feature.
// "failed" - This feature was attempted but failed to initialize.
// "available" - User has this feature available.
"d3d11" { // This feature is Windows-only.
status: <string>,
warp: <bool>, // Software rendering (WARP) mode was chosen.
textureSharing: <bool> // Whether or not texture sharing works.
version: <number>, // The D3D11 device feature level.
},
"d2d" { // This feature is Windows-only.
status: <string>,
version: <string>, // Either "1.0" or "1.1".
},
},
},
},
addons: {
+108 -83
View File
@@ -7,6 +7,7 @@
#include "GeckoTaskTracer.h"
#include "GeckoTaskTracerImpl.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/TimeStamp.h"
@@ -27,13 +28,32 @@ static pid_t gettid()
}
#endif
// NS_ENSURE_TRUE_VOID() without the warning on the debug build.
#define ENSURE_TRUE_VOID(x) \
do { \
if (MOZ_UNLIKELY(!(x))) { \
return; \
} \
} while(0)
// NS_ENSURE_TRUE() without the warning on the debug build.
#define ENSURE_TRUE(x, ret) \
do { \
if (MOZ_UNLIKELY(!(x))) { \
return ret; \
} \
} while(0)
namespace mozilla {
namespace tasktracer {
static mozilla::ThreadLocal<TraceInfo*>* sTraceInfoTLS = nullptr;
static mozilla::ThreadLocal<TraceInfo*> sTraceInfoTLS;
static mozilla::StaticMutex sMutex;
// The generation of TraceInfo. It will be > 0 if the Task Tracer is started and
// <= 0 if stopped.
static mozilla::Atomic<bool> sStarted;
static nsTArray<nsAutoPtr<TraceInfo>>* sTraceInfos = nullptr;
static bool sIsLoggingStarted = false;
static PRTime sStartTime;
static const char sJSLabelPrefix[] = "#tt#";
@@ -52,24 +72,16 @@ AllocTraceInfo(int aTid)
StaticMutexAutoLock lock(sMutex);
nsAutoPtr<TraceInfo>* info = sTraceInfos->AppendElement(
new TraceInfo(aTid, sIsLoggingStarted));
new TraceInfo(aTid));
return info->get();
}
static bool
IsInitialized()
{
return sTraceInfoTLS ? sTraceInfoTLS->initialized() : false;
}
static void
SaveCurTraceInfo()
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!info) {
return;
}
ENSURE_TRUE_VOID(info);
info->mSavedCurTraceSourceId = info->mCurTraceSourceId;
info->mSavedCurTraceSourceType = info->mCurTraceSourceType;
@@ -80,9 +92,7 @@ static void
RestoreCurTraceInfo()
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!info) {
return;
}
ENSURE_TRUE_VOID(info);
info->mCurTraceSourceId = info->mSavedCurTraceSourceId;
info->mCurTraceSourceType = info->mSavedCurTraceSourceType;
@@ -92,14 +102,14 @@ RestoreCurTraceInfo()
static void
CreateSourceEvent(SourceEventType aType)
{
NS_ENSURE_TRUE_VOID(IsInitialized());
// Save the currently traced source event info.
SaveCurTraceInfo();
// Create a new unique task id.
uint64_t newId = GenNewUniqueTaskId();
TraceInfo* info = GetOrCreateTraceInfo();
ENSURE_TRUE_VOID(info);
info->mCurTraceSourceId = newId;
info->mCurTraceSourceType = aType;
info->mCurTaskId = newId;
@@ -129,54 +139,57 @@ CreateSourceEvent(SourceEventType aType)
static void
DestroySourceEvent()
{
NS_ENSURE_TRUE_VOID(IsInitialized());
// Log a fake end for this source event.
TraceInfo* info = GetOrCreateTraceInfo();
ENSURE_TRUE_VOID(info);
LogEnd(info->mCurTraceSourceId, info->mCurTraceSourceId);
// Restore the previously saved source event info.
RestoreCurTraceInfo();
}
inline static bool
IsStartLogging()
{
return sStarted;
}
static void
SetLogStarted(bool aIsStartLogging)
{
MOZ_ASSERT(aIsStartLogging != IsStartLogging());
sStarted = aIsStartLogging;
StaticMutexAutoLock lock(sMutex);
if (!aIsStartLogging) {
for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) {
(*sTraceInfos)[i]->mObsolete = true;
}
}
}
static void
CleanUp()
{
SetLogStarted(false);
StaticMutexAutoLock lock(sMutex);
if (sTraceInfos) {
delete sTraceInfos;
sTraceInfos = nullptr;
}
// pthread_key_delete() is not called at the destructor of
// mozilla::ThreadLocal (Bug 1064672).
if (sTraceInfoTLS) {
delete sTraceInfoTLS;
sTraceInfoTLS = nullptr;
}
}
static void
SetLogStarted(bool aIsStartLogging)
inline static void
ObsoleteCurrentTraceInfos()
{
// TODO: This is called from a signal handler. Use semaphore instead.
StaticMutexAutoLock lock(sMutex);
// Note that we can't and don't need to acquire sMutex here because this
// function is called before the other threads are recreated.
for (uint32_t i = 0; i < sTraceInfos->Length(); ++i) {
(*sTraceInfos)[i]->mStartLogging = aIsStartLogging;
(*sTraceInfos)[i]->mObsolete = true;
}
sIsLoggingStarted = aIsStartLogging;
}
static bool
IsStartLogging(TraceInfo* aInfo)
{
StaticMutexAutoLock lock(sMutex);
return aInfo ? aInfo->mStartLogging : false;
}
} // namespace anonymous
nsCString*
@@ -197,17 +210,15 @@ void
InitTaskTracer(uint32_t aFlags)
{
if (aFlags & FORKED_AFTER_NUWA) {
CleanUp();
ObsoleteCurrentTraceInfos();
return;
}
MOZ_ASSERT(!sTraceInfoTLS);
sTraceInfoTLS = new ThreadLocal<TraceInfo*>();
MOZ_ASSERT(!sTraceInfos);
sTraceInfos = new nsTArray<nsAutoPtr<TraceInfo>>();
if (!sTraceInfoTLS->initialized()) {
unused << sTraceInfoTLS->init();
if (!sTraceInfoTLS.initialized()) {
unused << sTraceInfoTLS.init();
}
}
@@ -217,15 +228,36 @@ ShutdownTaskTracer()
CleanUp();
}
static void
FreeTraceInfo(TraceInfo* aTraceInfo)
{
StaticMutexAutoLock lock(sMutex);
if (aTraceInfo) {
sTraceInfos->RemoveElement(aTraceInfo);
}
}
void FreeTraceInfo()
{
FreeTraceInfo(sTraceInfoTLS.get());
}
TraceInfo*
GetOrCreateTraceInfo()
{
NS_ENSURE_TRUE(IsInitialized(), nullptr);
ENSURE_TRUE(sTraceInfoTLS.initialized(), nullptr);
ENSURE_TRUE(IsStartLogging(), nullptr);
TraceInfo* info = sTraceInfoTLS.get();
if (info && info->mObsolete) {
// TraceInfo is obsolete: remove it.
FreeTraceInfo(info);
info = nullptr;
}
TraceInfo* info = sTraceInfoTLS->get();
if (!info) {
info = AllocTraceInfo(gettid());
sTraceInfoTLS->set(info);
sTraceInfoTLS.set(info);
}
return info;
@@ -235,7 +267,7 @@ uint64_t
GenNewUniqueTaskId()
{
TraceInfo* info = GetOrCreateTraceInfo();
NS_ENSURE_TRUE(info, 0);
ENSURE_TRUE(info, 0);
pid_t tid = gettid();
uint64_t taskid = ((uint64_t)tid << 32) | ++info->mLastUniqueTaskId;
@@ -257,7 +289,7 @@ SetCurTraceInfo(uint64_t aSourceEventId, uint64_t aParentTaskId,
SourceEventType aSourceEventType)
{
TraceInfo* info = GetOrCreateTraceInfo();
NS_ENSURE_TRUE_VOID(info);
ENSURE_TRUE_VOID(info);
info->mCurTraceSourceId = aSourceEventId;
info->mCurTaskId = aParentTaskId;
@@ -269,7 +301,7 @@ GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId,
SourceEventType* aOutSourceEventType)
{
TraceInfo* info = GetOrCreateTraceInfo();
NS_ENSURE_TRUE_VOID(info);
ENSURE_TRUE_VOID(info);
*aOutSourceEventId = info->mCurTraceSourceId;
*aOutParentTaskId = info->mCurTaskId;
@@ -279,18 +311,28 @@ GetCurTraceInfo(uint64_t* aOutSourceEventId, uint64_t* aOutParentTaskId,
void
LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId,
SourceEventType aSourceEventType)
{
LogDispatch(aTaskId, aParentTaskId, aSourceEventId, aSourceEventType, 0);
}
void
LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId, uint64_t aSourceEventId,
SourceEventType aSourceEventType, int aDelayTimeMs)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!IsStartLogging(info)) {
return;
}
ENSURE_TRUE_VOID(info);
// aDelayTimeMs is the expected delay time in milliseconds, thus the dispatch
// time calculated of it might be slightly off in the real world.
uint64_t time = (aDelayTimeMs <= 0) ? GetTimestamp() :
GetTimestamp() + aDelayTimeMs;
// Log format:
// [0 taskId dispatchTime sourceEventId sourceEventType parentTaskId]
nsCString* log = info->AppendLog();
if (log) {
log->AppendPrintf("%d %lld %lld %lld %d %lld",
ACTION_DISPATCH, aTaskId, GetTimestamp(), aSourceEventId,
ACTION_DISPATCH, aTaskId, time, aSourceEventId,
aSourceEventType, aParentTaskId);
}
}
@@ -299,9 +341,7 @@ void
LogBegin(uint64_t aTaskId, uint64_t aSourceEventId)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!IsStartLogging(info)) {
return;
}
ENSURE_TRUE_VOID(info);
// Log format:
// [1 taskId beginTime processId threadId]
@@ -316,9 +356,7 @@ void
LogEnd(uint64_t aTaskId, uint64_t aSourceEventId)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!IsStartLogging(info)) {
return;
}
ENSURE_TRUE_VOID(info);
// Log format:
// [2 taskId endTime]
@@ -332,9 +370,7 @@ void
LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, int* aVptr)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!IsStartLogging(info)) {
return;
}
ENSURE_TRUE_VOID(info);
// Log format:
// [4 taskId address]
@@ -344,18 +380,6 @@ LogVirtualTablePtr(uint64_t aTaskId, uint64_t aSourceEventId, int* aVptr)
}
}
void
FreeTraceInfo()
{
NS_ENSURE_TRUE_VOID(IsInitialized());
StaticMutexAutoLock lock(sMutex);
TraceInfo* info = GetOrCreateTraceInfo();
if (info) {
sTraceInfos->RemoveElement(info);
}
}
AutoSourceEvent::AutoSourceEvent(SourceEventType aType)
{
CreateSourceEvent(aType);
@@ -369,9 +393,7 @@ AutoSourceEvent::~AutoSourceEvent()
void AddLabel(const char* aFormat, ...)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!IsStartLogging(info)) {
return;
}
ENSURE_TRUE_VOID(info);
va_list args;
va_start(args, aFormat);
@@ -404,7 +426,7 @@ StopLogging()
}
TraceInfoLogsType*
GetLoggedData()
GetLoggedData(TimeStamp aTimeStamp)
{
TraceInfoLogsType* result = new TraceInfoLogsType();
@@ -430,5 +452,8 @@ GetJSLabelPrefix()
return sJSLabelPrefix;
}
#undef ENSURE_TRUE_VOID
#undef ENSURE_TRUE
} // namespace tasktracer
} // namespace mozilla
+3 -6
View File
@@ -37,10 +37,6 @@ namespace tasktracer {
enum {
FORKED_AFTER_NUWA = 1 << 0
};
void InitTaskTracer(uint32_t aFlags = 0);
void ShutdownTaskTracer();
class FakeTracedTask;
enum SourceEventType {
Unknown = 0,
@@ -59,6 +55,9 @@ public:
~AutoSourceEvent();
};
void InitTaskTracer(uint32_t aFlags = 0);
void ShutdownTaskTracer();
// Add a label to the currently running task, aFormat is the message to log,
// followed by corresponding parameters.
void AddLabel(const char* aFormat, ...);
@@ -78,8 +77,6 @@ Task* CreateTracedTask(Task* aTask);
already_AddRefed<nsIRunnable> CreateTracedRunnable(nsIRunnable* aRunnable);
already_AddRefed<FakeTracedTask> CreateFakeTracedTask(int* aVptr);
// Free the TraceInfo allocated on a thread's TLS. Currently we are wrapping
// tasks running on nsThreads and base::thread, so FreeTraceInfo is called at
// where nsThread and base::thread release themselves.
+7 -3
View File
@@ -18,7 +18,7 @@ typedef nsTArray<nsCString> TraceInfoLogsType;
struct TraceInfo
{
TraceInfo(uint32_t aThreadId, bool aStartLogging)
TraceInfo(uint32_t aThreadId)
: mCurTraceSourceId(0)
, mCurTaskId(0)
, mSavedCurTraceSourceId(0)
@@ -27,7 +27,7 @@ struct TraceInfo
, mSavedCurTraceSourceType(Unknown)
, mThreadId(aThreadId)
, mLastUniqueTaskId(0)
, mStartLogging(aStartLogging)
, mObsolete(false)
, mLogsMutex("TraceInfoMutex")
{
MOZ_COUNT_CTOR(TraceInfo);
@@ -46,7 +46,7 @@ struct TraceInfo
SourceEventType mSavedCurTraceSourceType;
uint32_t mThreadId;
uint32_t mLastUniqueTaskId;
bool mStartLogging;
mozilla::Atomic<bool> mObsolete;
// This mutex protects the following log array because MoveLogsInto() might
// be called on another thread.
@@ -86,6 +86,10 @@ enum ActionType {
void LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId,
uint64_t aSourceEventId, SourceEventType aSourceEventType);
void LogDispatch(uint64_t aTaskId, uint64_t aParentTaskId,
uint64_t aSourceEventId, SourceEventType aSourceEventType,
int aDelayTimeMs);
void LogBegin(uint64_t aTaskId, uint64_t aSourceEventId);
void LogEnd(uint64_t aTaskId, uint64_t aSourceEventId);
+68 -72
View File
@@ -7,49 +7,80 @@
#include "GeckoTaskTracerImpl.h"
#include "TracedTaskCommon.h"
// NS_ENSURE_TRUE_VOID() without the warning on the debug build.
#define ENSURE_TRUE_VOID(x) \
do { \
if (MOZ_UNLIKELY(!(x))) { \
return; \
} \
} while(0)
namespace mozilla {
namespace tasktracer {
TracedTaskCommon::TracedTaskCommon()
: mSourceEventId(0)
, mSourceEventType(SourceEventType::Unknown)
: mSourceEventType(SourceEventType::Unknown)
, mSourceEventId(0)
, mParentTaskId(0)
, mTaskId(0)
, mIsTraceInfoInit(false)
{
}
TracedTaskCommon::~TracedTaskCommon()
{
Init();
}
void
TracedTaskCommon::Init()
{
TraceInfo* info = GetOrCreateTraceInfo();
NS_ENSURE_TRUE_VOID(info);
ENSURE_TRUE_VOID(info);
mTaskId = GenNewUniqueTaskId();
mSourceEventId = info->mCurTraceSourceId;
mSourceEventType = info->mCurTraceSourceType;
LogDispatch(mTaskId, info->mCurTaskId, mSourceEventId, mSourceEventType);
mParentTaskId = info->mCurTaskId;
mIsTraceInfoInit = true;
}
void
TracedTaskCommon::SetTraceInfo()
TracedTaskCommon::DispatchTask(int aDelayTimeMs)
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!info) {
return;
}
info->mCurTraceSourceId = mSourceEventId;
info->mCurTraceSourceType = mSourceEventType;
info->mCurTaskId = mTaskId;
LogDispatch(mTaskId, mParentTaskId, mSourceEventId, mSourceEventType,
aDelayTimeMs);
}
void
TracedTaskCommon::ClearTraceInfo()
TracedTaskCommon::GetTLSTraceInfo()
{
TraceInfo* info = GetOrCreateTraceInfo();
if (!info) {
return;
ENSURE_TRUE_VOID(info);
mSourceEventType = info->mCurTraceSourceType;
mSourceEventId = info->mCurTraceSourceId;
mTaskId = info->mCurTaskId;
mIsTraceInfoInit = true;
}
void
TracedTaskCommon::SetTLSTraceInfo()
{
TraceInfo* info = GetOrCreateTraceInfo();
ENSURE_TRUE_VOID(info);
if (mIsTraceInfoInit) {
info->mCurTraceSourceId = mSourceEventId;
info->mCurTraceSourceType = mSourceEventType;
info->mCurTaskId = mTaskId;
}
}
void
TracedTaskCommon::ClearTLSTraceInfo()
{
TraceInfo* info = GetOrCreateTraceInfo();
ENSURE_TRUE_VOID(info);
info->mCurTraceSourceId = 0;
info->mCurTraceSourceType = SourceEventType::Unknown;
@@ -63,19 +94,23 @@ TracedRunnable::TracedRunnable(nsIRunnable* aOriginalObj)
: TracedTaskCommon()
, mOriginalObj(aOriginalObj)
{
Init();
LogVirtualTablePtr(mTaskId, mSourceEventId, *(int**)(aOriginalObj));
}
TracedRunnable::~TracedRunnable()
{
}
NS_IMETHODIMP
TracedRunnable::Run()
{
SetTLSTraceInfo();
LogBegin(mTaskId, mSourceEventId);
SetTraceInfo();
nsresult rv = mOriginalObj->Run();
ClearTraceInfo();
LogEnd(mTaskId, mSourceEventId);
ClearTLSTraceInfo();
return rv;
}
@@ -86,54 +121,26 @@ TracedTask::TracedTask(Task* aOriginalObj)
: TracedTaskCommon()
, mOriginalObj(aOriginalObj)
{
Init();
LogVirtualTablePtr(mTaskId, mSourceEventId, *(int**)(aOriginalObj));
}
TracedTask::~TracedTask()
{
if (mOriginalObj) {
delete mOriginalObj;
mOriginalObj = nullptr;
}
}
void
TracedTask::Run()
{
SetTLSTraceInfo();
LogBegin(mTaskId, mSourceEventId);
SetTraceInfo();
mOriginalObj->Run();
ClearTraceInfo();
LogEnd(mTaskId, mSourceEventId);
}
FakeTracedTask::FakeTracedTask(int* aVptr)
: TracedTaskCommon()
{
LogVirtualTablePtr(mTaskId, mSourceEventId, aVptr);
}
void
FakeTracedTask::BeginFakeTracedTask()
{
LogBegin(mTaskId, mSourceEventId);
SetTraceInfo();
}
void
FakeTracedTask::EndFakeTracedTask()
{
ClearTraceInfo();
LogEnd(mTaskId, mSourceEventId);
}
AutoRunFakeTracedTask::AutoRunFakeTracedTask(FakeTracedTask* aFakeTracedTask)
: mFakeTracedTask(aFakeTracedTask)
{
if (mFakeTracedTask) {
mFakeTracedTask->BeginFakeTracedTask();
}
}
AutoRunFakeTracedTask::~AutoRunFakeTracedTask()
{
if (mFakeTracedTask) {
mFakeTracedTask->EndFakeTracedTask();
}
ClearTLSTraceInfo();
}
/**
@@ -158,16 +165,5 @@ CreateTracedTask(Task* aTask)
return task;
}
/**
* CreateFakeTracedTask() returns a FakeTracedTask tracking the event which is
* not dispatched from its parent task directly, such as timer events.
*/
already_AddRefed<FakeTracedTask>
CreateFakeTracedTask(int* aVptr)
{
nsRefPtr<FakeTracedTask> task(new FakeTracedTask(aVptr));
return task.forget();
}
} // namespace tasktracer
} // namespace mozilla
+16 -47
View File
@@ -19,22 +19,25 @@ class TracedTaskCommon
{
public:
TracedTaskCommon();
virtual ~TracedTaskCommon() {}
virtual ~TracedTaskCommon();
void DispatchTask(int aDelayTimeMs = 0);
void SetTLSTraceInfo();
void GetTLSTraceInfo();
void ClearTLSTraceInfo();
protected:
void Init();
// Sets up the metadata on the current thread's TraceInfo for this task.
// After Run(), ClearTraceInfo is called to reset the metadata.
void SetTraceInfo();
void ClearTraceInfo();
// Its own task Id, an unique number base on its thread Id and a last unique
// task Id stored in its TraceInfo.
uint64_t mTaskId;
uint64_t mSourceEventId;
// TraceInfo of TLS will be set by the following parameters, including source
// event type, source event ID, parent task ID, and task ID of this traced
// task/runnable.
SourceEventType mSourceEventType;
uint64_t mSourceEventId;
uint64_t mParentTaskId;
uint64_t mTaskId;
bool mIsTraceInfoInit;
};
class TracedRunnable : public TracedTaskCommon
@@ -46,7 +49,7 @@ public:
TracedRunnable(nsIRunnable* aOriginalObj);
private:
virtual ~TracedRunnable() {}
virtual ~TracedRunnable();
nsCOMPtr<nsIRunnable> mOriginalObj;
};
@@ -56,13 +59,7 @@ class TracedTask : public TracedTaskCommon
{
public:
TracedTask(Task* aOriginalObj);
~TracedTask()
{
if (mOriginalObj) {
delete mOriginalObj;
mOriginalObj = nullptr;
}
}
~TracedTask();
virtual void Run();
@@ -70,34 +67,6 @@ private:
Task* mOriginalObj;
};
// FakeTracedTask is for tracking events that are not directly dispatched from
// their parents, e.g. The timer events.
class FakeTracedTask : public TracedTaskCommon
{
public:
NS_INLINE_DECL_REFCOUNTING(FakeTracedTask)
FakeTracedTask(int* aVptr);
void BeginFakeTracedTask();
void EndFakeTracedTask();
private:
virtual ~FakeTracedTask() {}
// No copy allowed.
FakeTracedTask() = delete;
FakeTracedTask(const FakeTracedTask& aTask) = delete;
FakeTracedTask& operator=(const FakeTracedTask& aTask) = delete;
};
class AutoRunFakeTracedTask
{
public:
AutoRunFakeTracedTask(FakeTracedTask* aFakeTracedTask);
~AutoRunFakeTracedTask();
private:
nsRefPtr<FakeTracedTask> mFakeTracedTask;
};
} // namespace tasktracer
} // namespace mozilla
+113 -2
View File
@@ -32,6 +32,8 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "gfxPrefs.h"
#include "gfxPlatform.h"
using namespace mozilla::widget;
using namespace mozilla;
@@ -161,7 +163,7 @@ GetPrefValueForFeature(int32_t aFeature, int32_t& aValue)
if (!prefname)
return false;
aValue = false;
aValue = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
return NS_SUCCEEDED(Preferences::GetInt(prefname, &aValue));
}
@@ -307,6 +309,7 @@ BlacklistDevicesToDeviceFamily(nsIDOMHTMLCollection* aDevices)
static int32_t
BlacklistFeatureToGfxFeature(const nsAString& aFeature)
{
MOZ_ASSERT(!aFeature.IsEmpty());
if (aFeature.EqualsLiteral("DIRECT2D"))
return nsIGfxInfo::FEATURE_DIRECT2D;
else if (aFeature.EqualsLiteral("DIRECT3D_9_LAYERS"))
@@ -333,7 +336,13 @@ BlacklistFeatureToGfxFeature(const nsAString& aFeature)
return nsIGfxInfo::FEATURE_STAGEFRIGHT;
else if (aFeature.EqualsLiteral("WEBRTC_HW_ACCELERATION"))
return nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION;
return 0;
// If we don't recognize the feature, it may be new, and something
// this version doesn't understand. So, nothing to do. This is
// different from feature not being specified at all, in which case
// this method should not get called and we should continue with the
// "all features" blocklisting.
return -1;
}
static int32_t
@@ -521,6 +530,11 @@ BlacklistEntryToDriverInfo(nsIDOMNode* aBlacklistEntry,
getter_AddRefs(dataNode))) {
BlacklistNodeToTextValue(dataNode, dataValue);
aDriverInfo.mFeature = BlacklistFeatureToGfxFeature(dataValue);
if (aDriverInfo.mFeature < 0) {
// If we don't recognize the feature, we do not want to proceed.
gfxWarning() << "Unrecognized feature " << NS_ConvertUTF16toUTF8(dataValue).get();
return false;
}
}
// <featureStatus> BLOCKED_DRIVER_VERSION </featureStatus>
@@ -649,6 +663,17 @@ GfxInfoBase::Init()
NS_IMETHODIMP
GfxInfoBase::GetFeatureStatus(int32_t aFeature, int32_t* aStatus)
{
int32_t blocklistAll = gfxPrefs::BlocklistAll();
if (blocklistAll > 0) {
gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Forcing blocklisting all features";
*aStatus = FEATURE_BLOCKED_DEVICE;
return NS_OK;
} else if (blocklistAll < 0) {
gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false)) << "Ignoring any feature blocklisting.";
*aStatus = FEATURE_STATUS_OK;
return NS_OK;
}
if (GetPrefValueForFeature(aFeature, *aStatus))
return NS_OK;
@@ -1141,6 +1166,92 @@ GfxInfoBase::GetMonitors(JSContext* aCx, JS::MutableHandleValue aResult)
return NS_OK;
}
static const char*
GetLayersBackendName(layers::LayersBackend aBackend)
{
switch (aBackend) {
case layers::LayersBackend::LAYERS_NONE:
return "none";
case layers::LayersBackend::LAYERS_OPENGL:
return "opengl";
case layers::LayersBackend::LAYERS_D3D9:
return "d3d9";
case layers::LayersBackend::LAYERS_D3D11:
return "d3d11";
case layers::LayersBackend::LAYERS_CLIENT:
return "client";
case layers::LayersBackend::LAYERS_BASIC:
return "basic";
default:
MOZ_ASSERT_UNREACHABLE("unknown layers backend");
return "unknown";
}
}
nsresult
GfxInfoBase::GetFeatures(JSContext* aCx, JS::MutableHandle<JS::Value> aOut)
{
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (!obj) {
return NS_ERROR_OUT_OF_MEMORY;
}
aOut.setObject(*obj);
layers::LayersBackend backend = gfxPlatform::Initialized()
? gfxPlatform::GetPlatform()->GetCompositorBackend()
: layers::LayersBackend::LAYERS_NONE;
const char* backendName = GetLayersBackendName(backend);
{
JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, backendName));
JS::Rooted<JS::Value> val(aCx, StringValue(str));
JS_SetProperty(aCx, obj, "compositor", val);
}
// If graphics isn't initialized yet, just stop now.
if (!gfxPlatform::Initialized()) {
return NS_OK;
}
DescribeFeatures(aCx, obj);
return NS_OK;
}
void
GfxInfoBase::DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut)
{
}
bool
GfxInfoBase::InitFeatureObject(JSContext* aCx,
JS::Handle<JSObject*> aContainer,
const char* aName,
mozilla::gfx::FeatureStatus aFeatureStatus,
JS::MutableHandle<JSObject*> aOutObj)
{
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (!obj) {
return false;
}
const char* status = FeatureStatusToString(aFeatureStatus);
// Set "status".
{
JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, status));
JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
JS_SetProperty(aCx, obj, "status", val);
}
// Add the feature object to the container.
{
JS::Rooted<JS::Value> val(aCx, JS::ObjectValue(*obj));
JS_SetProperty(aCx, aContainer, aName, val);
}
aOutObj.set(obj);
return true;
}
GfxInfoCollectorBase::GfxInfoCollectorBase()
{
GfxInfoBase::AddCollector(this);
+10
View File
@@ -19,6 +19,7 @@
#include "nsTArray.h"
#include "nsString.h"
#include "GfxInfoCollector.h"
#include "gfxTelemetry.h"
#include "nsIGfxInfoDebug.h"
#include "mozilla/Mutex.h"
#include "js/Value.h"
@@ -58,6 +59,7 @@ public:
NS_IMETHOD GetFailures(uint32_t *failureCount, int32_t** indices, char ***failures) override;
NS_IMETHOD_(void) LogFailure(const nsACString &failure) override;
NS_IMETHOD GetInfo(JSContext*, JS::MutableHandle<JS::Value>) override;
NS_IMETHOD GetFeatures(JSContext*, JS::MutableHandle<JS::Value>) override;
// Initialization function. If you override this, you must call this class's
// version of Init first.
@@ -103,6 +105,14 @@ protected:
// (while subclasses check for more specific ones).
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo() = 0;
virtual void DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> obj);
bool InitFeatureObject(
JSContext* aCx,
JS::Handle<JSObject*> aContainer,
const char* aName,
mozilla::gfx::FeatureStatus aFeatureStatus,
JS::MutableHandle<JSObject*> aOutObj);
private:
virtual int32_t FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& aDriverInfo,
nsAString& aSuggestedVersion,
+2
View File
@@ -1149,6 +1149,8 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
WindowUsesOMTC();
mLayerManager = lm.forget();
gfxPlatform::GetPlatform()->NotifyCompositorCreated(mLayerManager->GetCompositorBackendType());
}
bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
+33 -7
View File
@@ -8,7 +8,7 @@
/* NOTE: this interface is completely undesigned, not stable and likely to change */
[scriptable, uuid(d9333198-838d-4976-881f-4d9a77819453)]
[scriptable, uuid(98690931-c9a5-4675-9ab4-90932ec32bf2)]
interface nsIGfxInfo : nsISupports
{
/*
@@ -76,7 +76,7 @@ interface nsIGfxInfo : nsISupports
* A set of constants for features that we can ask this GfxInfo object
* about via GetFeatureStatus
*/
/* Don't assign 0 or -1 */
/* Don't assign any value <= 0 */
/* Whether Direct2D is supported for content rendering. */
const long FEATURE_DIRECT2D = 1;
/* Whether Direct3D 9 is supported for layers. */
@@ -93,15 +93,15 @@ interface nsIGfxInfo : nsISupports
const long FEATURE_WEBGL_ANGLE = 7;
/* Whether WebGL antialiasing is supported. */
const long FEATURE_WEBGL_MSAA = 8;
/* Whether Stagefright is supported */
/* Whether Stagefright is supported, starting in 17. */
const long FEATURE_STAGEFRIGHT = 9;
/* Whether Webrtc Hardware acceleration is supported */
/* Whether Webrtc Hardware acceleration is supported, starting in 31. */
const long FEATURE_WEBRTC_HW_ACCELERATION = 10;
/* Whether Direct3D 11 is supported for layers. */
/* Whether Direct3D 11 is supported for layers, starting in 32. */
const long FEATURE_DIRECT3D_11_LAYERS = 11;
/* Whether hardware accelerated video decoding is supported. */
/* Whether hardware accelerated video decoding is supported, starting in 36. */
const long FEATURE_HARDWARE_VIDEO_DECODING = 12;
/* Whether Direct3D 11 is supported for ANGLE. */
/* Whether Direct3D 11 is supported for ANGLE, starting in 38. */
const long FEATURE_DIRECT3D_11_ANGLE = 13;
/*
@@ -146,5 +146,31 @@ interface nsIGfxInfo : nsISupports
[implicit_jscontext]
jsval getInfo();
// Returns an object containing information about graphics features. It is
// intended to be directly included into the Telemetry environment.
//
// "layers":
// {
// "compositor": "d3d9", "d3d11", "opengl", "basic", or "none"
// // ("none" indicates no compositors have been created)
// // Feature is one of "d3d9", "d3d11", "opengl", "basic", or "d2d".
// "<feature>": {
// // Each backend can have one of the following statuses:
// // "unused" - This feature has not been requested.
// // "unavailable" - OS version or restriction prevents use.
// // "blocked" - An internal condition (such as safe mode) prevents use.
// // "blacklisted" - Blocked due to a blacklist restriction.
// // "disabled" - User explicitly disabled this default feature.
// // "failed" - Feature failed to initialize.
// // "available" - User has this feature available by default.
// "status": "<status>",
// "version": "<version>",
// "warp": true|false, // D3D11 only.
// "textureSharing": true|false, // D3D11 only.
// }
// }
[implicit_jscontext]
jsval getFeatures();
};
+36
View File
@@ -1141,6 +1141,42 @@ GfxInfo::FindMonitors(JSContext* aCx, JS::HandleObject aOutArray)
return NS_OK;
}
void
GfxInfo::DescribeFeatures(JSContext* aCx, JS::Handle<JSObject*> aObj)
{
JS::Rooted<JSObject*> obj(aCx);
gfxWindowsPlatform* platform = gfxWindowsPlatform::GetPlatform();
gfx::FeatureStatus d3d11 = platform->GetD3D11Status();
if (!InitFeatureObject(aCx, aObj, "d3d11", d3d11, &obj)) {
return;
}
if (d3d11 == gfx::FeatureStatus::Available) {
JS::Rooted<JS::Value> val(aCx, JS::Int32Value(platform->GetD3D11Version()));
JS_SetProperty(aCx, obj, "version", val);
val = JS::BooleanValue(platform->IsWARP());
JS_SetProperty(aCx, obj, "warp", val);
val = JS::BooleanValue(platform->DoesD3D11TextureSharingWork());
JS_SetProperty(aCx, obj, "textureSharing", val);
}
gfx::FeatureStatus d2d = platform->GetD2DStatus();
if (!InitFeatureObject(aCx, aObj, "d2d", d2d, &obj)) {
return;
}
{
const char* version = "1.0";
if (platform->GetD2D1Status() == gfx::FeatureStatus::Available)
version = "1.1";
JS::Rooted<JSString*> str(aCx, JS_NewStringCopyZ(aCx, version));
JS::Rooted<JS::Value> val(aCx, JS::StringValue(str));
JS_SetProperty(aCx, obj, "version", val);
}
}
#ifdef DEBUG
// Implement nsIGfxInfoDebug
+2
View File
@@ -68,6 +68,8 @@ protected:
OperatingSystem* aOS = nullptr);
virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo();
void DescribeFeatures(JSContext* cx, JS::Handle<JSObject*> aOut) override;
private:
void GetCountryCode();
+5 -1
View File
@@ -317,7 +317,11 @@ nsConsoleService::LogMessageWithMode(nsIConsoleMessage* aMessage,
}
if (r) {
NS_DispatchToMainThread(r);
// avoid failing in XPCShell tests
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (mainThread) {
NS_DispatchToMainThread(r.forget());
}
}
return NS_OK;
+18 -7
View File
@@ -161,6 +161,22 @@ NS_DispatchToCurrentThread(nsIRunnable* aEvent)
return thread->Dispatch(aEvent, NS_DISPATCH_NORMAL);
}
NS_METHOD
NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDispatchFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
nsCOMPtr<nsIThread> thread;
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
NS_ASSERTION(false, "Failed NS_DispatchToMainThread() in shutdown; leaking");
// NOTE: if you stop leaking here, adjust Promise::MaybeReportRejected(),
// which assumes a leak here, or split into leaks and no-leaks versions
nsIRunnable* temp = event.forget().take(); // leak without using "unused <<" due to Windows (boo)
return temp ? rv : rv; // to make compiler not bletch on us
}
return thread->Dispatch(event.forget(), aDispatchFlags);
}
// In the case of failure with a newly allocated runnable with a
// refcount of zero, we intentionally leak the runnable, because it is
// likely that the runnable is being dispatched to the main thread
@@ -169,12 +185,8 @@ NS_DispatchToCurrentThread(nsIRunnable* aEvent)
NS_METHOD
NS_DispatchToMainThread(nsIRunnable* aEvent, uint32_t aDispatchFlags)
{
nsCOMPtr<nsIThread> thread;
nsresult rv = NS_GetMainThread(getter_AddRefs(thread));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return thread->Dispatch(aEvent, aDispatchFlags);
nsCOMPtr<nsIRunnable> event(aEvent);
return NS_DispatchToMainThread(event.forget(), aDispatchFlags);
}
#ifndef XPCOM_GLUE_AVOID_NSPR
@@ -374,4 +386,3 @@ nsAutoLowPriorityIO::~nsAutoLowPriorityIO()
}
#endif
}
+3
View File
@@ -123,6 +123,9 @@ extern NS_METHOD NS_DispatchToCurrentThread(nsIRunnable* aEvent);
extern NS_METHOD
NS_DispatchToMainThread(nsIRunnable* aEvent,
uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
extern NS_METHOD
NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent,
uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
#ifndef XPCOM_GLUE_AVOID_NSPR
/**
+2 -1
View File
@@ -53,7 +53,8 @@ nsTSubstring_CharT::MutatePrep(size_type aCapacity, char_type** aOldData,
// If |aCapacity > kMaxCapacity|, then our doubling algorithm may not be
// able to allocate it. Just bail out in cases like that. We don't want
// to be allocating 2GB+ strings anyway.
PR_STATIC_ASSERT((sizeof(nsStringBuffer) & 0x1) == 0);
static_assert((sizeof(nsStringBuffer) & 0x1) == 0,
"bad size for nsStringBuffer");
const size_type kMaxCapacity =
(size_type(-1) / 2 - sizeof(nsStringBuffer)) / sizeof(char_type) - 2;
if (aCapacity > kMaxCapacity) {
+15 -7
View File
@@ -109,7 +109,7 @@ LazyIdleThread::EnableIdleTimeout()
if (mThread) {
nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(Dispatch(runnable.forget(), NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch!");
}
}
@@ -302,7 +302,7 @@ LazyIdleThread::ShutdownThread()
PreDispatch();
rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
rv = mThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -343,7 +343,7 @@ LazyIdleThread::ShutdownThread()
runnable.swap(queuedRunnables[index]);
MOZ_ASSERT(runnable, "Null runnable?!");
if (NS_FAILED(Dispatch(runnable, NS_DISPATCH_NORMAL))) {
if (NS_FAILED(Dispatch(runnable.forget(), NS_DISPATCH_NORMAL))) {
NS_ERROR("Failed to re-dispatch queued runnable!");
}
}
@@ -395,10 +395,18 @@ NS_IMPL_QUERY_INTERFACE(LazyIdleThread, nsIThread,
nsIObserver)
NS_IMETHODIMP
LazyIdleThread::Dispatch(nsIRunnable* aEvent,
LazyIdleThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
LazyIdleThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
uint32_t aFlags)
{
ASSERT_OWNING_THREAD();
nsCOMPtr<nsIRunnable> event(aEvent); // avoid leaks
// LazyIdleThread can't always support synchronous dispatch currently.
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
@@ -412,7 +420,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
// If our thread is shutting down then we can't actually dispatch right now.
// Queue this runnable for later.
if (UseRunnableQueue()) {
mQueuedRunnables->AppendElement(aEvent);
mQueuedRunnables->AppendElement(event);
return NS_OK;
}
@@ -423,7 +431,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent,
PreDispatch();
return mThread->Dispatch(aEvent, aFlags);
return mThread->Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
@@ -557,7 +565,7 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
return NS_ERROR_UNEXPECTED;
}
nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
nsresult rv = mOwningThread->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+4
View File
@@ -45,6 +45,10 @@ public:
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSITHREADOBSERVER
NS_DECL_NSIOBSERVER
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
enum ShutdownMethod
{
+3 -3
View File
@@ -453,9 +453,9 @@ TimerThread::AddTimerInternal(nsTimerImpl* aTimer)
NS_ADDREF(aTimer);
#ifdef MOZ_TASK_TRACER
// Create a FakeTracedTask, and dispatch it here. This is the start point of
// the latency.
aTimer->DispatchTracedTask();
// Caller of AddTimer is the parent task of its timer event, so we store the
// TraceInfo here for later used.
aTimer->GetTLSTraceInfo();
#endif
return insertSlot - mTimers.Elements();
+7
View File
@@ -84,6 +84,13 @@ nsEventQueue::GetEvent(bool aMayWait, nsIRunnable** aResult)
void
nsEventQueue::PutEvent(nsIRunnable* aRunnable)
{
nsCOMPtr<nsIRunnable> event(aRunnable);
PutEvent(event.forget());
}
void
nsEventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aRunnable)
{
// Avoid calling AddRef+Release while holding our monitor.
nsCOMPtr<nsIRunnable> event(aRunnable);
+3
View File
@@ -10,6 +10,8 @@
#include <stdlib.h>
#include "mozilla/ReentrantMonitor.h"
#include "nsIRunnable.h"
#include "nsCOMPtr.h"
#include "mozilla/AlreadyAddRefed.h"
// A threadsafe FIFO event queue...
class nsEventQueue
@@ -24,6 +26,7 @@ public:
// a strong reference to the event after this method returns. This method
// cannot fail.
void PutEvent(nsIRunnable* aEvent);
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent);
// This method gets an event from the event queue. If mayWait is true, then
// the method will block the calling thread until an event is available. If
+52 -18
View File
@@ -5,29 +5,28 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
#include "nsIRunnable.idl"
%{C++
#include "nsCOMPtr.h"
#include "mozilla/AlreadyAddRefed.h"
%}
interface nsIRunnable;
native alreadyAddRefed_nsIRunnable(already_AddRefed<nsIRunnable>&&);
[scriptable, uuid(4e8febe4-6631-49dc-8ac9-308c1cb9b09c)]
[scriptable, uuid(f9d60700-e6dc-4a72-9537-689058655472)]
interface nsIEventTarget : nsISupports
{
/* until we can get rid of all uses, keep the non-alreadyAddRefed<> version */
/**
* Dispatch an event to this event target. This function may be called from
* any thread, and it may be called re-entrantly.
*
* @param event
* The event to dispatch.
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
* This must be non-virtual due to issues with MSVC 2013's ordering of
* vtbls for overloads. With other platforms we can leave this virtual
* and avoid adding lots of Dispatch() methods to classes inheriting this.
*/
void dispatch(in nsIRunnable event, in unsigned long flags);
%{C++
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
%}
/**
* This flag specifies the default mode of event dispatch, whereby the event
@@ -45,7 +44,7 @@ interface nsIEventTarget : nsISupports
* given event to be processed.
*/
const unsigned long DISPATCH_SYNC = 1;
/**
* Check to see if this event target is associated with the current thread.
*
@@ -55,6 +54,41 @@ interface nsIEventTarget : nsISupports
* this method).
*/
boolean isOnCurrentThread();
/**
* Dispatch an event to this event target. This function may be called from
* any thread, and it may be called re-entrantly.
*
* @param event
* The alreadyAddRefed<> event to dispatch
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
*/
[noscript, binaryname(Dispatch)] void dispatchFromC(in alreadyAddRefed_nsIRunnable event, in unsigned long flags);
/**
* Version of Dispatch to expose to JS, which doesn't require an alreadyAddRefed<>
* (it will be converted to that internally)
*
* @param event
* The (raw) event to dispatch.
* @param flags
* The flags modifying event dispatch. The flags are described in detail
* below.
*
* @throws NS_ERROR_INVALID_ARG
* Indicates that event is null.
* @throws NS_ERROR_UNEXPECTED
* Indicates that the thread is shutting down and has finished processing
* events, so this event would never run and has not been dispatched.
*/
[binaryname(DispatchFromScript)] void dispatch(in nsIRunnable event, in unsigned long flags);
};
%{C++
+1 -1
View File
@@ -27,7 +27,7 @@ interface nsIThreadPoolListener : nsISupports
* anonymous (unnamed) worker threads. An event dispatched to the thread pool
* will be run on the next available worker thread.
*/
[scriptable, uuid(53675068-cb3a-40e5-a026-1be5a97c9b23)]
[scriptable, uuid(cacd4a2e-2655-4ff8-894c-10c15883cd0a)]
interface nsIThreadPool : nsIEventTarget
{
/**
+45 -18
View File
@@ -67,6 +67,7 @@
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracer.h"
#include "TracedTaskCommon.h"
using namespace mozilla::tasktracer;
#endif
@@ -446,7 +447,7 @@ nsThread::Init()
// that mThread is set properly.
{
MutexAutoLock lock(mLock);
mEventsRoot.PutEvent(startup);
mEventsRoot.PutEvent(startup); // retain a reference
}
// Wait for thread to call ThreadManager::SetupCurrentThread, which completes
@@ -467,6 +468,13 @@ nsThread::InitCurrentThread()
nsresult
nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return PutEvent(event.forget(), aTarget);
}
nsresult
nsThread::PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget* aTarget)
{
nsCOMPtr<nsIThreadObserver> obs;
@@ -475,9 +483,11 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
nsChainedEventQueue* queue = aTarget ? aTarget->mQueue : &mEventsRoot;
if (!queue || (queue == &mEventsRoot && mEventsAreDoomed)) {
NS_WARNING("An event was posted to a thread that will never run it (rejected)");
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIRunnable> temp(aEvent);
nsIRunnable* temp2 = temp.forget().take(); // can't use unused << aEvent here due to Windows (boo)
return temp2 ? NS_ERROR_UNEXPECTED : NS_ERROR_UNEXPECTED; // to make compiler not bletch on us
}
queue->PutEvent(aEvent);
queue->PutEvent(Move(aEvent));
// Make sure to grab the observer before dropping the lock, otherwise the
// event that we just placed into the queue could run and eventually delete
@@ -494,20 +504,23 @@ nsThread::PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget)
}
nsresult
nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
nsThread::DispatchInternal(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags,
nsNestedEventTarget* aTarget)
{
if (NS_WARN_IF(!aEvent)) {
nsCOMPtr<nsIRunnable> event(aEvent);
if (NS_WARN_IF(!event)) {
return NS_ERROR_INVALID_ARG;
}
if (gXPCOMThreadsShutDown && MAIN_THREAD != mIsMainThread && !aTarget) {
NS_ASSERTION(false, "Failed Dispatch after xpcom-shutdown-threads");
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
}
#ifdef MOZ_TASK_TRACER
nsCOMPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(aEvent);
aEvent = tracedRunnable;
nsCOMPtr<nsIRunnable> tracedRunnable = CreateTracedRunnable(event); // adds a ref
(static_cast<TracedRunnable*>(tracedRunnable.get()))->DispatchTask();
event = tracedRunnable.forget();
#endif
if (aFlags & DISPATCH_SYNC) {
@@ -521,8 +534,8 @@ nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
// that to tell us when the event has been processed.
nsRefPtr<nsThreadSyncDispatch> wrapper =
new nsThreadSyncDispatch(thread, aEvent);
nsresult rv = PutEvent(wrapper, aTarget);
new nsThreadSyncDispatch(thread, event.forget());
nsresult rv = PutEvent(wrapper, aTarget); // hold a ref
// Don't wait for the event to finish if we didn't dispatch it...
if (NS_FAILED(rv)) {
return rv;
@@ -536,18 +549,25 @@ nsThread::DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
}
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
return PutEvent(aEvent, aTarget);
return PutEvent(event.forget(), aTarget);
}
//-----------------------------------------------------------------------------
// nsIEventTarget
NS_IMETHODIMP
nsThread::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x]\n", this, aEvent, aFlags));
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
return DispatchInternal(aEvent, aFlags, nullptr);
NS_IMETHODIMP
nsThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x]\n", this, /* XXX aEvent */nullptr, aFlags));
return DispatchInternal(Move(aEvent), aFlags, nullptr);
}
NS_IMETHODIMP
@@ -600,7 +620,7 @@ nsThread::Shutdown()
// events to process.
nsCOMPtr<nsIRunnable> event = new nsThreadShutdownEvent(this, &context);
// XXXroc What if posting the event fails due to OOM?
PutEvent(event, nullptr);
PutEvent(event.forget(), nullptr);
// We could still end up with other events being added after the shutdown
// task, but that's okay because we process pending events in ThreadFunc
@@ -983,7 +1003,7 @@ nsThread::PopEventQueue(nsIEventTarget* aInnermostTarget)
nsCOMPtr<nsIRunnable> event;
while (queue->GetEvent(false, getter_AddRefs(event))) {
mEvents->PutEvent(event);
mEvents->PutEvent(event.forget());
}
// Don't let the event target post any more events.
@@ -1028,12 +1048,19 @@ nsThreadSyncDispatch::Run()
NS_IMPL_ISUPPORTS(nsThread::nsNestedEventTarget, nsIEventTarget)
NS_IMETHODIMP
nsThread::nsNestedEventTarget::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThread::nsNestedEventTarget::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), aEvent,
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
nsThread::nsNestedEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD(%p) Dispatch [%p %x] to nested loop %p\n", mThread.get(), /*XXX aEvent*/ nullptr,
aFlags, this));
return mThread->DispatchInternal(aEvent, aFlags, this);
return mThread->DispatchInternal(Move(aEvent), aFlags, this);
}
NS_IMETHODIMP
+13 -2
View File
@@ -16,6 +16,7 @@
#include "nsTObserverArray.h"
#include "mozilla/Attributes.h"
#include "nsAutoPtr.h"
#include "mozilla/AlreadyAddRefed.h"
// A native thread
class nsThread
@@ -28,6 +29,10 @@ public:
NS_DECL_NSITHREAD
NS_DECL_NSITHREADINTERNAL
NS_DECL_NSISUPPORTSPRIORITY
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
enum MainThreadFlag
{
@@ -98,8 +103,9 @@ protected:
return mEvents->GetEvent(aMayWait, aEvent);
}
nsresult PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget);
nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent, nsNestedEventTarget* aTarget);
nsresult DispatchInternal(nsIRunnable* aEvent, uint32_t aFlags,
nsresult DispatchInternal(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags,
nsNestedEventTarget* aTarget);
// Wrapper for nsEventQueue that supports chaining.
@@ -121,6 +127,11 @@ protected:
mQueue.PutEvent(aEvent);
}
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent)
{
mQueue.PutEvent(mozilla::Move(aEvent));
}
bool HasPendingEvent()
{
return mQueue.HasPendingEvent();
@@ -189,7 +200,7 @@ protected:
class nsThreadSyncDispatch : public nsRunnable
{
public:
nsThreadSyncDispatch(nsIThread* aOrigin, nsIRunnable* aTask)
nsThreadSyncDispatch(nsIThread* aOrigin, already_AddRefed<nsIRunnable>&& aTask)
: mOrigin(aOrigin)
, mSyncTask(aTask)
, mResult(NS_ERROR_NOT_INITIALIZED)
+19 -5
View File
@@ -66,6 +66,13 @@ nsThreadPool::~nsThreadPool()
nsresult
nsThreadPool::PutEvent(nsIRunnable* aEvent)
{
nsCOMPtr<nsIRunnable> event(aEvent);
return PutEvent(event.forget());
}
nsresult
nsThreadPool::PutEvent(already_AddRefed<nsIRunnable>&& aEvent)
{
// Avoid spawning a new thread while holding the event queue lock...
@@ -89,7 +96,7 @@ nsThreadPool::PutEvent(nsIRunnable* aEvent)
spawnThread = true;
}
mEvents.PutEvent(aEvent);
mEvents.PutEvent(Move(aEvent));
stackSize = mStackSize;
}
@@ -235,9 +242,16 @@ nsThreadPool::Run()
}
NS_IMETHODIMP
nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
nsThreadPool::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags)
{
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, aEvent, aFlags));
nsCOMPtr<nsIRunnable> event(aEvent);
return Dispatch(event.forget(), aFlags);
}
NS_IMETHODIMP
nsThreadPool::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
{
LOG(("THRD-P(%p) dispatch [%p %x]\n", this, /* XXX aEvent*/ nullptr, aFlags));
if (NS_WARN_IF(mShutdown)) {
return NS_ERROR_NOT_AVAILABLE;
@@ -251,7 +265,7 @@ nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
}
nsRefPtr<nsThreadSyncDispatch> wrapper =
new nsThreadSyncDispatch(thread, aEvent);
new nsThreadSyncDispatch(thread, Move(aEvent));
PutEvent(wrapper);
while (wrapper->IsPending()) {
@@ -259,7 +273,7 @@ nsThreadPool::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
}
} else {
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL, "unexpected dispatch flags");
PutEvent(aEvent);
PutEvent(Move(aEvent));
}
return NS_OK;
}
+6
View File
@@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsThreadUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AlreadyAddRefed.h"
class nsThreadPool final
: public nsIThreadPool
@@ -25,6 +26,10 @@ public:
NS_DECL_NSIEVENTTARGET
NS_DECL_NSITHREADPOOL
NS_DECL_NSIRUNNABLE
// missing from NS_DECL_NSIEVENTTARGET because MSVC
nsresult Dispatch(nsIRunnable* aEvent, uint32_t aFlags) {
return Dispatch(nsCOMPtr<nsIRunnable>(aEvent).forget(), aFlags);
}
nsThreadPool();
@@ -33,6 +38,7 @@ private:
void ShutdownThread(nsIThread* aThread);
nsresult PutEvent(nsIRunnable* aEvent);
nsresult PutEvent(already_AddRefed<nsIRunnable>&& aEvent);
nsCOMArray<nsIThread> mThreads;
nsEventQueue mEvents;
+41 -40
View File
@@ -17,6 +17,10 @@
#ifdef MOZ_NUWA_PROCESS
#include "ipc/Nuwa.h"
#endif
#ifdef MOZ_TASK_TRACER
#include "GeckoTaskTracerImpl.h"
using namespace mozilla::tasktracer;
#endif
using mozilla::Atomic;
using mozilla::LogLevel;
@@ -274,7 +278,7 @@ nsTimerImpl::Release(void)
nsTimerImpl::nsTimerImpl() :
mClosure(nullptr),
mCallbackType(CALLBACK_TYPE_UNKNOWN),
mCallbackType(CallbackType::Unknown),
mFiring(false),
mArmed(false),
mCanceled(false),
@@ -393,7 +397,7 @@ nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc,
}
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_FUNC;
mCallbackType = CallbackType::Function;
mCallback.c = aFunc;
mClosure = aClosure;
@@ -410,7 +414,7 @@ nsTimerImpl::InitWithCallback(nsITimerCallback* aCallback,
}
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_INTERFACE;
mCallbackType = CallbackType::Interface;
mCallback.i = aCallback;
NS_ADDREF(mCallback.i);
@@ -425,7 +429,7 @@ nsTimerImpl::Init(nsIObserver* aObserver, uint32_t aDelay, uint32_t aType)
}
ReleaseCallback();
mCallbackType = CALLBACK_TYPE_OBSERVER;
mCallbackType = CallbackType::Observer;
mCallback.o = aObserver;
NS_ADDREF(mCallback.o);
@@ -449,7 +453,7 @@ nsTimerImpl::Cancel()
NS_IMETHODIMP
nsTimerImpl::SetDelay(uint32_t aDelay)
{
if (mCallbackType == CALLBACK_TYPE_UNKNOWN && mType == TYPE_ONE_SHOT) {
if (mCallbackType == CallbackType::Unknown && mType == TYPE_ONE_SHOT) {
// This may happen if someone tries to re-use a one-shot timer
// by re-setting delay instead of reinitializing the timer.
NS_ERROR("nsITimer->SetDelay() called when the "
@@ -508,7 +512,7 @@ nsTimerImpl::GetClosure(void** aClosure)
NS_IMETHODIMP
nsTimerImpl::GetCallback(nsITimerCallback** aCallback)
{
if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
if (mCallbackType == CallbackType::Interface) {
NS_IF_ADDREF(*aCallback = mCallback.i);
} else if (mTimerCallbackWhileFiring) {
NS_ADDREF(*aCallback = mTimerCallbackWhileFiring);
@@ -531,7 +535,7 @@ nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
NS_IMETHODIMP
nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
{
if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN)) {
if (NS_WARN_IF(mCallbackType != CallbackType::Unknown)) {
return NS_ERROR_ALREADY_INITIALIZED;
}
@@ -556,13 +560,6 @@ nsTimerImpl::Fire()
js::ProfileEntry::Category::OTHER);
#endif
#ifdef MOZ_TASK_TRACER
// mTracedTask is an instance of FakeTracedTask created by
// DispatchTracedTask(). AutoRunFakeTracedTask logs the begin/end time of the
// timer/FakeTracedTask instance in ctor/dtor.
mozilla::tasktracer::AutoRunFakeTracedTask runTracedTask(mTracedTask);
#endif
TimeStamp now = TimeStamp::Now();
if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
TimeDuration a = now - mStart; // actual delay in intervals
@@ -595,7 +592,7 @@ nsTimerImpl::Fire()
timeout -= TimeDuration::FromMilliseconds(mDelay);
}
if (mCallbackType == CALLBACK_TYPE_INTERFACE) {
if (mCallbackType == CallbackType::Interface) {
mTimerCallbackWhileFiring = mCallback.i;
}
mFiring = true;
@@ -603,22 +600,22 @@ nsTimerImpl::Fire()
// Handle callbacks that re-init the timer, but avoid leaking.
// See bug 330128.
CallbackUnion callback = mCallback;
unsigned callbackType = mCallbackType;
if (callbackType == CALLBACK_TYPE_INTERFACE) {
CallbackType callbackType = mCallbackType;
if (callbackType == CallbackType::Interface) {
NS_ADDREF(callback.i);
} else if (callbackType == CALLBACK_TYPE_OBSERVER) {
} else if (callbackType == CallbackType::Observer) {
NS_ADDREF(callback.o);
}
ReleaseCallback();
switch (callbackType) {
case CALLBACK_TYPE_FUNC:
case CallbackType::Function:
callback.c(this, mClosure);
break;
case CALLBACK_TYPE_INTERFACE:
case CallbackType::Interface:
callback.i->Notify(this);
break;
case CALLBACK_TYPE_OBSERVER:
case CallbackType::Observer:
callback.o->Observe(static_cast<nsITimer*>(this),
NS_TIMER_CALLBACK_TOPIC,
nullptr);
@@ -629,15 +626,15 @@ nsTimerImpl::Fire()
// If the callback didn't re-init the timer, and it's not a one-shot timer,
// restore the callback state.
if (mCallbackType == CALLBACK_TYPE_UNKNOWN &&
if (mCallbackType == CallbackType::Unknown &&
mType != TYPE_ONE_SHOT && !mCanceled) {
mCallback = callback;
mCallbackType = callbackType;
} else {
// The timer was a one-shot, or the callback was reinitialized.
if (callbackType == CALLBACK_TYPE_INTERFACE) {
if (callbackType == CallbackType::Interface) {
NS_RELEASE(callback.i);
} else if (callbackType == CALLBACK_TYPE_OBSERVER) {
} else if (callbackType == CallbackType::Observer) {
NS_RELEASE(callback.o);
}
}
@@ -752,6 +749,14 @@ nsTimerImpl::PostTimerEvent(already_AddRefed<nsTimerImpl> aTimerRef)
}
}
#ifdef MOZ_TASK_TRACER
// During the dispatch of TimerEvent, we overwrite the current TraceInfo
// partially with the info saved in timer earlier, and restore it back by
// AutoSaveCurTraceInfo.
AutoSaveCurTraceInfo saveCurTraceInfo;
(timer->GetTracedTask()).SetTLSTraceInfo();
#endif
nsIEventTarget* target = timer->mEventTarget;
event->SetTimer(timer.forget());
@@ -796,21 +801,17 @@ nsTimerImpl::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
return aMallocSizeOf(this);
}
// NOT FOR PUBLIC CONSUMPTION!
nsresult
NS_NewTimer(nsITimer** aResult, nsTimerCallbackFunc aCallback, void* aClosure,
uint32_t aDelay, uint32_t aType)
#ifdef MOZ_TASK_TRACER
void
nsTimerImpl::GetTLSTraceInfo()
{
nsTimerImpl* timer = new nsTimerImpl();
NS_ADDREF(timer);
nsresult rv = timer->InitWithFuncCallback(aCallback, aClosure,
aDelay, aType);
if (NS_FAILED(rv)) {
NS_RELEASE(timer);
return rv;
}
*aResult = timer;
return NS_OK;
mTracedTask.GetTLSTraceInfo();
}
TracedTaskCommon
nsTimerImpl::GetTracedTask()
{
return mTracedTask;
}
#endif
+22 -22
View File
@@ -31,14 +31,6 @@ extern PRLogModuleInfo* GetTimerLog();
{0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
}
enum
{
CALLBACK_TYPE_UNKNOWN = 0,
CALLBACK_TYPE_INTERFACE = 1,
CALLBACK_TYPE_FUNC = 2,
CALLBACK_TYPE_OBSERVER = 3
};
class nsTimerImpl final : public nsITimer
{
public:
@@ -67,15 +59,20 @@ public:
}
#ifdef MOZ_TASK_TRACER
void DispatchTracedTask()
{
mTracedTask = mozilla::tasktracer::CreateFakeTracedTask(*(int**)(this));
}
void GetTLSTraceInfo();
mozilla::tasktracer::TracedTaskCommon GetTracedTask();
#endif
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
private:
enum class CallbackType : uint8_t {
Unknown = 0,
Interface = 1,
Function = 2,
Observer = 3,
};
~nsTimerImpl();
nsresult InitCommon(uint32_t aType, uint32_t aDelay);
@@ -84,21 +81,24 @@ private:
// if we're the last owner of the callback object, make
// sure that we don't recurse into ReleaseCallback in case
// the callback's destructor calls Cancel() or similar.
uint8_t cbType = mCallbackType;
mCallbackType = CALLBACK_TYPE_UNKNOWN;
CallbackType cbType = mCallbackType;
mCallbackType = CallbackType::Unknown;
if (cbType == CALLBACK_TYPE_INTERFACE) {
if (cbType == CallbackType::Interface) {
NS_RELEASE(mCallback.i);
} else if (cbType == CALLBACK_TYPE_OBSERVER) {
} else if (cbType == CallbackType::Observer) {
NS_RELEASE(mCallback.o);
}
}
bool IsRepeating() const
{
PR_STATIC_ASSERT(TYPE_ONE_SHOT < TYPE_REPEATING_SLACK);
PR_STATIC_ASSERT(TYPE_REPEATING_SLACK < TYPE_REPEATING_PRECISE);
PR_STATIC_ASSERT(TYPE_REPEATING_PRECISE < TYPE_REPEATING_PRECISE_CAN_SKIP);
static_assert(TYPE_ONE_SHOT < TYPE_REPEATING_SLACK,
"invalid ordering of timer types!");
static_assert(TYPE_REPEATING_SLACK < TYPE_REPEATING_PRECISE,
"invalid ordering of timer types!");
static_assert(TYPE_REPEATING_PRECISE < TYPE_REPEATING_PRECISE_CAN_SKIP,
"invalid ordering of timer types!");
return mType >= TYPE_REPEATING_SLACK;
}
@@ -122,8 +122,8 @@ private:
// timer is firing.
nsCOMPtr<nsITimerCallback> mTimerCallbackWhileFiring;
// These members are set by Init (called from NS_NewTimer) and never reset.
uint8_t mCallbackType;
// These members are set by Init and never reset.
CallbackType mCallbackType;
// These members are set by the initiating thread, when the timer's type is
// changed and during the period where it fires on that thread.
@@ -147,7 +147,7 @@ private:
TimeStamp mTimeout;
#ifdef MOZ_TASK_TRACER
nsRefPtr<mozilla::tasktracer::FakeTracedTask> mTracedTask;
mozilla::tasktracer::TracedTaskCommon mTracedTask;
#endif
TimeStamp mStart, mStart2;