Made NS_BASE_STREAM_WOULD_BLOCK a failure code (for JS). Reduced socket transport buffer size. Fixed ABBA deadlock when calling OnEmpty in pipe code (bug#12870).

This commit is contained in:
warren%netscape.com 1999-08-31 21:47:30 +00:00
parent 5a36ea1109
commit efb0c1cd5d
5 changed files with 41 additions and 44 deletions

View File

@ -446,7 +446,8 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
}
}
// Process the write request...
if (NS_SUCCEEDED(rv) && (GetWriteType() != eSocketWrite_None)) {
if ((NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK)
&& (GetWriteType() != eSocketWrite_None)) {
rv = doWrite(aSelectFlags);
if (NS_OK == rv) {
SetFlag(eSocketWrite_Done);
@ -472,12 +473,12 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
if (NS_OK == rv) {
mCurrentState = gStateTable[mOperation][mCurrentState];
}
else if (NS_FAILED(rv)) {
mCurrentState = eSocketState_Error;
}
else if (NS_BASE_STREAM_WOULD_BLOCK == rv) {
done = PR_TRUE;
}
else if (NS_FAILED(rv)) {
mCurrentState = eSocketState_Error;
}
//
// Any select flags are *only* valid the first time through the loop...
//
@ -1011,7 +1012,7 @@ nsresult nsSocketTransport::doWriteFromBuffer(PRUint32 *aCount)
mSelectFlags &= (~PR_POLL_WRITE);
rv = NS_OK;
}
else if (NS_SUCCEEDED(rv)) {
else if (NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK) {
//
// If the buffer is empty, then notify the reader and stop polling
// for write until there is data in the buffer. See the OnWrite()
@ -1062,7 +1063,7 @@ nsresult nsSocketTransport::doWriteFromStream(PRUint32 *aCount)
#else
rv = mWriteFromStream->Read(gIOBuffer, maxBytesToRead, &bytesRead);
#endif
if (NS_SUCCEEDED(rv) && bytesRead) {
if ((NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK) && bytesRead) {
// Update the counters...
*aCount += bytesRead;
if (mWriteCount > 0) {
@ -1435,8 +1436,8 @@ nsSocketTransport::AsyncRead(PRUint32 startPosition, PRInt32 readCount,
rv = NS_NewPipe(getter_AddRefs(mReadPipeIn),
getter_AddRefs(mReadPipeOut),
this, // nsIPipeObserver
MAX_IO_BUFFER_SIZE/2,
2*MAX_IO_BUFFER_SIZE);
NS_SOCKET_TRANSPORT_SEGMENT_SIZE,
NS_SOCKET_TRANSPORT_BUFFER_SIZE);
if (NS_SUCCEEDED(rv)) {
rv = mReadPipeIn->SetNonBlocking(PR_TRUE);
}
@ -1593,8 +1594,8 @@ nsSocketTransport::OpenInputStream(PRUint32 startPosition, PRInt32 readCount,
rv = NS_NewPipe(getter_AddRefs(mReadPipeIn),
getter_AddRefs(mReadPipeOut),
this, // nsIPipeObserver
MAX_IO_BUFFER_SIZE/2,
2*MAX_IO_BUFFER_SIZE);
NS_SOCKET_TRANSPORT_SEGMENT_SIZE,
NS_SOCKET_TRANSPORT_BUFFER_SIZE);
if (NS_SUCCEEDED(rv)) {
rv = mReadPipeOut->SetNonBlocking(PR_TRUE);
*result = mReadPipeIn;
@ -1656,7 +1657,8 @@ nsSocketTransport::OpenOutputStream(PRUint32 startPosition, nsIOutputStream* *re
#else
rv = NS_NewPipe(getter_AddRefs(in), getter_AddRefs(out),
this, // nsIPipeObserver
MAX_IO_BUFFER_SIZE, MAX_IO_BUFFER_SIZE);
NS_SOCKET_TRANSPORT_SEGMENT_SIZE,
NS_SOCKET_TRANSPORT_BUFFER_SIZE);
if (NS_SUCCEEDED(rv)) {
rv = in->SetNonBlocking(PR_TRUE);
}

View File

@ -34,6 +34,9 @@
#include "nsIPipe.h"
#define NSPIPE2
#define NS_SOCKET_TRANSPORT_SEGMENT_SIZE (4*1024)
#define NS_SOCKET_TRANSPORT_BUFFER_SIZE (64*1024)
//
// This is the size of the global buffer used by all nsSocketTransport
// instances when reading from or writing to the network.

View File

@ -669,13 +669,6 @@ nsFileChannel::Process(void)
if (mReadFixedAmount)
mAmount -= amt; // subtract off the amount we just read from mAmount.
if (NS_FAILED(mStatus)) goto error;
if (mStatus == NS_BASE_STREAM_WOULD_BLOCK || amt == 0) {
// Our nsIPipeObserver will have been called from WriteFrom
// which in turn calls Suspend, so we should end up suspending
// this file channel.
Suspend();
return;
}
// and feed the buffer to the application via the buffer stream:
if (mListener) {

View File

@ -41,8 +41,6 @@ interface nsIBaseStream : nsISupports
/// For unichar streams
#define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6)
#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 7)
#define NS_BASE_STREAM_FULL NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 8)
#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 7)
//@}
%}

View File

@ -323,23 +323,18 @@ nsPipe::nsPipeInputStream::GetLength(PRUint32 *result)
nsAutoCMonitor mon(pipe);
PRUint32 len = pipe->mBuffer.GetSize();
if (pipe->mReadCursor) {
char* end = (pipe->mReadLimit == pipe->mWriteLimit)
? pipe->mWriteCursor
: pipe->mReadLimit;
len -= pipe->mBuffer.GetSegmentSize() - (end - pipe->mReadCursor);
}
// if (pipe->mWriteCursor)
//len -= pipe->mWriteLimit - pipe->mWriteCursor;
if (pipe->mReadCursor)
len -= pipe->mBuffer.GetSegmentSize() - (pipe->mReadLimit - pipe->mReadCursor);
if (pipe->mWriteCursor)
len -= pipe->mWriteLimit - pipe->mWriteCursor;
if (result)
*result = len;
*result = len;
return NS_OK;
}
NS_IMETHODIMP
nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
void* closure,
void* closure,
PRUint32 count,
PRUint32 *readCount)
{
@ -360,11 +355,13 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
if (*readCount > 0 || NS_FAILED(rv))
goto done; // don't Fill if we've got something
if (pipe->mObserver) {
PR_CExitMonitor(pipe);
rv = pipe->mObserver->OnEmpty(pipe);
PR_CEnterMonitor(pipe);
if (NS_FAILED(rv)) goto done;
}
rv = Fill();
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
if (/*rv == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv))
goto done;
// else we filled the pipe, so go around again
continue;
@ -375,18 +372,18 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
PRUint32 writeCount;
rv = writer(closure, readBuffer, *readCount, readBufferLen, &writeCount);
NS_ASSERTION(rv != NS_BASE_STREAM_EOF, "Write should not return EOF");
if (NS_FAILED(rv))
goto done;
if (writeCount == 0 || rv == NS_BASE_STREAM_WOULD_BLOCK) {
rv = pipe->mCondition;
if (*readCount > 0 || NS_FAILED(rv))
goto done; // don't Fill if we've got something
rv = Fill();
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
if (/*rv == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv))
goto done;
// else we filled the pipe, so go around again
continue;
}
if (NS_FAILED(rv))
goto done;
NS_ASSERTION(writeCount <= readBufferLen, "writer returned bad writeCount");
readBuffer += writeCount;
readBufferLen -= writeCount;
@ -399,7 +396,9 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
pipe->mReadLimit = nsnull;
PRBool empty = pipe->mBuffer.DeleteFirstSegment();
if (empty && pipe->mObserver) {
PR_CExitMonitor(pipe);
rv = pipe->mObserver->OnEmpty(pipe);
PR_CEnterMonitor(pipe);
if (NS_FAILED(rv))
goto done;
}
@ -610,11 +609,13 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
goto done;
if (writeBufLen == 0) {
if (pipe->mObserver && *writeCount == 0) {
PR_CExitMonitor(pipe);
rv = pipe->mObserver->OnFull(pipe);
PR_CEnterMonitor(pipe);
if (NS_FAILED(rv)) goto done;
}
rv = Flush();
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
if (/*rv == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv))
goto done;
// else we flushed, so go around again
continue;
@ -624,21 +625,21 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
while (writeBufLen > 0) {
PRUint32 readCount = 0;
rv = reader(closure, writeBuf, *writeCount, writeBufLen, &readCount);
if (NS_FAILED(rv)) {
// save the failure condition so that we can get it again later
pipe->mCondition = rv;
goto done;
}
if (readCount == 0) {
if (rv == NS_BASE_STREAM_WOULD_BLOCK || readCount == 0) {
// The reader didn't have anything else to put in the buffer, so
// call flush to notify the guy downstream, hoping that he'll somehow
// wake up the guy upstream to eventually produce more data for us.
nsresult rv2 = Flush();
if (rv2 == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv2))
if (/*rv2 == NS_BASE_STREAM_WOULD_BLOCK || */NS_FAILED(rv2))
goto done;
// else we flushed, so go around again
continue;
}
if (NS_FAILED(rv)) {
// save the failure condition so that we can get it again later
pipe->mCondition = rv;
goto done;
}
NS_ASSERTION(readCount <= writeBufLen, "reader returned bad readCount");
writeBuf += readCount;
writeBufLen -= readCount;