Bug 1241906 - Spdy deadlock on suspended channel r=hurley

--HG--
extra : rebase_source : 5c61ce077ba3b6ff5e68b379ac0efda304424e1b
This commit is contained in:
Patrick McManus 2016-01-29 11:47:58 -05:00
Родитель 66e6da78e6
Коммит 677082b660
6 изменённых файлов: 38 добавлений и 9 удалений

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

@ -2102,6 +2102,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
SpdyStream31 *stream = mInputFrameDataStream; SpdyStream31 *stream = mInputFrameDataStream;
mSegmentWriter = writer; mSegmentWriter = writer;
rv = mInputFrameDataStream->WriteSegments(this, count, countWritten); rv = mInputFrameDataStream->WriteSegments(this, count, countWritten);
bool channelPipeFull = false;
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
"stream channel pipe full\n",
this, stream, stream ? stream->StreamID() : 0));
channelPipeFull = mInputFrameDataStream->ChannelPipeFull();
}
mSegmentWriter = nullptr; mSegmentWriter = nullptr;
mLastDataReadEpoch = mLastReadEpoch; mLastDataReadEpoch = mLastReadEpoch;
@ -2137,10 +2144,13 @@ SpdySession31::WriteSegments(nsAHttpSegmentWriter *writer,
} }
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LOG3(("SpdySession31 %p data frame read failure %x\n", this, rv)); LOG3(("SpdySession31::WriteSegments session=%p stream=%p 0x%X "
"data frame read failure %x pipefull=%d\n",
this, stream, stream ? stream->StreamID() : 0, rv, channelPipeFull));
// maybe just blocked reading from network // maybe just blocked reading from network
if (rv == NS_BASE_STREAM_WOULD_BLOCK) if ((rv == NS_BASE_STREAM_WOULD_BLOCK) && !channelPipeFull) {
rv = NS_OK; rv = NS_OK;
}
} }
return rv; return rv;

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

@ -229,6 +229,13 @@ SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
return rv; return rv;
} }
bool
SpdyStream31::ChannelPipeFull()
{
nsHttpTransaction *trans = mTransaction ? mTransaction->QueryHttpTransaction() : nullptr;
return trans ? trans->ChannelPipeFull() : false;
}
void void
SpdyStream31::CreatePushHashKey(const nsCString &scheme, SpdyStream31::CreatePushHashKey(const nsCString &scheme,
const nsCString &hostHeader, const nsCString &hostHeader,

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

@ -88,6 +88,7 @@ public:
int64_t LocalWindow() { return mLocalWindow; } int64_t LocalWindow() { return mLocalWindow; }
bool BlockedOnRwin() { return mBlockedOnRwin; } bool BlockedOnRwin() { return mBlockedOnRwin; }
bool ChannelPipeFull();
// A pull stream has an implicit sink, a pushed stream has a sink // A pull stream has an implicit sink, a pushed stream has a sink
// once it is matched to a pull stream. // once it is matched to a pull stream.

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

@ -1765,23 +1765,27 @@ nsHttpConnection::OnSocketReadable()
break; break;
} }
mSocketInCondition = NS_OK;
rv = mTransaction->WriteSegments(this, nsIOService::gDefaultSegmentSize, &n); rv = mTransaction->WriteSegments(this, nsIOService::gDefaultSegmentSize, &n);
LOG(("nsHttpConnection::OnSocketReadable %p trans->ws rv=%x n=%d socketin=%x\n",
this, rv, n, mSocketInCondition));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
// if the transaction didn't want to take any more data, then // if the transaction didn't want to take any more data, then
// wait for the transaction to call ResumeRecv. // wait for the transaction to call ResumeRecv.
if (rv == NS_BASE_STREAM_WOULD_BLOCK) if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
rv = NS_OK; rv = NS_OK;
}
again = false; again = false;
} } else {
else {
mCurrentBytesRead += n; mCurrentBytesRead += n;
mTotalBytesRead += n; mTotalBytesRead += n;
if (NS_FAILED(mSocketInCondition)) { if (NS_FAILED(mSocketInCondition)) {
// continue waiting for the socket if necessary... // continue waiting for the socket if necessary...
if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) if (mSocketInCondition == NS_BASE_STREAM_WOULD_BLOCK) {
rv = ResumeRecv(); rv = ResumeRecv();
else } else {
rv = mSocketInCondition; rv = mSocketInCondition;
}
again = false; again = false;
} }
} }

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

