bug 692260 - pr_poll limit autodiscovery for windows r=jduell

--HG--
extra : rebase_source : dc9b024b4004e0a4025e843e94e046b4dd69dca9
This commit is contained in:
Patrick McManus 2011-10-25 11:36:49 -04:00
Родитель 6bd2493132
Коммит 7bd44a1858
5 изменённых файлов: 115 добавлений и 5 удалений

Просмотреть файл

@ -85,6 +85,7 @@ nsSocketTransportService::nsSocketTransportService()
, mActiveCount(0)
, mIdleCount(0)
, mSendBufferSize(0)
, mProbedMaxCount(false)
{
#if defined(PR_LOGGING)
gSocketTransportLog = PR_NewLogModule("nsSocketTransport");
@ -719,6 +720,14 @@ nsSocketTransportService::DoPollIteration(bool wait)
SOCKET_LOG((" calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount));
#if defined(XP_WIN)
// 30 active connections is the historic limit before firefox 7's 256. A few
// windows systems have troubles with the higher limit, so actively probe a
// limit the first time we exceed 30.
if ((mActiveCount > 30) && !mProbedMaxCount)
ProbeMaxCount();
#endif
// Measures seconds spent while blocked on PR_Poll
PRUint32 pollInterval;
@ -835,6 +844,73 @@ nsSocketTransportService::GetSendBufferSize(PRInt32 *value)
#include <sys/resource.h>
#endif
// Right now the only need to do this is on windows.
#if defined(XP_WIN)
void
nsSocketTransportService::ProbeMaxCount()
{
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (mProbedMaxCount)
return;
mProbedMaxCount = true;
PRInt32 startedMaxCount = gMaxCount;
// Allocate and test a PR_Poll up to the gMaxCount number of unconnected
// sockets. See bug 692260 - windows should be able to handle 1000 sockets
// in select() without a problem, but LSPs have been known to balk at lower
// numbers. (64 in the bug).
// Allocate
struct PRPollDesc pfd[SOCKET_LIMIT_TARGET];
PRUint32 numAllocated = 0;
for (PRUint32 index = 0 ; index < gMaxCount; ++index) {
pfd[index].in_flags = PR_POLL_READ | PR_POLL_WRITE | PR_POLL_EXCEPT;
pfd[index].out_flags = 0;
pfd[index].fd = PR_OpenTCPSocket(PR_AF_INET);
if (!pfd[index].fd) {
SOCKET_LOG(("Socket Limit Test index %d failed\n", index));
if (index < SOCKET_LIMIT_MIN)
gMaxCount = SOCKET_LIMIT_MIN;
else
gMaxCount = index;
break;
}
++numAllocated;
}
// Test
PR_STATIC_ASSERT(SOCKET_LIMIT_MIN >= 32U);
while (gMaxCount <= numAllocated) {
PRInt32 rv = PR_Poll(pfd, gMaxCount, PR_MillisecondsToInterval(0));
SOCKET_LOG(("Socket Limit Test poll() size=%d rv=%d\n",
gMaxCount, rv));
if (rv >= 0)
break;
SOCKET_LOG(("Socket Limit Test poll confirmationSize=%d rv=%d error=%d\n",
gMaxCount, rv, PR_GetError()));
gMaxCount -= 32;
if (gMaxCount <= SOCKET_LIMIT_MIN) {
gMaxCount = SOCKET_LIMIT_MIN;
break;
}
}
// Free
for (PRUint32 index = 0 ; index < numAllocated; ++index)
if (pfd[index].fd)
PR_Close(pfd[index].fd);
SOCKET_LOG(("Socket Limit Test max was confirmed at %d\n", gMaxCount));
}
#endif // windows
PRStatus
nsSocketTransportService::DiscoverMaxCount()
{

Просмотреть файл

@ -205,6 +205,12 @@ private:
// Preference Monitor for SendBufferSize
nsresult UpdatePrefs();
PRInt32 mSendBufferSize;
// Socket thread only for dynamically adjusting max socket size
#if defined(XP_WIN)
void ProbeMaxCount();
#endif
bool mProbedMaxCount;
};
extern nsSocketTransportService *gSocketTransportService;

Просмотреть файл

@ -646,6 +646,16 @@ nsHttpConnectionMgr::AtActiveConnectionLimit(nsConnectionEntry *ent, PRUint8 cap
LOG(("nsHttpConnectionMgr::AtActiveConnectionLimit [ci=%s caps=%x]\n",
ci->HashKey().get(), caps));
// update maxconns if potentially limited by the max socket count
// this requires a dynamic reduction in the max socket count to a point
// lower than the max-connections pref.
PRUint32 maxSocketCount = gHttpHandler->MaxSocketCount();
if (mMaxConns > maxSocketCount) {
mMaxConns = maxSocketCount;
LOG(("nsHttpConnectionMgr %p mMaxConns dynamically reduced to %u",
this, mMaxConns));
}
// If there are more active connections than the global limit, then we're
// done. Purging idle connections won't get us below it.
if (mNumActiveConns >= mMaxConns) {

Просмотреть файл

@ -773,6 +773,24 @@ nsHttpHandler::InitUserAgentComponents()
mUserAgentIsDirty = true;
}
PRUint32
nsHttpHandler::MaxSocketCount()
{
PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
nsSocketTransportService::DiscoverMaxCount);
// Don't use the full max count because sockets can be held in
// the persistent connection pool for a long time and that could
// starve other users.
PRUint32 maxCount = nsSocketTransportService::gMaxCount;
if (maxCount <= 8)
maxCount = 1;
else
maxCount -= 8;
return maxCount;
}
void
nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
{
@ -837,11 +855,10 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
if (NS_SUCCEEDED(rv)) {
PR_CallOnce(&nsSocketTransportService::gMaxCountInitOnce,
nsSocketTransportService::DiscoverMaxCount);
mMaxConnections =
(PRUint16) NS_CLAMP((PRUint32)val, 1,
nsSocketTransportService::gMaxCount);
mMaxConnections = (PRUint16) NS_CLAMP((PRUint32)val,
1, MaxSocketCount());
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
mMaxConnections);

Просмотреть файл

@ -108,6 +108,7 @@ public:
PRUint8 GetQoSBits() { return mQoSBits; }
PRUint16 GetIdleSynTimeout() { return mIdleSynTimeout; }
bool FastFallbackToIPv4() { return mFastFallbackToIPv4; }
PRUint32 MaxSocketCount();
bool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }