mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-05 10:48:15 +02:00
Have idleThreadGraceTimeout and idleThreadMaximumTimeout instead of just idleThreadTimeout. Clarify that idleThreadMaximumTimeout is only affecting allowed idle threads. Make idle threads end only after at minimum idleThreadGraceTimeout even if they are in excess. Remove the idleThreadTimeoutRegressive setting. Introduce a "most recently used" priority for notifying idle threads to avoid excessive round-robin through all available idle threads. The management of the linked list has constant time, adding thus only minimal overhead wrt to the previous wasIdle flags we had. As a side effect (and coming from the investigations in bug 1891732) to some extent this can help to improve the "logical thread affinity", together with trying to keep events dispatched with NS_DISPATCH_AT_END on the dispatching thread as much as possible, which should help TaskQueue a lot with affinity. Differential Revision: https://phabricator.services.mozilla.com/D209884
127 lines
3.9 KiB
C++
127 lines
3.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "LazyIdleThread.h"
|
|
|
|
#include "nsIObserverService.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
#ifdef DEBUG
|
|
# define ASSERT_OWNING_THREAD() \
|
|
do { \
|
|
MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread()); \
|
|
} while (0)
|
|
#else
|
|
# define ASSERT_OWNING_THREAD() /* nothing */
|
|
#endif
|
|
|
|
namespace mozilla {
|
|
|
|
LazyIdleThread::LazyIdleThread(uint32_t aIdleTimeoutMS, const char* aName,
|
|
ShutdownMethod aShutdownMethod)
|
|
: mOwningEventTarget(GetCurrentSerialEventTarget()),
|
|
mThreadPool(new nsThreadPool()),
|
|
mTaskQueue(TaskQueue::Create(do_AddRef(mThreadPool), aName)) {
|
|
// Configure the threadpool to host a single thread. It will be responsible
|
|
// for managing the thread's lifetime.
|
|
MOZ_ALWAYS_SUCCEEDS(mThreadPool->SetThreadLimit(1));
|
|
MOZ_ALWAYS_SUCCEEDS(mThreadPool->SetIdleThreadLimit(1));
|
|
MOZ_ALWAYS_SUCCEEDS(mThreadPool->SetIdleThreadGraceTimeout(0));
|
|
MOZ_ALWAYS_SUCCEEDS(mThreadPool->SetIdleThreadMaximumTimeout(aIdleTimeoutMS));
|
|
MOZ_ALWAYS_SUCCEEDS(mThreadPool->SetName(nsDependentCString(aName)));
|
|
|
|
if (aShutdownMethod == ShutdownMethod::AutomaticShutdown &&
|
|
NS_IsMainThread()) {
|
|
if (nsCOMPtr<nsIObserverService> obs =
|
|
do_GetService(NS_OBSERVERSERVICE_CONTRACTID)) {
|
|
MOZ_ALWAYS_SUCCEEDS(
|
|
obs->AddObserver(this, "xpcom-shutdown-threads", false));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void LazyIdleThreadShutdown(nsThreadPool* aThreadPool,
|
|
TaskQueue* aTaskQueue) {
|
|
aTaskQueue->BeginShutdown();
|
|
aTaskQueue->AwaitShutdownAndIdle();
|
|
aThreadPool->Shutdown();
|
|
}
|
|
|
|
LazyIdleThread::~LazyIdleThread() {
|
|
if (!mShutdown) {
|
|
mOwningEventTarget->Dispatch(NS_NewRunnableFunction(
|
|
"LazyIdleThread::~LazyIdleThread",
|
|
[threadPool = mThreadPool, taskQueue = mTaskQueue] {
|
|
LazyIdleThreadShutdown(threadPool, taskQueue);
|
|
}));
|
|
}
|
|
}
|
|
|
|
void LazyIdleThread::Shutdown() {
|
|
ASSERT_OWNING_THREAD();
|
|
|
|
if (!mShutdown) {
|
|
mShutdown = true;
|
|
LazyIdleThreadShutdown(mThreadPool, mTaskQueue);
|
|
}
|
|
}
|
|
|
|
nsresult LazyIdleThread::SetListener(nsIThreadPoolListener* aListener) {
|
|
return mThreadPool->SetListener(aListener);
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(LazyIdleThread, nsIEventTarget, nsISerialEventTarget,
|
|
nsIObserver)
|
|
|
|
NS_IMETHODIMP
|
|
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) {
|
|
return mTaskQueue->Dispatch(std::move(aEvent), aFlags);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
LazyIdleThread::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
LazyIdleThread::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
LazyIdleThread::UnregisterShutdownTask(nsITargetShutdownTask* aTask) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
LazyIdleThread::IsOnCurrentThread(bool* aIsOnCurrentThread) {
|
|
return mTaskQueue->IsOnCurrentThread(aIsOnCurrentThread);
|
|
}
|
|
|
|
NS_IMETHODIMP_(bool)
|
|
LazyIdleThread::IsOnCurrentThreadInfallible() {
|
|
return mTaskQueue->IsOnCurrentThreadInfallible();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
LazyIdleThread::Observe(nsISupports* /* aSubject */, const char* aTopic,
|
|
const char16_t* /* aData */) {
|
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
|
MOZ_ASSERT(!strcmp("xpcom-shutdown-threads", aTopic), "Bad topic!");
|
|
|
|
Shutdown();
|
|
return NS_OK;
|
|
}
|
|
|
|
} // namespace mozilla
|