bug 1083930 - cpu spin during large h2/spdy upload r=hurley

--HG--
extra : rebase_source : 0204d5128df1f76d0e2c9a9ec24f719cb538a1e6
This commit is contained in:
Patrick McManus 2015-10-19 17:42:18 -04:00
Родитель 18bdfef857
Коммит 70c555d190
2 изменённых файлов: 57 добавлений и 8 удалений

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

@ -83,6 +83,7 @@ nsHttpConnection::nsHttpConnection()
, mTransactionCaps(0)
, mResponseTimeoutEnabled(false)
, mTCPKeepaliveConfig(kTCPKeepaliveDisabled)
, mForceSendPending(false)
{
LOG(("Creating nsHttpConnection @%p\n", this));
@ -113,6 +114,10 @@ nsHttpConnection::~nsHttpConnection()
Telemetry::HTTP_KBREAD_PER_CONN,
totalKBRead);
}
if (mForceSendTimer) {
mForceSendTimer->Cancel();
mForceSendTimer = nullptr;
}
}
nsresult
@ -569,6 +574,10 @@ nsHttpConnection::Close(nsresult reason)
mTCPKeepaliveTransitionTimer->Cancel();
mTCPKeepaliveTransitionTimer = nullptr;
}
if (mForceSendTimer) {
mForceSendTimer->Cancel();
mForceSendTimer = nullptr;
}
if (NS_FAILED(reason)) {
if (mIdleMonitoring)
@ -1340,10 +1349,10 @@ nsHttpConnection::ResumeRecv()
}
class nsHttpConnectionForceIO : public nsRunnable
class HttpConnectionForceIO : public nsRunnable
{
public:
nsHttpConnectionForceIO(nsHttpConnection *aConn, bool doRecv)
HttpConnectionForceIO(nsHttpConnection *aConn, bool doRecv)
: mConn(aConn)
, mDoRecv(doRecv)
{}
@ -1357,8 +1366,12 @@ public:
return NS_OK;
return mConn->OnInputStreamReady(mConn->mSocketIn);
}
if (!mConn->mSocketOut)
MOZ_ASSERT(mConn->mForceSendPending);
mConn->mForceSendPending = false;
if (!mConn->mSocketOut) {
return NS_OK;
}
return mConn->OnOutputStreamReady(mConn->mSocketOut);
}
private:
@ -1366,6 +1379,37 @@ private:
bool mDoRecv;
};
void
nsHttpConnection::ForceSendIO(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsHttpConnection *self = static_cast<nsHttpConnection *>(aClosure);
MOZ_ASSERT(aTimer == self->mForceSendTimer);
self->mForceSendTimer = nullptr;
NS_DispatchToCurrentThread(new HttpConnectionForceIO(self, false));
}
nsresult
nsHttpConnection::MaybeForceSendIO()
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
// due to bug 1213084 sometimes real I/O events do not get serviced when
// NSPR derived I/O events are ready and this can cause a deadlock with
// https over https proxying. Normally we would expect the write callback to
// be invoked before this timer goes off, but set it at the old windows
// tick interval (kForceDelay) as a backup for those circumstances.
static const uint32_t kForceDelay = 17; //ms
if (mForceSendPending) {
return NS_OK;
}
MOZ_ASSERT(!mForceSendTimer);
mForceSendPending = true;
mForceSendTimer = do_CreateInstance("@mozilla.org/timer;1");
return mForceSendTimer->InitWithFuncCallback(
nsHttpConnection::ForceSendIO, this, kForceDelay, nsITimer::TYPE_ONE_SHOT);
}
// trigger an asynchronous read
nsresult
nsHttpConnection::ForceRecv()
@ -1373,7 +1417,7 @@ nsHttpConnection::ForceRecv()
LOG(("nsHttpConnection::ForceRecv [this=%p]\n", this));
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
return NS_DispatchToCurrentThread(new nsHttpConnectionForceIO(this, true));
return NS_DispatchToCurrentThread(new HttpConnectionForceIO(this, true));
}
// trigger an asynchronous write
@ -1386,8 +1430,7 @@ nsHttpConnection::ForceSend()
if (mTLSFilter) {
return mTLSFilter->NudgeTunnel(this);
}
return NS_DispatchToCurrentThread(new nsHttpConnectionForceIO(this, false));
return MaybeForceSendIO();
}
void
@ -2052,7 +2095,6 @@ nsHttpConnection::OnOutputStreamReady(nsIAsyncOutputStream *out)
{
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
MOZ_ASSERT(out == mSocketOut, "unexpected socket");
// if the transaction was dropped...
if (!mTransaction) {
LOG((" no transaction; ignoring event\n"));

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

@ -142,7 +142,7 @@ public:
int64_t MaxBytesRead() {return mMaxBytesRead;}
uint8_t GetLastHttpResponseVersion() { return mLastHttpResponseVersion; }
friend class nsHttpConnectionForceIO;
friend class HttpConnectionForceIO;
nsresult ForceSend();
nsresult ForceRecv();
@ -349,6 +349,13 @@ private:
// Flag to indicate connection is in inital keepalive period (fast detect).
uint32_t mTCPKeepaliveConfig;
nsCOMPtr<nsITimer> mTCPKeepaliveTransitionTimer;
private:
// For ForceSend()
static void ForceSendIO(nsITimer *aTimer, void *aClosure);
nsresult MaybeForceSendIO();
bool mForceSendPending;
nsCOMPtr<nsITimer> mForceSendTimer;
};
} // namespace net