@ -127,6 +127,7 @@ nsHttpTransaction::nsHttpTransaction()
, mContentDecoding(false) , mContentDecoding(false)
, mContentDecodingCheck(false) , mContentDecodingCheck(false)
, mDeferredSendProgress(false) , mDeferredSendProgress(false)
, mWaitingOnPipeOut(false)
, mReportedStart(false) , mReportedStart(false)
, mReportedResponseHeader(false) , mReportedResponseHeader(false)
, mForTakeResponseHead(nullptr) , mForTakeResponseHead(nullptr)
@ -832,9 +833,10 @@ nsHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
if (rv == NS_BASE_STREAM_WOULD_BLOCK) { if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
nsCOMPtr<nsIEventTarget> target; nsCOMPtr<nsIEventTarget> target;
gHttpHandler->GetSocketThreadTarget(getter_AddRefs(target)); gHttpHandler->GetSocketThreadTarget(getter_AddRefs(target));
if (target) if (target) {
mPipeOut->AsyncWait(this, 0, 0, target); mPipeOut->AsyncWait(this, 0, 0, target);
else { mWaitingOnPipeOut = true;
} else {
NS_ERROR("no socket thread event target"); NS_ERROR("no socket thread event target");
rv = NS_ERROR_UNEXPECTED; rv = NS_ERROR_UNEXPECTED;
} }
@ -2179,6 +2181,7 @@ NS_IMPL_QUERY_INTERFACE(nsHttpTransaction,
NS_IMETHODIMP NS_IMETHODIMP
nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out) nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out)
{ {
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
if (mConnection) { if (mConnection) {
mConnection->TransactionHasDataToWrite(this); mConnection->TransactionHasDataToWrite(this);
nsresult rv = mConnection->ResumeSend(); nsresult rv = mConnection->ResumeSend();
@ -2196,6 +2199,8 @@ nsHttpTransaction::OnInputStreamReady(nsIAsyncInputStream *out)
NS_IMETHODIMP NS_IMETHODIMP
nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out) nsHttpTransaction::OnOutputStreamReady(nsIAsyncOutputStream *out)
{ {
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
mWaitingOnPipeOut = false;
if (mConnection) { if (mConnection) {
mConnection->TransactionHasDataToRecv(this); mConnection->TransactionHasDataToRecv(this);
nsresult rv = mConnection->ResumeRecv(); nsresult rv = mConnection->ResumeRecv();

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

@ -143,6 +143,7 @@ public:
} }
void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; } void SetPushedStream(Http2PushedStream *push) { mPushedStream = push; }
uint32_t InitialRwin() const { return mInitialRwin; }; uint32_t InitialRwin() const { return mInitialRwin; };
bool ChannelPipeFull() { return mWaitingOnPipeOut; }
// Locked methods to get and set timing info // Locked methods to get and set timing info
const TimingStruct Timings(); const TimingStruct Timings();
@ -306,6 +307,7 @@ private:
bool mContentDecoding; bool mContentDecoding;
bool mContentDecodingCheck; bool mContentDecodingCheck;
bool mDeferredSendProgress; bool mDeferredSendProgress;
bool mWaitingOnPipeOut;
// mClosed := transaction has been explicitly closed // mClosed := transaction has been explicitly closed
// mTransactionDone := transaction ran to completion or was interrupted // mTransactionDone := transaction ran to completion or was interrupted