author | Patrick McManus <mcmanus@ducksong.com> |
Fri, 08 Apr 2011 14:36:38 -0400 | |
changeset 67708 | 649e429d342f926227772c2d6cf1003c594524d7 |
parent 67665 | 1d17596bbf5f830272cd8b1d3cacaf742451cf3c |
child 67709 | 198b15a6543283696599bcd6f3640ace0c8b82bc |
push id | 1 |
push user | root |
push date | Tue, 26 Apr 2011 22:38:44 +0000 |
treeherder | mozilla-beta@bfdb6e623a36 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jduell |
bugs | 607741 |
milestone | 2.2a1pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/netwerk/base/src/nsSocketTransportService2.cpp +++ b/netwerk/base/src/nsSocketTransportService2.cpp @@ -59,49 +59,63 @@ using namespace mozilla; #if defined(PR_LOGGING) PRLogModuleInfo *gSocketTransportLog = nsnull; #endif nsSocketTransportService *gSocketTransportService = nsnull; PRThread *gSocketThread = nsnull; #define SEND_BUFFER_PREF "network.tcp.sendbuffer" +#define SOCKET_LIMIT_TARGET 550 //----------------------------------------------------------------------------- // ctor/dtor (called on the main/UI thread by the service manager) nsSocketTransportService::nsSocketTransportService() : mThread(nsnull) , mThreadEvent(nsnull) , mAutodialEnabled(PR_FALSE) , mLock("nsSocketTransportService::mLock") , mInitialized(PR_FALSE) , mShuttingDown(PR_FALSE) + , mActiveListSize(50) + , mIdleListSize(50) , mActiveCount(0) , mIdleCount(0) , mSendBufferSize(0) { #if defined(PR_LOGGING) gSocketTransportLog = PR_NewLogModule("nsSocketTransport"); #endif NS_ASSERTION(NS_IsMainThread(), "wrong thread"); + DetermineMaxCount(); /* init mMaxCount */ + mActiveList = (SocketContext *) + moz_xmalloc(sizeof(SocketContext) * mActiveListSize); + mIdleList = (SocketContext *) + moz_xmalloc(sizeof(SocketContext) * mIdleListSize); + mPollList = (PRPollDesc *) + moz_xmalloc(sizeof(PRPollDesc) * (mActiveListSize + 1)); + NS_ASSERTION(!gSocketTransportService, "must not instantiate twice"); gSocketTransportService = this; } nsSocketTransportService::~nsSocketTransportService() { NS_ASSERTION(NS_IsMainThread(), "wrong thread"); NS_ASSERTION(!mInitialized, "not shutdown properly"); if (mThreadEvent) PR_DestroyPollableEvent(mThreadEvent); + moz_free(mActiveList); + moz_free(mIdleList); + moz_free(mPollList); gSocketTransportService = nsnull; } //----------------------------------------------------------------------------- // event queue (any thread) already_AddRefed<nsIThread> nsSocketTransportService::GetThreadSafely() @@ -172,30 +186,30 @@ nsSocketTransportService::AttachSocket(P nsresult rv = AddToIdleList(&sock); if (NS_SUCCEEDED(rv)) NS_ADDREF(handler); return rv; } nsresult -nsSocketTransportService::DetachSocket(SocketContext *sock) +nsSocketTransportService::DetachSocket(SocketContext *listHead, SocketContext *sock) { SOCKET_LOG(("nsSocketTransportService::DetachSocket [handler=%x]\n", sock->mHandler)); + NS_ABORT_IF_FALSE((listHead == mActiveList) || (listHead == mIdleList), + "DetachSocket invalid head"); // inform the handler that this socket is going away sock->mHandler->OnSocketDetached(sock->mFD); // cleanup sock->mFD = nsnull; NS_RELEASE(sock->mHandler); - // find out what list this is on. - PRUint32 index = sock - mActiveList; - if (index < NS_SOCKET_MAX_COUNT) + if (listHead == mActiveList) RemoveFromPollList(sock); else RemoveFromIdleList(sock); // NOTE: sock is now an invalid pointer // // notify the first element on the pending socket queue... @@ -206,23 +220,28 @@ nsSocketTransportService::DetachSocket(S return Dispatch(event, NS_DISPATCH_NORMAL); } return NS_OK; } nsresult nsSocketTransportService::AddToPollList(SocketContext *sock) { - SOCKET_LOG(("nsSocketTransportService::AddToPollList [handler=%x]\n", sock->mHandler)); + NS_ABORT_IF_FALSE(!(((PRUint32)(sock - mActiveList)) < mActiveListSize), + "AddToPollList Socket Already Active"); - if (mActiveCount == NS_SOCKET_MAX_COUNT) { - NS_ERROR("too many active sockets"); - return NS_ERROR_UNEXPECTED; + SOCKET_LOG(("nsSocketTransportService::AddToPollList [handler=%x]\n", sock->mHandler)); + if (mActiveCount == mActiveListSize) { + SOCKET_LOG((" Active List size of %d met\n", mActiveCount)); + if (!GrowActiveList()) { + NS_ERROR("too many active sockets"); + return NS_ERROR_OUT_OF_MEMORY; + } } - + mActiveList[mActiveCount] = *sock; mActiveCount++; mPollList[mActiveCount].fd = sock->mFD; mPollList[mActiveCount].in_flags = sock->mHandler->mPollFlags; mPollList[mActiveCount].out_flags = 0; SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount)); @@ -230,81 +249,118 @@ nsSocketTransportService::AddToPollList( } void nsSocketTransportService::RemoveFromPollList(SocketContext *sock) { SOCKET_LOG(("nsSocketTransportService::RemoveFromPollList [handler=%x]\n", sock->mHandler)); PRUint32 index = sock - mActiveList; - NS_ASSERTION(index < NS_SOCKET_MAX_COUNT, "invalid index"); + NS_ABORT_IF_FALSE(index < mActiveListSize, "invalid index"); SOCKET_LOG((" index=%u mActiveCount=%u\n", index, mActiveCount)); if (index != mActiveCount-1) { mActiveList[index] = mActiveList[mActiveCount-1]; mPollList[index+1] = mPollList[mActiveCount]; } mActiveCount--; SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount)); } nsresult nsSocketTransportService::AddToIdleList(SocketContext *sock) { - SOCKET_LOG(("nsSocketTransportService::AddToIdleList [handler=%x]\n", sock->mHandler)); + NS_ABORT_IF_FALSE(!(((PRUint32)(sock - mIdleList)) < mIdleListSize), + "AddToIdlelList Socket Already Idle"); - if (mIdleCount == NS_SOCKET_MAX_COUNT) { - NS_ERROR("too many idle sockets"); - return NS_ERROR_UNEXPECTED; + SOCKET_LOG(("nsSocketTransportService::AddToIdleList [handler=%x]\n", sock->mHandler)); + if (mIdleCount == mIdleListSize) { + SOCKET_LOG((" Idle List size of %d met\n", mIdleCount)); + if (!GrowIdleList()) { + NS_ERROR("too many idle sockets"); + return NS_ERROR_OUT_OF_MEMORY; + } } mIdleList[mIdleCount] = *sock; mIdleCount++; SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount)); return NS_OK; } void nsSocketTransportService::RemoveFromIdleList(SocketContext *sock) { SOCKET_LOG(("nsSocketTransportService::RemoveFromIdleList [handler=%x]\n", sock->mHandler)); - PRUint32 index = sock - &mIdleList[0]; - NS_ASSERTION(index < NS_SOCKET_MAX_COUNT, "invalid index"); + PRUint32 index = sock - mIdleList; + NS_ASSERTION(index < mIdleListSize, "invalid index in idle list"); if (index != mIdleCount-1) mIdleList[index] = mIdleList[mIdleCount-1]; mIdleCount--; SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount)); } void nsSocketTransportService::MoveToIdleList(SocketContext *sock) { nsresult rv = AddToIdleList(sock); if (NS_FAILED(rv)) - DetachSocket(sock); + DetachSocket(mActiveList, sock); else RemoveFromPollList(sock); } void nsSocketTransportService::MoveToPollList(SocketContext *sock) { nsresult rv = AddToPollList(sock); if (NS_FAILED(rv)) - DetachSocket(sock); + DetachSocket(mIdleList, sock); else RemoveFromIdleList(sock); } +PRBool +nsSocketTransportService::GrowActiveList() +{ + PRInt32 toAdd = MaxCount() - mActiveListSize; + if (toAdd > 100) + toAdd = 100; + if (toAdd < 1) + return PR_FALSE; + + mActiveListSize += toAdd; + mActiveList = (SocketContext *) + moz_xrealloc(mActiveList, sizeof(SocketContext) * mActiveListSize); + mPollList = (PRPollDesc *) + moz_xrealloc(mPollList, sizeof(PRPollDesc) * (mActiveListSize + 1)); + return PR_TRUE; +} + +PRBool +nsSocketTransportService::GrowIdleList() +{ + PRInt32 toAdd = MaxCount() - mIdleListSize; + if (toAdd > 100) + toAdd = 100; + if (toAdd < 1) + return PR_FALSE; + + mIdleListSize += toAdd; + mIdleList = (SocketContext *) + moz_xrealloc(mIdleList, sizeof(SocketContext) * mIdleListSize); + return PR_TRUE; +} + PRIntervalTime nsSocketTransportService::PollTimeout() { if (mActiveCount == 0) return NS_SOCKET_POLL_TIMEOUT; // compute minimum time before any socket timeout expires. PRUint32 minR = PR_UINT16_MAX; @@ -589,19 +645,19 @@ nsSocketTransportService::Run() NS_ProcessNextEvent(thread); } SOCKET_LOG(("STS shutting down thread\n")); // detach any sockets PRInt32 i; for (i=mActiveCount-1; i>=0; --i) - DetachSocket(&mActiveList[i]); + DetachSocket(mActiveList, &mActiveList[i]); for (i=mIdleCount-1; i>=0; --i) - DetachSocket(&mIdleList[i]); + DetachSocket(mIdleList, &mIdleList[i]); // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. NS_ProcessPendingEvents(thread); gSocketThread = nsnull; SOCKET_LOG(("STS thread exit\n")); @@ -630,17 +686,17 @@ nsSocketTransportService::DoPollIteratio for (i=mActiveCount-1; i>=0; --i) { //--- SOCKET_LOG((" active [%u] { handler=%x condition=%x pollflags=%hu }\n", i, mActiveList[i].mHandler, mActiveList[i].mHandler->mCondition, mActiveList[i].mHandler->mPollFlags)); //--- if (NS_FAILED(mActiveList[i].mHandler->mCondition)) - DetachSocket(&mActiveList[i]); + DetachSocket(mActiveList, &mActiveList[i]); else { PRUint16 in_flags = mActiveList[i].mHandler->mPollFlags; if (in_flags == 0) MoveToIdleList(&mActiveList[i]); else { // update poll flags mPollList[i+1].in_flags = in_flags; mPollList[i+1].out_flags = 0; @@ -650,17 +706,17 @@ nsSocketTransportService::DoPollIteratio for (i=count-1; i>=0; --i) { //--- SOCKET_LOG((" idle [%u] { handler=%x condition=%x pollflags=%hu }\n", i, mIdleList[i].mHandler, mIdleList[i].mHandler->mCondition, mIdleList[i].mHandler->mPollFlags)); //--- if (NS_FAILED(mIdleList[i].mHandler->mCondition)) - DetachSocket(&mIdleList[i]); + DetachSocket(mIdleList, &mIdleList[i]); else if (mIdleList[i].mHandler->mPollFlags != 0) MoveToPollList(&mIdleList[i]); } SOCKET_LOG((" calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount)); // Measures seconds spent while blocked on PR_Poll PRUint32 pollInterval; @@ -697,17 +753,17 @@ nsSocketTransportService::DoPollIteratio } // // check for "dead" sockets and remove them (need to do this in // reverse order obviously). // for (i=mActiveCount-1; i>=0; --i) { if (NS_FAILED(mActiveList[i].mHandler->mCondition)) - DetachSocket(&mActiveList[i]); + DetachSocket(mActiveList, &mActiveList[i]); } if (n != 0 && mPollList[0].out_flags == PR_POLL_READ) { // acknowledge pollable event (wait should not block) if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) { // On Windows, the TCP loopback connection in the // pollable event may become broken when a laptop // switches between wired and wireless networks or @@ -766,8 +822,72 @@ nsSocketTransportService::Observe(nsISup NS_IMETHODIMP nsSocketTransportService::GetSendBufferSize(PRInt32 *value) { *value = mSendBufferSize; return NS_OK; } +/// ugly OS specific includes are placed at the bottom of the src for clarity + +#if defined(XP_WIN) +#include <windows.h> +#elif defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) +#include <sys/resource.h> +#endif + +void +nsSocketTransportService::DetermineMaxCount() +{ + mMaxCount = 50; /* historic default */ + +#if defined(XP_UNIX) && !defined(AIX) && !defined(NEXTSTEP) && !defined(QNX) + // on unix and os x network sockets and file + // descriptors are the same. OS X comes defaulted at 256, + // most linux at 1000. We can reliably use [sg]rlimit to + // query that and raise it. We will try to raise it 250 past + // our target number of SOCKET_LIMIT_TARGET so that some descriptors + // are still available for other things. + + struct rlimit rlimitData; + if (getrlimit(RLIMIT_NOFILE, &rlimitData) == -1) + return; + if (rlimitData.rlim_cur >= SOCKET_LIMIT_TARGET + 250) { + mMaxCount = SOCKET_LIMIT_TARGET; + return; + } + + PRInt32 maxallowed = rlimitData.rlim_max; + if (maxallowed == -1) /* no limit */ + maxallowed = SOCKET_LIMIT_TARGET + 250; + else if (maxallowed < 50 + 250) + return; + else if (maxallowed > SOCKET_LIMIT_TARGET + 250) + maxallowed = SOCKET_LIMIT_TARGET + 250; + + rlimitData.rlim_cur = maxallowed; + setrlimit(RLIMIT_NOFILE, &rlimitData); + if (getrlimit(RLIMIT_NOFILE, &rlimitData) == -1) + return; + if (rlimitData.rlim_cur > 50 + 250) + mMaxCount = rlimitData.rlim_cur - 250; + return; + +#elif defined(XP_WIN) && !defined(WIN_CE) + // win 95, 98, etc had a limit of 100 - so we will just + // use the historical 50 in every case older than XP (0x501). + // >= XP is confirmed to have at least 1000 + + OSVERSIONINFO osInfo = { sizeof(OSVERSIONINFO) }; + if (GetVersionEx(&osInfo)) { + PRInt32 version = + (osInfo.dwMajorVersion & 0xff) << 8 | + (osInfo.dwMinorVersion & 0xff); + if (version >= 0x501) { /* xp or later */ + mMaxCount = SOCKET_LIMIT_TARGET; + } + } + return; +#else + // other platforms are harder to test - so leave at safe legacy value +#endif +}
--- a/netwerk/base/src/nsSocketTransportService2.h +++ b/netwerk/base/src/nsSocketTransportService2.h @@ -60,17 +60,16 @@ // extern PRLogModuleInfo *gSocketTransportLog; #endif #define SOCKET_LOG(args) PR_LOG(gSocketTransportLog, PR_LOG_DEBUG, args) #define SOCKET_LOG_ENABLED() PR_LOG_TEST(gSocketTransportLog, PR_LOG_DEBUG) //----------------------------------------------------------------------------- -#define NS_SOCKET_MAX_COUNT 50 #define NS_SOCKET_POLL_TIMEOUT PR_INTERVAL_NO_TIMEOUT //----------------------------------------------------------------------------- class nsSocketTransportService : public nsPISocketTransportService , public nsIEventTarget , public nsIThreadObserver , public nsIRunnable @@ -92,19 +91,21 @@ public: // // the number of sockets that can be attached at any given time is // limited. this is done because some operating systems (e.g., Win9x) // limit the number of sockets that can be created by an application. // AttachSocket will fail if the limit is exceeded. consumers should // call CanAttachSocket and check the result before creating a socket. // PRBool CanAttachSocket() { - return mActiveCount + mIdleCount < NS_SOCKET_MAX_COUNT; + return mActiveCount + mIdleCount < mMaxCount; } + PRUint32 MaxCount() { return mMaxCount; } + protected: virtual ~nsSocketTransportService(); private: //------------------------------------------------------------------------- // misc (any thread) @@ -148,38 +149,45 @@ private: struct SocketContext { PRFileDesc *mFD; nsASocketHandler *mHandler; PRUint16 mElapsedTime; // time elapsed w/o activity }; - SocketContext mActiveList [ NS_SOCKET_MAX_COUNT ]; - SocketContext mIdleList [ NS_SOCKET_MAX_COUNT ]; + SocketContext *mActiveList; /* mListSize entries */ + SocketContext *mIdleList; /* mListSize entries */ + PRUint32 mActiveListSize; + PRUint32 mIdleListSize; PRUint32 mActiveCount; PRUint32 mIdleCount; + PRUint32 mMaxCount; - nsresult DetachSocket(SocketContext *); + nsresult DetachSocket(SocketContext *, SocketContext *); nsresult AddToIdleList(SocketContext *); nsresult AddToPollList(SocketContext *); void RemoveFromIdleList(SocketContext *); void RemoveFromPollList(SocketContext *); void MoveToIdleList(SocketContext *sock); void MoveToPollList(SocketContext *sock); - + + PRBool GrowActiveList(); + PRBool GrowIdleList(); + void DetermineMaxCount(); + //------------------------------------------------------------------------- // poll list (socket thread only) // // first element of the poll list is mThreadEvent (or null if the pollable // event cannot be created). //------------------------------------------------------------------------- - PRPollDesc mPollList[ NS_SOCKET_MAX_COUNT + 1 ]; + PRPollDesc *mPollList; /* mListSize + 1 entries */ PRIntervalTime PollTimeout(); // computes ideal poll timeout nsresult DoPollIteration(PRBool wait); // perfoms a single poll iteration PRInt32 Poll(PRBool wait, PRUint32 *interval); // calls PR_Poll. the out param // interval indicates the poll // duration in seconds.
--- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -839,17 +839,18 @@ nsHttpHandler::PrefsChanged(nsIPrefBranc mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY, mMaxRequestDelay); } } if (PREF_CHANGED(HTTP_PREF("max-connections"))) { rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val); if (NS_SUCCEEDED(rv)) { - mMaxConnections = (PRUint16) NS_CLAMP(val, 1, NS_SOCKET_MAX_COUNT); + mMaxConnections = (PRUint16) NS_CLAMP( + val, 1, gSocketTransportService->MaxCount()); if (mConnMgr) mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS, mMaxConnections); } } if (PREF_CHANGED(HTTP_PREF("max-connections-per-server"))) { rv = prefs->GetIntPref(HTTP_PREF("max-connections-per-server"), &val);