/* -*- Mode: C++; tab-width: 8; 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/. */
void EnqueueTask(already_AddRefed<nsIRunnable> aTask, int aDelayMs);
/* * The AndroidUiThread is derived from nsThread so that nsIRunnable objects that * get dispatched may be intercepted. Only nsIRunnable objects that need to be * synchronously executed are passed into the nsThread to be queued. All other * nsIRunnable object are immediately dispatched to the Android UI thread. * AndroidUiThread is derived from nsThread instead of being an nsIEventTarget * wrapper that contains an nsThread object because if nsIRunnable objects with * a delay were dispatch directly to an nsThread object, such as obtained from * nsThreadManager::GetCurrentThread(), the nsIRunnable could get stuck in the * nsThread nsIRunnable queue. This is due to the fact that Android controls the * event loop in the Android UI thread and has no knowledge of when the nsThread * needs to be drained.
*/
class AndroidUiThread : public nsThread { public:
NS_INLINE_DECL_REFCOUNTING_INHERITED(AndroidUiThread, nsThread)
AndroidUiThread()
: nsThread(
MakeNotNull<ThreadEventQueue*>(MakeUnique<mozilla::EventQueue>()),
nsThread::NOT_MAIN_THREAD, {.stackSize = 0}) {}
AndroidUiTask(already_AddRefed<nsIRunnable> aTask, int aDelayMs)
: mTask(aTask),
mRunTime(TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs)) {}
bool IsEarlierThan(const AndroidUiTask& aOther) const { if (mRunTime) { return aOther.mRunTime ? mRunTime < aOther.mRunTime : false;
} // In the case of no delay, we're earlier if aOther has a delay. // Otherwise, we're not earlier, to maintain task order. return !!aOther.mRunTime;
}
private: staticvoid RegisterThreadWithProfiler() { #ifdefined(MOZ_GECKO_PROFILER) // We don't use the PROFILER_REGISTER_THREAD macro here because by this // point the Android UI thread is already quite a ways into its stack; // the profiler's sampler thread will ignore a lot of frames if we do not // provide a better value for the stack top. We'll manually obtain that // info via pthreads.
// Fallback address if any pthread calls fail char fallback; char* stackTop = &fallback;
auto regOnExit = MakeScopeExit(
[&stackTop]() { profiler_register_thread("AndroidUI", stackTop); });
pthread_attr_t attrs; if (pthread_getattr_np(pthread_self(), &attrs)) { return;
}
void EnqueueTask(already_AddRefed<nsIRunnable> aTask, int aDelayMs) { if (sThreadDestroyed) { return;
}
// add the new task into the sTaskQueue, sorted with // the earliest task first in the queue
AndroidUiTask* newTask =
(aDelayMs ? new AndroidUiTask(std::move(aTask), aDelayMs)
: new AndroidUiTask(std::move(aTask)));
while (task) { if (newTask->IsEarlierThan(*task)) {
task->setPrevious(newTask); break;
}
task = task->getNext();
}
if (!newTask->isInList()) {
sTaskQueue->insertBack(newTask);
}
headOfList = !newTask->getPrevious();
}
if (headOfList) { // if we're inserting it at the head of the queue, notify Java because // we need to get a callback at an earlier time than the last scheduled // callback
java::GeckoThread::RequestUiThreadCallback(int64_t(aDelayMs));
}
}
} // namespace
namespace mozilla {
void CreateAndroidUiThread() {
MOZ_ASSERT(!sThread);
MOZ_ASSERT(!sMessageLoopAccessMonitor);
sTaskQueue = new LinkedList<AndroidUiTask>();
sTaskQueueLock = new Mutex("AndroidUiThreadTaskQueueLock");
sMessageLoopAccessMonitor = new Monitor("AndroidUiThreadMessageLoopAccessMonitor");
sThreadDestroyed = false;
RefPtr<CreateOnUiThread> runnable = new CreateOnUiThread;
EnqueueTask(do_AddRef(runnable), 0);
}
while (!sTaskQueue->isEmpty()) {
AndroidUiTask* task = sTaskQueue->getFirst(); const int64_t timeLeft = task->MillisecondsToRunTime(); if (timeLeft > 0) { // this task (and therefore all remaining tasks) // have not yet reached their runtime. return the // time left until we should be called again return timeLeft;
}
// Retrieve task before unlocking/running.
nsCOMPtr<nsIRunnable> runnable(task->TakeTask()); // LinkedListElements auto remove from list upon destruction delete task;
// Unlock to allow posting new tasks reentrantly.
MutexAutoUnlock unlock(*sTaskQueueLock);
runnable->Run(); if (sThreadDestroyed) { return -1;
}
} return -1;
}
} // namespace mozilla
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.