--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -15,17 +15,19 @@
#include <stdlib.h>
#include <ctime>
#include "nsHostResolver.h"
#include "nsError.h"
#include "nsISupportsBase.h"
#include "nsISupportsUtils.h"
#include "nsIThreadManager.h"
#include "nsAutoPtr.h"
+#include "nsComponentManagerUtils.h"
#include "nsPrintfCString.h"
+#include "nsXPCOMCIDInternal.h"
#include "prthread.h"
#include "prerror.h"
#include "prtime.h"
#include "mozilla/Logging.h"
#include "PLDHashTable.h"
#include "plstr.h"
#include "nsURLHelper.h"
#include "nsThreadUtils.h"
@@ -521,21 +523,21 @@ NS_IMPL_ISUPPORTS0(nsHostResolver)
nsHostResolver::nsHostResolver(uint32_t maxCacheEntries,
uint32_t defaultCacheEntryLifetime,
uint32_t defaultGracePeriod)
: mMaxCacheEntries(maxCacheEntries)
, mDefaultCacheLifetime(defaultCacheEntryLifetime)
, mDefaultGracePeriod(defaultGracePeriod)
, mLock("nsHostResolver.mLock")
- , mIdleThreadCV(mLock, "nsHostResolver.mIdleThreadCV")
+ , mIdleTaskCV(mLock, "nsHostResolver.mIdleTaskCV")
, mEvictionQSize(0)
, mShutdown(true)
- , mNumIdleThreads(0)
- , mThreadCount(0)
+ , mNumIdleTasks(0)
+ , mActiveTaskCount(0)
, mActiveAnyThreadCount(0)
, mPendingCount(0)
{
mCreationTime = PR_Now();
mLongIdleTimeout = TimeDuration::FromSeconds(LongIdleTimeoutSeconds);
mShortIdleTimeout = TimeDuration::FromSeconds(ShortIdleTimeoutSeconds);
}
@@ -577,16 +579,23 @@ nsHostResolver::Init()
// during application startup.
static int initCount = 0;
if (initCount++ > 0) {
LOG(("Calling 'res_ninit'.\n"));
res_ninit(&_res);
}
#endif
+ nsCOMPtr<nsIThreadPool> threadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
+ MOZ_ALWAYS_SUCCEEDS(threadPool->SetThreadLimit(MAX_RESOLVER_THREADS));
+ MOZ_ALWAYS_SUCCEEDS(threadPool->SetIdleThreadLimit(MAX_RESOLVER_THREADS));
+ MOZ_ALWAYS_SUCCEEDS(threadPool->SetThreadStackSize(nsIThreadManager::kThreadPoolStackSize));
+ MOZ_ALWAYS_SUCCEEDS(threadPool->SetName(NS_LITERAL_CSTRING("DNS Resolver")));
+ mResolverThreads = threadPool.forget();
+
return NS_OK;
}
void
nsHostResolver::ClearPendingQueue(LinkedList<RefPtr<nsHostRecord>>& aPendingQ)
{
// loop through pending queue, erroring out pending lookups.
if (!aPendingQ.isEmpty()) {
@@ -659,18 +668,18 @@ nsHostResolver::Shutdown()
pendingQHigh = std::move(mHighQ);
pendingQMed = std::move(mMediumQ);
pendingQLow = std::move(mLowQ);
evictionQ = std::move(mEvictionQ);
mEvictionQSize = 0;
mPendingCount = 0;
- if (mNumIdleThreads)
- mIdleThreadCV.NotifyAll();
+ if (mNumIdleTasks)
+ mIdleTaskCV.NotifyAll();
// empty host database
mRecordDB.Clear();
}
ClearPendingQueue(pendingQHigh);
ClearPendingQueue(pendingQMed);
ClearPendingQueue(pendingQLow);
@@ -690,30 +699,32 @@ nsHostResolver::Shutdown()
iter.UserData()->Cancel();
}
#ifdef NS_BUILD_REFCNT_LOGGING
// Logically join the outstanding worker threads with a timeout.
// Use this approach instead of PR_JoinThread() because that does
// not allow a timeout which may be necessary for a semi-responsive
// shutdown if the thread is blocked on a very slow DNS resolution.
- // mThreadCount is read outside of mLock, but the worst case
+ // mActiveTaskCount is read outside of mLock, but the worst case
// scenario for that race is one extra 25ms sleep.
PRIntervalTime delay = PR_MillisecondsToInterval(25);
PRIntervalTime stopTime = PR_IntervalNow() + PR_SecondsToInterval(20);
- while (mThreadCount && PR_IntervalNow() < stopTime)
+ while (mActiveTaskCount && PR_IntervalNow() < stopTime)
PR_Sleep(delay);
#endif
{
mozilla::DebugOnly<nsresult> rv = GetAddrInfoShutdown();
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"Failed to shutdown GetAddrInfo");
}
+
+ mResolverThreads->Shutdown();
}
nsresult
nsHostResolver::GetHostRecord(const nsACString &host,
uint16_t flags, uint16_t af, bool pb,
const nsCString &originSuffix,
nsHostRecord **result)
{
@@ -974,17 +985,17 @@ nsHostResolver::ResolveHost(const nsACSt
ConditionallyCreateThread(rec);
} else if (IsMediumPriority(flags) &&
IsLowPriority(rec->flags)) {
// Move from low to med.
NS_ASSERTION(rec->onQueue, "Moving Host Record Not Currently Queued");
rec->remove();
mMediumQ.insertBack(rec);
rec->flags = flags;
- mIdleThreadCV.Notify();
+ mIdleTaskCV.Notify();
}
}
}
}
}
if (result) {
if (callback->isInList()) {
@@ -1036,41 +1047,30 @@ nsHostResolver::DetachCallback(const nsA
if (rec) {
callback->OnResolveHostComplete(this, rec, status);
}
}
nsresult
nsHostResolver::ConditionallyCreateThread(nsHostRecord *rec)
{
- if (mNumIdleThreads) {
- // wake up idle thread to process this lookup
- mIdleThreadCV.Notify();
+ if (mNumIdleTasks) {
+ // wake up idle tasks to process this lookup
+ mIdleTaskCV.Notify();
}
- else if ((mThreadCount < HighThreadThreshold) ||
- (IsHighPriority(rec->flags) && mThreadCount < MAX_RESOLVER_THREADS)) {
- static nsThreadPoolNaming naming;
- nsCString name = naming.GetNextThreadName("DNS Resolver");
-
- // dispatch new worker thread
- nsCOMPtr<nsIThread> thread;
- nsresult rv = NS_NewNamedThread(name, getter_AddRefs(thread), nullptr,
- nsIThreadManager::kThreadPoolStackSize);
- if (NS_WARN_IF(NS_FAILED(rv)) || !thread) {
- return rv;
- }
-
+ else if ((mActiveTaskCount < HighThreadThreshold) ||
+ (IsHighPriority(rec->flags) && mActiveTaskCount < MAX_RESOLVER_THREADS)) {
nsCOMPtr<nsIRunnable> event =
mozilla::NewRunnableMethod("nsHostResolver::ThreadFunc",
this,
&nsHostResolver::ThreadFunc);
- mThreadCount++;
- rv = thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
+ mActiveTaskCount++;
+ nsresult rv = mResolverThreads->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
- mThreadCount--;
+ mActiveTaskCount--;
}
}
else {
LOG((" Unable to find a thread for looking up host [%s].\n", rec->host.get()));
}
return NS_OK;
}
@@ -1211,19 +1211,19 @@ nsHostResolver::NativeLookup(nsHostRecor
rec->mNative = true;
rec->mNativeUsed = true;
rec->onQueue = true;
rec->mResolving++;
nsresult rv = ConditionallyCreateThread(rec);
LOG ((" DNS thread counters: total=%d any-live=%d idle=%d pending=%d\n",
- static_cast<uint32_t>(mThreadCount),
+ static_cast<uint32_t>(mActiveTaskCount),
static_cast<uint32_t>(mActiveAnyThreadCount),
- static_cast<uint32_t>(mNumIdleThreads),
+ static_cast<uint32_t>(mNumIdleTasks),
static_cast<uint32_t>(mPendingCount)));
return rv;
}
ResolverMode
nsHostResolver::Mode()
{
@@ -1307,17 +1307,17 @@ bool
nsHostResolver::GetHostToLookup(nsHostRecord **result)
{
bool timedOut = false;
TimeDuration timeout;
TimeStamp epoch, now;
MutexAutoLock lock(mLock);
- timeout = (mNumIdleThreads >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
+ timeout = (mNumIdleTasks >= HighThreadThreshold) ? mShortIdleTimeout : mLongIdleTimeout;
epoch = TimeStamp::Now();
while (!mShutdown) {
// remove next record from Q; hand over owning reference. Check high, then med, then low
#define SET_GET_TTL(var, val) (var)->mGetTtl = sGetTtlEnabled && (val)
if (!mHighQ.isEmpty()) {
@@ -1349,19 +1349,19 @@ nsHostResolver::GetHostToLookup(nsHostRe
if (timedOut)
break;
// wait for one or more of the following to occur:
// (1) the pending queue has a host record to process
// (2) the shutdown flag has been set
// (3) the thread has been idle for too long
- mNumIdleThreads++;
- mIdleThreadCV.Wait(timeout);
- mNumIdleThreads--;
+ mNumIdleTasks++;
+ mIdleTaskCV.Wait(timeout);
+ mNumIdleTasks--;
now = TimeStamp::Now();
if (now - epoch >= timeout) {
timedOut = true;
} else {
// It is possible that CondVar::Wait() was interrupted and returned
// early, in which case we will loop back and re-enter it. In that
@@ -1861,22 +1861,18 @@ nsHostResolver::ThreadFunc()
if (LOOKUP_RESOLVEAGAIN == CompleteLookup(rec, status, ai, rec->pb)) {
// leave 'rec' assigned and loop to make a renewed host resolve
LOG(("DNS lookup thread - Re-resolving host [%s].\n", rec->host.get()));
} else {
rec = nullptr;
}
} while(true);
- nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
- NS_DispatchToMainThread(NS_NewRunnableFunction("nsHostResolver::ThreadFunc::AsyncShutdown", [thread]() {
- thread->AsyncShutdown();
- }));
- mThreadCount--;
- LOG(("DNS lookup thread - queue empty, thread finished.\n"));
+ mActiveTaskCount--;
+ LOG(("DNS lookup thread - queue empty, task finished.\n"));
}
void
nsHostResolver::SetCacheLimits(uint32_t aMaxCacheEntries,
uint32_t aDefaultCacheEntryLifetime,
uint32_t aDefaultGracePeriod)
{
MutexAutoLock lock(mLock);
--- a/netwerk/dns/nsHostResolver.h
+++ b/netwerk/dns/nsHostResolver.h
@@ -18,16 +18,17 @@
#include "GetAddrInfo.h"
#include "mozilla/net/DNS.h"
#include "mozilla/net/DashboardTypes.h"
#include "mozilla/Atomics.h"
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "nsRefPtrHashtable.h"
+#include "nsIThreadPool.h"
class nsHostResolver;
class nsResolveHostCallback;
namespace mozilla { namespace net {
class TRR;
enum ResolverMode {
MODE_NATIVEONLY, // 0 - TRR OFF (by default)
MODE_PARALLEL, // 1 - race and use the first response
@@ -439,30 +440,32 @@ private:
METHOD_NETWORK_FIRST = 6,
METHOD_NETWORK_SHARED = 7
};
uint32_t mMaxCacheEntries;
uint32_t mDefaultCacheLifetime; // granularity seconds
uint32_t mDefaultGracePeriod; // granularity seconds
mutable Mutex mLock; // mutable so SizeOfIncludingThis can be const
- CondVar mIdleThreadCV;
+ CondVar mIdleTaskCV;
nsRefPtrHashtable<nsGenericHashKey<nsHostKey>, nsHostRecord> mRecordDB;
mozilla::LinkedList<RefPtr<nsHostRecord>> mHighQ;
mozilla::LinkedList<RefPtr<nsHostRecord>> mMediumQ;
mozilla::LinkedList<RefPtr<nsHostRecord>> mLowQ;
mozilla::LinkedList<RefPtr<nsHostRecord>> mEvictionQ;
uint32_t mEvictionQSize;
PRTime mCreationTime;
mozilla::TimeDuration mLongIdleTimeout;
mozilla::TimeDuration mShortIdleTimeout;
+ RefPtr<nsIThreadPool> mResolverThreads;
+
mozilla::Atomic<bool> mShutdown;
- mozilla::Atomic<uint32_t> mNumIdleThreads;
- mozilla::Atomic<uint32_t> mThreadCount;
+ mozilla::Atomic<uint32_t> mNumIdleTasks;
+ mozilla::Atomic<uint32_t> mActiveTaskCount;
mozilla::Atomic<uint32_t> mActiveAnyThreadCount;
mozilla::Atomic<uint32_t> mPendingCount;
// Set the expiration time stamps appropriately.
void PrepareRecordExpiration(nsHostRecord* rec) const;
public:
/*