mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
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:
+16
-4
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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',
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user